From a5009a54f93ed1ffba374d001177d6ee0b124a66 Mon Sep 17 00:00:00 2001 From: Yury Smolski <140245+ysmolski@users.noreply.github.com> Date: Thu, 16 Oct 2025 19:32:28 +0300 Subject: [PATCH 1/5] chore: deprecate and retract v1 I plan to merge it and then tag it with v1.68.0 --- go.mod | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/go.mod b/go.mod index 66330ad5c..fe217d475 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,15 @@ +// Deprecated: use github.com/wundergraph/graphql-go-tools/v2 instead. module github.com/wundergraph/graphql-go-tools go 1.25 +retract ( + v0.0.1 + v0.13.2 + v1.0.0 + [v1.0.0, v1.67.4] +) + require ( github.com/99designs/gqlgen v0.17.45 github.com/buger/jsonparser v1.1.1 From d76e5e1e8c940c172f4cf9bea1c7817ea0fd5022 Mon Sep 17 00:00:00 2001 From: Yury Smolski <140245+ysmolski@users.noreply.github.com> Date: Thu, 16 Oct 2025 19:40:39 +0300 Subject: [PATCH 2/5] clarify the retraction rationale --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index fe217d475..87af27c36 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module github.com/wundergraph/graphql-go-tools go 1.25 +// Use github.com/wundergraph/graphql-go-tools/v2 instead. retract ( v0.0.1 v0.13.2 - v1.0.0 [v1.0.0, v1.67.4] ) From 878f2788b39e260a7b698dbc371141afe7e7ba7e Mon Sep 17 00:00:00 2001 From: Yury Smolski <140245+ysmolski@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:53:08 +0300 Subject: [PATCH 3/5] remove v1 and edit readme --- Makefile | 46 - README.md | 14 +- go.mod | 5 +- go.work | 7 - go.work.sum | 16 + pkg/ast/ast.go | 260 - pkg/ast/ast_argument.go | 196 - pkg/ast/ast_description.go | 93 - pkg/ast/ast_directive.go | 214 - pkg/ast/ast_directive_definition.go | 157 - pkg/ast/ast_enum_type_definition.go | 92 - pkg/ast/ast_enum_type_extension.go | 62 - pkg/ast/ast_enum_value_definition.go | 104 - pkg/ast/ast_field.go | 130 - pkg/ast/ast_field_alias.go | 48 - pkg/ast/ast_field_definition.go | 152 - pkg/ast/ast_fragment_definition.go | 73 - pkg/ast/ast_fragment_spread.go | 80 - pkg/ast/ast_inline_fragment.go | 72 - pkg/ast/ast_input_object_type_definition.go | 122 - pkg/ast/ast_input_object_type_extension.go | 62 - pkg/ast/ast_input_value_definition.go | 95 - pkg/ast/ast_interface_type_definition.go | 152 - pkg/ast/ast_interface_type_extension.go | 75 - pkg/ast/ast_node.go | 542 - pkg/ast/ast_node_kind.go | 90 - pkg/ast/ast_node_kind_test.go | 28 - pkg/ast/ast_object_field.go | 75 - pkg/ast/ast_object_type_definition.go | 119 - pkg/ast/ast_object_type_definition_test.go | 63 - pkg/ast/ast_object_type_extension.go | 75 - pkg/ast/ast_operation_definition.go | 143 - pkg/ast/ast_operation_definition_test.go | 49 - pkg/ast/ast_root_operation_type_definition.go | 148 - ...ast_root_operation_type_definition_test.go | 62 - pkg/ast/ast_scalar_type_definition.go | 65 - pkg/ast/ast_scalar_type_extension.go | 52 - pkg/ast/ast_schema_definition.go | 60 - pkg/ast/ast_schema_extension.go | 8 - pkg/ast/ast_selection.go | 181 - pkg/ast/ast_string.go | 160 - pkg/ast/ast_test.go | 473 - pkg/ast/ast_type.go | 249 - pkg/ast/ast_type_test.go | 1 - pkg/ast/ast_union_type_definition.go | 111 - pkg/ast/ast_union_type_extension.go | 62 - pkg/ast/ast_val_boolean_value.go | 13 - pkg/ast/ast_val_enum_value.go | 45 - pkg/ast/ast_val_float_value.go | 58 - pkg/ast/ast_val_int_value.go | 76 - pkg/ast/ast_val_list_value.go | 45 - pkg/ast/ast_val_object_value.go | 33 - pkg/ast/ast_val_string_value.go | 149 - pkg/ast/ast_val_variable_value.go | 63 - pkg/ast/ast_value.go | 333 - pkg/ast/ast_value_test.go | 245 - pkg/ast/ast_variable_definition.go | 77 - pkg/ast/directive_location.go | 162 - pkg/ast/directive_location_string.go | 42 - pkg/ast/directive_location_test.go | 61 - pkg/ast/helpers.go | 58 - pkg/ast/index.go | 174 - pkg/ast/index_test.go | 225 - pkg/ast/input.go | 155 - pkg/ast/path.go | 113 - pkg/astimport/astimport.go | 229 - pkg/astimport/astimport_test.go | 320 - pkg/astnormalization/astnormalization.go | 240 - pkg/astnormalization/astnormalization_test.go | 778 - .../definition_normalization.go | 67 - .../definition_normalization_test.go | 262 - .../directive_include_skip.go | 87 - .../directive_include_skip_test.go | 35 - pkg/astnormalization/enum_type_extending.go | 54 - .../enum_type_extending_test.go | 44 - pkg/astnormalization/extends_directive.go | 82 - .../extends_directive_test.go | 53 - pkg/astnormalization/field_deduplication.go | 59 - .../field_deduplication_test.go | 38 - .../field_selection_merging.go | 93 - .../field_selection_merging_test.go | 82 - .../fragment_definition_removal.go | 25 - .../fragment_spread_inlining.go | 115 - .../fragment_spread_inlining_test.go | 443 - pkg/astnormalization/fragmentspread_depth.go | 105 - .../fragmentspread_depth_test.go | 109 - .../implicit_extend_root_operation.go | 54 - .../implicit_extend_root_operation_test.go | 67 - .../implicit_schema_definition.go | 58 - .../implicit_schema_definition_test.go | 66 - .../inject_input_default_values.go | 235 - .../inject_input_default_values_test.go | 266 - .../inline_fragment_merging.go | 63 - .../inline_fragment_merging_test.go | 56 - .../input_coercion_for_list.go | 299 - .../input_coercion_for_list_test.go | 792 - .../input_object_type_extending.go | 54 - .../input_object_type_extending_test.go | 44 - .../interface_type_extending.go | 54 - .../interface_type_extending_test.go | 176 - pkg/astnormalization/object_type_extending.go | 55 - .../object_type_extending_test.go | 159 - pkg/astnormalization/remove_self_aliasing.go | 32 - .../remove_self_aliasing_test.go | 12 - .../remove_type_extensions.go | 21 - .../remove_type_extensions_test.go | 214 - pkg/astnormalization/scalar_type_extending.go | 55 - .../scalar_type_extending_test.go | 35 - .../subgraph_sdl_normalization.go | 33 - .../subgraph_sdl_normalization_test.go | 39 - pkg/astnormalization/union_type_extending.go | 54 - .../union_type_extending_test.go | 62 - .../variables_default_value_extraction.go | 218 - ...variables_default_value_extraction_test.go | 269 - pkg/astnormalization/variables_extraction.go | 198 - .../variables_extraction_test.go | 1337 - .../variables_unused_deletion.go | 93 - .../variables_unused_deletion_test.go | 31 - pkg/astparser/errors.go | 53 - pkg/astparser/parser.go | 1781 - pkg/astparser/parser_test.go | 2687 - pkg/astparser/parser_token_helpers.go | 90 - pkg/astparser/testdata/big_schema.graphql | 16688 ------ pkg/astparser/testdata/github.schema.graphql | 29914 ----------- .../testdata/introspection_normalized.graphql | 242 - .../testdata/introspectionquery.graphql | 99 - .../testdata/starwars.schema.graphql | 344 - pkg/astparser/testdata/todo.graphql | 228 - pkg/astparser/tokenizer.go | 97 - pkg/astprinter/astprinter.go | 1046 - pkg/astprinter/astprinter_test.go | 939 - .../fixtures/introspectionquery.golden | 210 - .../starwars_schema_definition.golden | 404 - .../testdata/introspectionquery.graphql | 210 - .../testdata/starwars.schema.graphql | 392 - pkg/asttransform/asttransform.go | 167 - pkg/asttransform/baseschema.go | 321 - pkg/asttransform/baseschema_test.go | 150 - pkg/asttransform/fixtures/complete.golden | 216 - .../fixtures/custom_query_name.golden | 216 - .../fixtures/mutation_only.golden | 214 - .../fixtures/schema_missing.golden | 216 - pkg/asttransform/fixtures/simple.golden | 216 - .../fixtures/subscription_only.golden | 213 - .../fixtures/subscription_renamed.golden | 213 - .../with_mutation_subscription.golden | 227 - pkg/asttransform/typename_visitor.go | 87 - pkg/astvalidation/definition_validation.go | 56 - .../definition_validation_test.go | 27 - ...peration_rule_all_variable_uses_defined.go | 56 - .../operation_rule_all_variables_used.go | 84 - .../operation_rule_argument_uniqueness.go | 42 - .../operation_rule_directives_defined.go | 39 - ...tion_rule_directives_in_valid_locations.go | 56 - ...ion_rule_directives_unique_per_location.go | 68 - ..._document_contains_executable_operation.go | 34 - .../operation_rule_field_selection_merging.go | 225 - pkg/astvalidation/operation_rule_fragments.go | 127 - .../operation_rule_known_arguments.go | 62 - ...operation_rule_lone_anonymous_operation.go | 31 - ...peration_rule_operation_name_uniqueness.go | 41 - .../operation_rule_required_arguments.go | 53 - ...ion_rule_subscription_single_root_field.go | 37 - .../operation_rule_valid_arguments.go | 184 - ...peration_rule_validate_field_selections.go | 89 - pkg/astvalidation/operation_rule_values.go | 714 - .../operation_rule_variable_uniqueness.go | 57 - ...peration_rule_variables_are_input_types.go | 54 - pkg/astvalidation/operation_validation.go | 75 - .../operation_validation_test.go | 11539 ---- pkg/astvalidation/overlapping_fields_test.go | 228 - pkg/astvalidation/reference/.gitignore | 1 - .../ExecutableDefinitionsRule-test.js | 94 - .../__tests__/FieldsOnCorrectTypeRule-test.js | 396 - .../FragmentsOnCompositeTypesRule-test.js | 126 - .../__tests__/KnownArgumentNamesRule-test.js | 329 - .../__tests__/KnownDirectivesRule-test.js | 409 - .../__tests__/KnownFragmentNamesRule-test.js | 71 - .../__tests__/KnownTypeNamesRule-test.js | 362 - .../LoneAnonymousOperationRule-test.js | 106 - .../LoneSchemaDefinitionRule-test.js | 158 - .../__tests__/NoDeprecatedCustomRule-test.js | 272 - .../__tests__/NoFragmentCyclesRule-test.js | 260 - .../NoSchemaIntrospectionCustomRule-test.js | 140 - .../NoUndefinedVariablesRule-test.js | 407 - .../__tests__/NoUnusedFragmentsRule-test.js | 163 - .../__tests__/NoUnusedVariablesRule-test.js | 233 - .../OverlappingFieldsCanBeMergedRule-test.js | 1050 - .../PossibleFragmentSpreadsRule-test.js | 250 - .../PossibleTypeExtensionsRule-test.js | 271 - .../ProvidedRequiredArgumentsRule-test.js | 356 - .../__tests__/ScalarLeafsRule-test.js | 129 - .../SingleFieldSubscriptionsRule-test.js | 86 - .../__tests__/UniqueArgumentNamesRule-test.js | 166 - .../UniqueDirectiveNamesRule-test.js | 101 - .../UniqueDirectivesPerLocationRule-test.js | 394 - .../UniqueEnumValueNamesRule-test.js | 194 - .../UniqueFieldDefinitionNamesRule-test.js | 435 - .../__tests__/UniqueFragmentNamesRule-test.js | 119 - .../UniqueInputFieldNamesRule-test.js | 110 - .../UniqueOperationNamesRule-test.js | 135 - .../UniqueOperationTypesRule-test.js | 384 - .../__tests__/UniqueTypeNamesRule-test.js | 162 - .../__tests__/UniqueVariableNamesRule-test.js | 59 - .../__tests__/ValuesOfCorrectTypeRule-test.js | 1197 - .../VariablesAreInputTypesRule-test.js | 44 - .../VariablesInAllowedPositionRule-test.js | 360 - .../reference/__tests__/harness.js | 170 - .../reference/__tests__/validation-test.js | 175 - pkg/astvalidation/reference/gen.sh | 8 - pkg/astvalidation/reference/main.go | 462 - pkg/astvalidation/reference/replacements.yml | 169 - .../testsgo/ExecutableDefinitionsRule_test.go | 99 - .../testsgo/FieldsOnCorrectTypeRule_test.go | 382 - .../FragmentsOnCompositeTypesRule_test.go | 128 - .../testsgo/KnownArgumentNamesRule_test.go | 358 - .../testsgo/KnownDirectivesRule_test.go | 413 - .../testsgo/KnownFragmentNamesRule_test.go | 76 - .../testsgo/KnownTypeNamesRule_test.go | 390 - .../LoneAnonymousOperationRule_test.go | 111 - .../testsgo/LoneSchemaDefinitionRule_test.go | 163 - .../testsgo/NoFragmentCyclesRule_test.go | 263 - .../testsgo/NoUndefinedVariablesRule_test.go | 412 - .../testsgo/NoUnusedFragmentsRule_test.go | 168 - .../testsgo/NoUnusedVariablesRule_test.go | 238 - .../OverlappingFieldsCanBeMergedRule_test.go | 1022 - .../PossibleFragmentSpreadsRule_test.go | 244 - .../PossibleTypeExtensionsRule_test.go | 276 - .../ProvidedRequiredArgumentsRule_test.go | 347 - .../reference/testsgo/ScalarLeafsRule_test.go | 127 - .../SingleFieldSubscriptionsRule_test.go | 88 - .../testsgo/UniqueArgumentNamesRule_test.go | 171 - .../testsgo/UniqueDirectiveNamesRule_test.go | 104 - .../UniqueDirectivesPerLocationRule_test.go | 377 - .../testsgo/UniqueEnumValueNamesRule_test.go | 197 - .../UniqueFieldDefinitionNamesRule_test.go | 434 - .../testsgo/UniqueFragmentNamesRule_test.go | 124 - .../testsgo/UniqueInputFieldNamesRule_test.go | 178 - .../testsgo/UniqueOperationNamesRule_test.go | 140 - .../testsgo/UniqueOperationTypesRule_test.go | 380 - .../testsgo/UniqueTypeNamesRule_test.go | 161 - .../testsgo/UniqueVariableNamesRule_test.go | 64 - .../testsgo/ValuesOfCorrectTypeRule_test.go | 1129 - .../VariablesAreInputTypesRule_test.go | 48 - .../VariablesInAllowedPositionRule_test.go | 355 - .../reference/testsgo/harness_test.go | 323 - .../reference/testsgo/test_schema.graphql | 131 - pkg/astvalidation/rule.go | 10 - .../rule_implement_transitive_interfaces.go | 141 - ...le_implement_transitive_interfaces_test.go | 257 - .../rule_implementing_types_are_supersets.go | 246 - ...e_implementing_types_are_supersets_test.go | 110 - pkg/astvalidation/rule_known_type_names.go | 121 - .../rule_known_type_names_test.go | 191 - .../rule_populated_type_bodies.go | 116 - .../rule_populated_type_bodies_test.go | 126 - ...le_require_defined_types_for_extensions.go | 89 - ...quire_defined_types_for_extensions_test.go | 142 - .../rule_unique_enum_value_names.go | 92 - .../rule_unique_enum_value_names_test.go | 98 - .../rule_unique_field_definition_names.go | 155 - ...rule_unique_field_definition_names_test.go | 243 - .../rule_unique_operation_types.go | 54 - .../rule_unique_operation_types_test.go | 123 - pkg/astvalidation/rule_unique_type_names.go | 75 - .../rule_unique_type_names_test.go | 106 - .../rule_unique_union_member_types.go | 93 - .../rule_unique_union_member_types_test.go | 30 - pkg/astvalidation/validation_state.go | 12 - pkg/astvalidation/validation_state_string.go | 25 - pkg/astvisitor/astvisitor.go | 8 - pkg/astvisitor/fixtures/path.golden | 14 - pkg/astvisitor/fixtures/schema_visitor.golden | 87 - pkg/astvisitor/fixtures/visitor.golden | 77 - pkg/astvisitor/fixtures/visitor_skip.golden | 13 - pkg/astvisitor/simplevisitor.go | 787 - pkg/astvisitor/simplevisitor_test.go | 25 - pkg/astvisitor/visitor.go | 3654 -- pkg/astvisitor/visitor_test.go | 1083 - pkg/codegen/codegen.go | 596 - pkg/codegen/codegen_test.go | 104 - pkg/codegen/fixtures/DataSource.golden | 283 - pkg/codegen/manual.go | 282 - pkg/codegen/manual_test.go | 240 - pkg/codegen/testdata/schema.graphql | 46 - .../datasource/graphql_datasource/batch.go | 205 - .../graphql_datasource/batch_test.go | 288 - .../graphql_datasource/graphql_datasource.go | 1456 - .../graphql_datasource_test.go | 10193 ---- .../graphql_datasource/graphql_sse_handler.go | 286 - .../graphql_sse_handler_test.go | 501 - .../graphql_subscription_client.go | 328 - .../graphql_subscription_client_test.go | 295 - .../graphql_datasource/graphql_tws_handler.go | 275 - .../graphql_tws_handler_test.go | 380 - .../graphql_datasource/graphql_ws_handler.go | 276 - .../graphql_ws_handler_test.go | 358 - .../graphql_ws_proto_types.go | 45 - .../datasource/httpclient/httpclient.go | 251 - .../datasource/httpclient/httpclient_test.go | 198 - .../datasource/httpclient/nethttpclient.go | 124 - .../config_factory.go | 77 - .../introspection_datasource/factory.go | 20 - .../enum_values_with_deprecated.golden | 20 - .../enum_values_without_deprecated.golden | 14 - .../fixtures/fields_with_deprecated.golden | 41 - .../fixtures/fields_without_deprecated.golden | 29 - .../fixtures/not_existing_type.golden | 1 - .../fixtures/schema_introspection.golden | 240 - ...on_with_custom_root_operation_types.golden | 309 - .../fixtures/type_introspection.golden | 50 - .../introspection_datasource/input.go | 75 - .../introspection_datasource/input_test.go | 42 - .../introspection_datasource/planner.go | 54 - .../introspection_datasource/planner_test.go | 460 - .../introspection_datasource/source.go | 102 - .../introspection_datasource/source_test.go | 111 - .../rest_datasource/rest_datasource.go | 172 - .../rest_datasource/rest_datasource_test.go | 1295 - .../staticdatasource/static_datasource.go | 66 - .../static_datasource_test.go | 67 - .../datasourcetesting/datasourcetesting.go | 66 - pkg/engine/plan/analyze_plan_kind.go | 65 - pkg/engine/plan/analyze_plan_kind_test.go | 181 - pkg/engine/plan/local_type_field_extractor.go | 349 - .../plan/local_type_field_extractor_test.go | 944 - pkg/engine/plan/plan.go | 1867 - pkg/engine/plan/plan_closer_test.go | 135 - pkg/engine/plan/plan_test.go | 723 - pkg/engine/plan/required_field_extractor.go | 140 - .../plan/required_field_extractor_test.go | 86 - pkg/engine/resolve/dataloader.go | 517 - pkg/engine/resolve/dataloader.md | 201 - pkg/engine/resolve/dataloader_test.go | 682 - pkg/engine/resolve/defer_test.go | 447 - pkg/engine/resolve/engine.md | 63 - pkg/engine/resolve/fetcher.go | 196 - pkg/engine/resolve/inputtemplate.go | 144 - pkg/engine/resolve/inputtemplate_test.go | 413 - pkg/engine/resolve/resolve.go | 1843 - pkg/engine/resolve/resolve_mock_test.go | 222 - pkg/engine/resolve/resolve_test.go | 4541 -- pkg/engine/resolve/stream_test.go | 411 - pkg/engine/resolve/testdata/defer_1.json | 16 - pkg/engine/resolve/testdata/defer_2.json | 16 - pkg/engine/resolve/testdata/defer_3.json | 16 - pkg/engine/resolve/testdata/posts.json | 14 - .../testdata/response_without_defer.json | 34 - pkg/engine/resolve/testdata/stream_1.json | 5 - pkg/engine/resolve/testdata/stream_2.json | 10 - pkg/engine/resolve/testdata/stream_3.json | 10 - pkg/engine/resolve/testdata/stream_4.json | 10 - pkg/engine/resolve/testdata/stream_5.json | 14 - pkg/engine/resolve/testdata/stream_6.json | 11 - pkg/engine/resolve/testdata/stream_7.json | 11 - pkg/engine/resolve/testdata/stream_8.json | 16 - pkg/engine/resolve/testdata/stream_9.json | 16 - pkg/engine/resolve/testdata/users.json | 48 - pkg/engine/resolve/variable.go | 640 - pkg/escape/bytes.go | 33 - pkg/escape/bytes_test.go | 91 - pkg/escape/escape.go | 2 - pkg/execution/datasource/datasource.go | 272 - .../datasource/datasource_graphql.go | 470 - .../datasource/datasource_http_json.go | 400 - .../datasource_http_polling_stream.go | 267 - pkg/execution/datasource/datasource_mqtt.go | 178 - pkg/execution/datasource/datasource_nats.go | 134 - .../datasource/datasource_pipeline.go | 142 - pkg/execution/datasource/datasource_schema.go | 66 - pkg/execution/datasource/datasource_static.go | 52 - pkg/execution/datasource/datasource_type.go | 48 - pkg/execution/datasource/hooks.go | 23 - pkg/execution/datasource_config.go | 417 - pkg/execution/datasource_graphql_test.go | 312 - pkg/execution/datasource_http_json_test.go | 873 - pkg/execution/datasource_pipeline_test.go | 54 - pkg/execution/execution.go | 613 - pkg/execution/execution_test.go | 3072 -- pkg/execution/fixtures/execution.golden | 52 - .../handler_render_graphql_definitions.golden | 134 - .../fixtures/introspection_execution.golden | 1 - .../render_graphql_definitions.golden | 246 - .../directives/graphql_datasource.graphql | 18 - .../directives/http_json_datasource.graphql | 41 - .../http_polling_stream_datasource.graphql | 25 - .../directives/mapping.graphql | 14 - .../directives/mqtt_datasource.graphql | 8 - .../directives/nats_datasource.graphql | 7 - .../directives/pipeline_datasource.graphql | 20 - .../directives/static_datasource.graphql | 3 - .../directives/transformation.graphql | 5 - .../directives/wasm_datasource.graphql | 4 - .../enums/http_method.graphql | 6 - .../enums/mapping_mode.graphql | 14 - .../enums/parameter_source.graphql | 32 - .../enums/transformation_mode.graphql | 3 - .../graphql_definitions/inputs/header.graphql | 4 - .../inputs/parameter.graphql | 22 - .../statuscode_typename_mapping.graphql | 4 - pkg/execution/handler.go | 109 - pkg/execution/handler_test.go | 42 - pkg/execution/jsonvaluetype.go | 84 - pkg/execution/jsonvaluetype_string.go | 27 - pkg/execution/jsonvaluetype_test.go | 44 - pkg/execution/planning.go | 436 - pkg/execution/planning_test.go | 4358 -- pkg/execution/testdata/memory.wasm | Bin 1845067 -> 0 bytes pkg/execution/testdata/simple_pipeline.json | 7 - pkg/execution/transformation.go | 22 - pkg/execution/transformation_test.go | 256 - pkg/fastbuffer/fastbuffer.go | 61 - pkg/fastbuffer/fastbuffer_test.go | 65 - .../fixtures/federated_schema.golden | 255 - pkg/federation/schema.go | 188 - pkg/federation/schema_test.go | 50 - pkg/federation/sdlmerge/collect_entities.go | 62 - .../sdlmerge/collect_entities_test.go | 88 - .../sdlmerge/enum_type_extending.go | 50 - .../sdlmerge/enum_type_extending_test.go | 107 - .../sdlmerge/input_type_extending.go | 50 - .../sdlmerge/input_type_extending_test.go | 83 - .../sdlmerge/interface_type_extending.go | 63 - .../sdlmerge/interface_type_extending_test.go | 172 - .../sdlmerge/merge_duplicated_fields.go | 62 - .../sdlmerge/object_type_extending.go | 66 - .../sdlmerge/object_type_extending_test.go | 238 - .../remove_duplicate_fielded_shared_types.go | 107 - ...ove_duplicate_fielded_shared_types_test.go | 529 - ...remove_duplicate_fieldless_shared_types.go | 98 - ...e_duplicate_fieldless_shared_types_test.go | 373 - .../remove_empty_object_type_definition.go | 32 - ...emove_empty_object_type_definition_test.go | 21 - .../remove_field_definition_by_directive.go | 46 - ...move_field_definition_by_directive_test.go | 28 - .../remove_field_definition_directive.go | 44 - .../remove_field_definition_directive_test.go | 29 - .../remove_interface_definition_directive.go | 45 - ...ove_interface_definition_directive_test.go | 50 - ...remove_object_type_definition_directive.go | 44 - ...e_object_type_definition_directive_test.go | 62 - .../sdlmerge/remove_type_extensions.go | 21 - .../sdlmerge/remove_type_extensions_test.go | 88 - .../sdlmerge/scalar_type_extending.go | 49 - .../sdlmerge/scalar_type_extending_test.go | 29 - pkg/federation/sdlmerge/sdlmerge.go | 205 - pkg/federation/sdlmerge/sdlmerge_test.go | 838 - pkg/federation/sdlmerge/shared_types.go | 168 - .../lack-definition-non-null.graphqls | 16 - .../lack-definition.graphqls | 16 - .../lack-extend-definition-non-null.graphqls | 16 - .../lack-extend-definition.graphqls | 17 - .../well-defined-non-null.graphqls | 16 - .../validate-subgraph/well-defined.graphqls | 16 - .../sdlmerge/union_type_extending.go | 50 - .../sdlmerge/union_type_extending_test.go | 71 - pkg/graphql/complexity.go | 75 - pkg/graphql/config_factory_federation.go | 203 - pkg/graphql/config_factory_federation_test.go | 298 - pkg/graphql/config_factory_proxy.go | 121 - pkg/graphql/config_factory_proxy_test.go | 291 - pkg/graphql/engine_config_v2.go | 255 - pkg/graphql/engine_config_v2_test.go | 329 - pkg/graphql/errors.go | 207 - pkg/graphql/errors_test.go | 155 - pkg/graphql/execution_engine.go | 172 - pkg/graphql/execution_engine_test.go | 684 - pkg/graphql/execution_engine_v2.go | 328 - .../execution_engine_v2_norace_test.go | 170 - pkg/graphql/execution_engine_v2_test.go | 2408 - pkg/graphql/extractor.go | 66 - pkg/graphql/extractor_test.go | 91 - .../fixtures/introspection_response.golden | 1 - pkg/graphql/lookup.go | 24 - pkg/graphql/lookup_test.go | 32 - pkg/graphql/normalization.go | 69 - pkg/graphql/normalization_test.go | 283 - pkg/graphql/request.go | 201 - pkg/graphql/request_fields_validator.go | 132 - pkg/graphql/request_fields_validator_test.go | 136 - pkg/graphql/request_test.go | 313 - pkg/graphql/response.go | 15 - pkg/graphql/schema.go | 470 - pkg/graphql/schema_test.go | 1932 - pkg/graphql/starwars_helpers_test.go | 41 - pkg/graphql/subscription.go | 16 - pkg/graphql/types.go | 11 - pkg/graphql/validation.go | 96 - pkg/graphql/validation_test.go | 323 - pkg/graphqlerrors/location.go | 6 - pkg/graphqljsonschema/jsonschema.go | 414 - pkg/graphqljsonschema/jsonschema_test.go | 1641 - pkg/http/handler.go | 87 - pkg/http/handler_test.go | 230 - pkg/http/http.go | 65 - pkg/http/ws.go | 185 - pkg/http/ws_connection_init.json | 4 - pkg/http/ws_start.json | 10 - pkg/http/ws_test.go | 131 - pkg/imports/fixtures/render_result.golden | 41 - .../fixtures/render_result_windows.golden | 41 - pkg/imports/fixtures/scanner_regex.golden | 17 - .../fixtures/scanner_regex_render.golden | 10 - .../fixtures/scanner_regex_windows.golden | 17 - pkg/imports/fixtures/scanner_result.golden | 26 - .../fixtures/scanner_result_windows.golden | 26 - pkg/imports/graphql_file.go | 92 - pkg/imports/graphql_file_test.go | 37 - pkg/imports/imports.go | 109 - pkg/imports/imports_test.go | 88 - pkg/imports/testdata/cycle/a/a.graphql | 1 - pkg/imports/testdata/cycle/b/b.graphql | 1 - .../testdata/deep/deeper/custom_types.graphql | 3 - .../testdata/deep/deeper/non_graphql.txt | 0 pkg/imports/testdata/import_cycle.graphql | 1 - pkg/imports/testdata/nested/nested.graphql | 5 - pkg/imports/testdata/nested2/nested2.graphql | 3 - pkg/imports/testdata/regexonly/flat.graphql | 4 - .../testdata/regexonly/mutation.graphql | 3 - pkg/imports/testdata/regexonly/query.graphql | 3 - pkg/imports/testdata/scalars/json.graphql | 1 - pkg/imports/testdata/schema.graphql | 9 - pkg/imports/testdata/types/mutation.graphql | 3 - pkg/imports/testdata/types/query.graphql | 3 - pkg/internal/quotes/quotes.go | 20 - pkg/internal/quotes/quotes_test.go | 24 - pkg/internal/unsafebytes/unsafebytes.go | 62 - pkg/internal/unsafebytes/unsafebytes_test.go | 150 - pkg/internal/unsafeparser/unsafeparser.go | 33 - pkg/internal/unsafeprinter/unsafeprinter.go | 28 - pkg/introspection/converter.go | 275 - pkg/introspection/converter_test.go | 76 - .../interfaces_implementing_interfaces.golden | 254 - pkg/introspection/fixtures/starwars.golden | 203 - .../fixtures/starwars_introspected.golden | 1359 - pkg/introspection/generator.go | 352 - pkg/introspection/generator_test.go | 80 - pkg/introspection/introspection.go | 155 - pkg/introspection/introspection_enum.go | 83 - pkg/introspection/introspection_test.go | 31 - ...interfaces_implementing_interfaces.graphql | 35 - .../out_swapi_introspection_response.json | 43273 ---------------- .../testdata/starwars.schema.graphql | 351 - .../swapi_introspection_response.json | 43270 --------------- pkg/lexer/fixtures/introspection_lexed.golden | 1952 - pkg/lexer/identkeyword/identkeyword.go | 105 - pkg/lexer/identkeyword/identkeyword_string.go | 42 - pkg/lexer/keyword/keyword.go | 42 - pkg/lexer/keyword/keyword_string.go | 52 - pkg/lexer/lexer.go | 430 - pkg/lexer/lexer_test.go | 680 - pkg/lexer/literal/literal.go | 156 - pkg/lexer/position/position.go | 42 - pkg/lexer/runes/runes.go | 35 - pkg/lexer/token/token.go | 32 - pkg/middleware/middleware.go | 2 - .../operation_complexity.go | 292 - .../operation_complexity_test.go | 895 - pkg/operationreport/externalerror.go | 494 - pkg/operationreport/externalerror_test.go | 71 - pkg/operationreport/operationreport.go | 67 - pkg/operationreport/operationreport_test.go | 63 - pkg/playground/files/favicon.png | Bin 5057 -> 0 bytes pkg/playground/files/logo.png | Bin 32043 -> 0 bytes pkg/playground/files/playground.css | 1 - pkg/playground/files/playground.html | 55 - pkg/playground/files/playground.js | 1 - pkg/playground/fixtures/handlers.golden | 22 - pkg/playground/playground.go | 186 - pkg/playground/playground_test.go | 104 - pkg/pool/bytesbuffer.go | 29 - pkg/pool/fastbuffer.go | 28 - pkg/pool/hash64.go | 31 - pkg/postprocess/datasourceinput.go | 104 - pkg/postprocess/datasourceinput_test.go | 316 - pkg/postprocess/defer.go | 169 - pkg/postprocess/defer_test.go | 941 - pkg/postprocess/postprocess.go | 31 - pkg/postprocess/postprocess_test.go | 437 - pkg/postprocess/stream.go | 86 - pkg/postprocess/stream_test.go | 411 - pkg/repair/repair.go | 2 - pkg/repair/sdl.go | 189 - pkg/repair/sdl_test.go | 47 - pkg/starwars/starwars.go | 101 - .../testdata/mutations/create_review.mutation | 7 - .../testdata/queries/directives_include.query | 8 - .../testdata/queries/directives_skip.query | 8 - .../testdata/queries/droid_with_arg.query | 5 - .../queries/droid_with_arg_and_var.query | 5 - pkg/starwars/testdata/queries/fragments.query | 12 - .../testdata/queries/hero_with_aliases.query | 8 - .../queries/hero_with_operation_name.query | 5 - .../testdata/queries/inline_fragments.query | 14 - .../interface_fragments_on_union.graphql | 10 - .../testdata/queries/introspection.query | 99 - pkg/starwars/testdata/queries/invalid.query | 5 - .../testdata/queries/invalid_fragments.query | 11 - .../testdata/queries/multi_queries.query | 14 - .../multi_queries_with_arguments.query | 22 - .../testdata/queries/simple_hero.query | 5 - pkg/starwars/testdata/queries/union.query | 16 - pkg/starwars/testdata/star_wars.graphql | 65 - .../remaining_jedis.subscription | 3 - pkg/subscription/constants.go | 7 - pkg/subscription/context.go | 73 - pkg/subscription/context_test.go | 73 - pkg/subscription/engine.go | 215 - pkg/subscription/engine_mock_test.go | 77 - pkg/subscription/engine_test.go | 512 - pkg/subscription/executor.go | 24 - pkg/subscription/executor_mock_test.go | 141 - pkg/subscription/executor_v1.go | 70 - pkg/subscription/executor_v2.go | 88 - pkg/subscription/handler.go | 210 - pkg/subscription/handler_mock_test.go | 98 - pkg/subscription/handler_test.go | 338 - pkg/subscription/init.go | 49 - pkg/subscription/legacy_handler.go | 499 - pkg/subscription/legacy_handler_test.go | 917 - pkg/subscription/mock_client_test.go | 150 - pkg/subscription/time_out.go | 38 - pkg/subscription/time_out_test.go | 59 - pkg/subscription/transport_client.go | 27 - .../transport_client_mock_test.go | 105 - pkg/subscription/websocket/client.go | 187 - pkg/subscription/websocket/client_test.go | 461 - .../websocket/engine_mock_test.go | 78 - pkg/subscription/websocket/handler.go | 228 - pkg/subscription/websocket/handler_test.go | 344 - pkg/subscription/websocket/init.go | 47 - .../protocol_graphql_transport_ws.go | 524 - .../protocol_graphql_transport_ws_test.go | 572 - .../websocket/protocol_graphql_ws.go | 359 - .../websocket/protocol_graphql_ws_test.go | 411 - .../federationtesting/accounts/gqlgen.yml | 55 - .../accounts/graph/entity.resolvers.go | 31 - .../accounts/graph/generated/federation.go | 187 - .../accounts/graph/generated/generated.go | 5456 -- .../accounts/graph/handler.go | 31 - .../accounts/graph/histories.go | 56 - .../accounts/graph/model/models_gen.go | 92 - .../accounts/graph/resolver.go | 6 - .../accounts/graph/schema.graphqls | 64 - .../accounts/graph/schema.resolvers.go | 49 - .../accounts/graph/wallets.go | 15 - .../federationtesting/accounts/handler.go | 12 - .../federation_integration_test.go | 462 - .../gateway/datasource_poller.go | 213 - .../federationtesting/gateway/gateway.go | 104 - .../federationtesting/gateway/http/handler.go | 68 - .../federationtesting/gateway/http/http.go | 42 - .../federationtesting/gateway/http/ws.go | 160 - pkg/testing/federationtesting/gateway/main.go | 42 - .../federationtesting/graphql_client_test.go | 138 - .../federationtesting/products/gqlgen.yml | 55 - .../products/graph/entity.resolvers.go | 27 - .../products/graph/generated/federation.go | 187 - .../products/graph/generated/generated.go | 4276 -- .../products/graph/handler.go | 82 - .../products/graph/model/models_gen.go | 12 - .../products/graph/products.go | 34 - .../products/graph/resolver.go | 6 - .../products/graph/schema.graphqls | 15 - .../products/graph/schema.resolvers.go | 90 - .../products/graph/variables.go | 13 - .../federationtesting/products/handler.go | 17 - .../federationtesting/reviews/gqlgen.yml | 55 - .../reviews/graph/attachments.go | 32 - .../reviews/graph/entity.resolvers.go | 31 - .../reviews/graph/generated/federation.go | 224 - .../reviews/graph/generated/generated.go | 5645 -- .../reviews/graph/handler.go | 31 - .../reviews/graph/model/models.go | 19 - .../reviews/graph/model/models_gen.go | 47 - .../reviews/graph/resolver.go | 6 - .../reviews/graph/reviews.go | 23 - .../reviews/graph/schema.graphqls | 54 - .../reviews/graph/schema.resolvers.go | 129 - .../federationtesting/reviews/handler.go | 12 - .../mutations/mutation_with_variables.query | 8 - .../testdata/queries/complex_nesting.graphql | 41 - .../testdata/queries/interface.query | 21 - .../interface_fragment_on_object.graphql | 10 - .../interface_fragments_on_union.graphql | 12 - .../testdata/queries/merged_field.graphql | 18 - .../testdata/queries/multiple_queries.query | 12 - ...ltiple_queries_with_nested_fragments.query | 30 - .../multiple_queries_with_union_return.query | 27 - .../testdata/queries/multiple_upstream.query | 11 - .../object_fragment_on_interface.graphql | 9 - .../testdata/queries/single_upstream.query | 6 - .../testdata/queries/union.query | 16 - .../testdata/subscriptions/subscription.query | 7 - pkg/testing/federationtesting/util.go | 48 - pkg/testing/flags/flags.go | 5 - pkg/testing/flags/flags_win.go | 5 - pkg/testing/goldie/goldie.go | 12 - pkg/testing/goldie/goldie_posix.go | 19 - pkg/testing/goldie/goldie_win.go | 22 - pkg/testing/subscriptiontesting/.gqlgen.yml | 3 - pkg/testing/subscriptiontesting/chat_test.go | 51 - pkg/testing/subscriptiontesting/generated.go | 3982 -- pkg/testing/subscriptiontesting/handler.go | 29 - pkg/testing/subscriptiontesting/models_gen.go | 14 - pkg/testing/subscriptiontesting/resolvers.go | 169 - .../subscriptiontesting/schema.graphql | 27 - pkg/testing/subscriptiontesting/util.go | 76 - 708 files changed, 24 insertions(+), 312411 deletions(-) delete mode 100644 Makefile delete mode 100644 pkg/ast/ast.go delete mode 100644 pkg/ast/ast_argument.go delete mode 100644 pkg/ast/ast_description.go delete mode 100644 pkg/ast/ast_directive.go delete mode 100644 pkg/ast/ast_directive_definition.go delete mode 100644 pkg/ast/ast_enum_type_definition.go delete mode 100644 pkg/ast/ast_enum_type_extension.go delete mode 100644 pkg/ast/ast_enum_value_definition.go delete mode 100644 pkg/ast/ast_field.go delete mode 100644 pkg/ast/ast_field_alias.go delete mode 100644 pkg/ast/ast_field_definition.go delete mode 100644 pkg/ast/ast_fragment_definition.go delete mode 100644 pkg/ast/ast_fragment_spread.go delete mode 100644 pkg/ast/ast_inline_fragment.go delete mode 100644 pkg/ast/ast_input_object_type_definition.go delete mode 100644 pkg/ast/ast_input_object_type_extension.go delete mode 100644 pkg/ast/ast_input_value_definition.go delete mode 100644 pkg/ast/ast_interface_type_definition.go delete mode 100644 pkg/ast/ast_interface_type_extension.go delete mode 100644 pkg/ast/ast_node.go delete mode 100644 pkg/ast/ast_node_kind.go delete mode 100644 pkg/ast/ast_node_kind_test.go delete mode 100644 pkg/ast/ast_object_field.go delete mode 100644 pkg/ast/ast_object_type_definition.go delete mode 100644 pkg/ast/ast_object_type_definition_test.go delete mode 100644 pkg/ast/ast_object_type_extension.go delete mode 100644 pkg/ast/ast_operation_definition.go delete mode 100644 pkg/ast/ast_operation_definition_test.go delete mode 100644 pkg/ast/ast_root_operation_type_definition.go delete mode 100644 pkg/ast/ast_root_operation_type_definition_test.go delete mode 100644 pkg/ast/ast_scalar_type_definition.go delete mode 100644 pkg/ast/ast_scalar_type_extension.go delete mode 100644 pkg/ast/ast_schema_definition.go delete mode 100644 pkg/ast/ast_schema_extension.go delete mode 100644 pkg/ast/ast_selection.go delete mode 100644 pkg/ast/ast_string.go delete mode 100644 pkg/ast/ast_test.go delete mode 100644 pkg/ast/ast_type.go delete mode 100644 pkg/ast/ast_type_test.go delete mode 100644 pkg/ast/ast_union_type_definition.go delete mode 100644 pkg/ast/ast_union_type_extension.go delete mode 100644 pkg/ast/ast_val_boolean_value.go delete mode 100644 pkg/ast/ast_val_enum_value.go delete mode 100644 pkg/ast/ast_val_float_value.go delete mode 100644 pkg/ast/ast_val_int_value.go delete mode 100644 pkg/ast/ast_val_list_value.go delete mode 100644 pkg/ast/ast_val_object_value.go delete mode 100644 pkg/ast/ast_val_string_value.go delete mode 100644 pkg/ast/ast_val_variable_value.go delete mode 100644 pkg/ast/ast_value.go delete mode 100644 pkg/ast/ast_value_test.go delete mode 100644 pkg/ast/ast_variable_definition.go delete mode 100644 pkg/ast/directive_location.go delete mode 100644 pkg/ast/directive_location_string.go delete mode 100644 pkg/ast/directive_location_test.go delete mode 100644 pkg/ast/helpers.go delete mode 100644 pkg/ast/index.go delete mode 100644 pkg/ast/index_test.go delete mode 100644 pkg/ast/input.go delete mode 100644 pkg/ast/path.go delete mode 100644 pkg/astimport/astimport.go delete mode 100644 pkg/astimport/astimport_test.go delete mode 100644 pkg/astnormalization/astnormalization.go delete mode 100644 pkg/astnormalization/astnormalization_test.go delete mode 100644 pkg/astnormalization/definition_normalization.go delete mode 100644 pkg/astnormalization/definition_normalization_test.go delete mode 100644 pkg/astnormalization/directive_include_skip.go delete mode 100644 pkg/astnormalization/directive_include_skip_test.go delete mode 100644 pkg/astnormalization/enum_type_extending.go delete mode 100644 pkg/astnormalization/enum_type_extending_test.go delete mode 100644 pkg/astnormalization/extends_directive.go delete mode 100644 pkg/astnormalization/extends_directive_test.go delete mode 100644 pkg/astnormalization/field_deduplication.go delete mode 100644 pkg/astnormalization/field_deduplication_test.go delete mode 100644 pkg/astnormalization/field_selection_merging.go delete mode 100644 pkg/astnormalization/field_selection_merging_test.go delete mode 100644 pkg/astnormalization/fragment_definition_removal.go delete mode 100644 pkg/astnormalization/fragment_spread_inlining.go delete mode 100644 pkg/astnormalization/fragment_spread_inlining_test.go delete mode 100644 pkg/astnormalization/fragmentspread_depth.go delete mode 100644 pkg/astnormalization/fragmentspread_depth_test.go delete mode 100644 pkg/astnormalization/implicit_extend_root_operation.go delete mode 100644 pkg/astnormalization/implicit_extend_root_operation_test.go delete mode 100644 pkg/astnormalization/implicit_schema_definition.go delete mode 100644 pkg/astnormalization/implicit_schema_definition_test.go delete mode 100644 pkg/astnormalization/inject_input_default_values.go delete mode 100644 pkg/astnormalization/inject_input_default_values_test.go delete mode 100644 pkg/astnormalization/inline_fragment_merging.go delete mode 100644 pkg/astnormalization/inline_fragment_merging_test.go delete mode 100644 pkg/astnormalization/input_coercion_for_list.go delete mode 100644 pkg/astnormalization/input_coercion_for_list_test.go delete mode 100644 pkg/astnormalization/input_object_type_extending.go delete mode 100644 pkg/astnormalization/input_object_type_extending_test.go delete mode 100644 pkg/astnormalization/interface_type_extending.go delete mode 100644 pkg/astnormalization/interface_type_extending_test.go delete mode 100644 pkg/astnormalization/object_type_extending.go delete mode 100644 pkg/astnormalization/object_type_extending_test.go delete mode 100644 pkg/astnormalization/remove_self_aliasing.go delete mode 100644 pkg/astnormalization/remove_self_aliasing_test.go delete mode 100644 pkg/astnormalization/remove_type_extensions.go delete mode 100644 pkg/astnormalization/remove_type_extensions_test.go delete mode 100644 pkg/astnormalization/scalar_type_extending.go delete mode 100644 pkg/astnormalization/scalar_type_extending_test.go delete mode 100644 pkg/astnormalization/subgraph_sdl_normalization.go delete mode 100644 pkg/astnormalization/subgraph_sdl_normalization_test.go delete mode 100644 pkg/astnormalization/union_type_extending.go delete mode 100644 pkg/astnormalization/union_type_extending_test.go delete mode 100644 pkg/astnormalization/variables_default_value_extraction.go delete mode 100644 pkg/astnormalization/variables_default_value_extraction_test.go delete mode 100644 pkg/astnormalization/variables_extraction.go delete mode 100644 pkg/astnormalization/variables_extraction_test.go delete mode 100644 pkg/astnormalization/variables_unused_deletion.go delete mode 100644 pkg/astnormalization/variables_unused_deletion_test.go delete mode 100644 pkg/astparser/errors.go delete mode 100644 pkg/astparser/parser.go delete mode 100644 pkg/astparser/parser_test.go delete mode 100644 pkg/astparser/parser_token_helpers.go delete mode 100644 pkg/astparser/testdata/big_schema.graphql delete mode 100644 pkg/astparser/testdata/github.schema.graphql delete mode 100644 pkg/astparser/testdata/introspection_normalized.graphql delete mode 100644 pkg/astparser/testdata/introspectionquery.graphql delete mode 100644 pkg/astparser/testdata/starwars.schema.graphql delete mode 100644 pkg/astparser/testdata/todo.graphql delete mode 100644 pkg/astparser/tokenizer.go delete mode 100644 pkg/astprinter/astprinter.go delete mode 100644 pkg/astprinter/astprinter_test.go delete mode 100644 pkg/astprinter/fixtures/introspectionquery.golden delete mode 100644 pkg/astprinter/fixtures/starwars_schema_definition.golden delete mode 100644 pkg/astprinter/testdata/introspectionquery.graphql delete mode 100644 pkg/astprinter/testdata/starwars.schema.graphql delete mode 100644 pkg/asttransform/asttransform.go delete mode 100644 pkg/asttransform/baseschema.go delete mode 100644 pkg/asttransform/baseschema_test.go delete mode 100644 pkg/asttransform/fixtures/complete.golden delete mode 100644 pkg/asttransform/fixtures/custom_query_name.golden delete mode 100644 pkg/asttransform/fixtures/mutation_only.golden delete mode 100644 pkg/asttransform/fixtures/schema_missing.golden delete mode 100644 pkg/asttransform/fixtures/simple.golden delete mode 100644 pkg/asttransform/fixtures/subscription_only.golden delete mode 100644 pkg/asttransform/fixtures/subscription_renamed.golden delete mode 100644 pkg/asttransform/fixtures/with_mutation_subscription.golden delete mode 100644 pkg/asttransform/typename_visitor.go delete mode 100644 pkg/astvalidation/definition_validation.go delete mode 100644 pkg/astvalidation/definition_validation_test.go delete mode 100644 pkg/astvalidation/operation_rule_all_variable_uses_defined.go delete mode 100644 pkg/astvalidation/operation_rule_all_variables_used.go delete mode 100644 pkg/astvalidation/operation_rule_argument_uniqueness.go delete mode 100644 pkg/astvalidation/operation_rule_directives_defined.go delete mode 100644 pkg/astvalidation/operation_rule_directives_in_valid_locations.go delete mode 100644 pkg/astvalidation/operation_rule_directives_unique_per_location.go delete mode 100644 pkg/astvalidation/operation_rule_document_contains_executable_operation.go delete mode 100644 pkg/astvalidation/operation_rule_field_selection_merging.go delete mode 100644 pkg/astvalidation/operation_rule_fragments.go delete mode 100644 pkg/astvalidation/operation_rule_known_arguments.go delete mode 100644 pkg/astvalidation/operation_rule_lone_anonymous_operation.go delete mode 100644 pkg/astvalidation/operation_rule_operation_name_uniqueness.go delete mode 100644 pkg/astvalidation/operation_rule_required_arguments.go delete mode 100644 pkg/astvalidation/operation_rule_subscription_single_root_field.go delete mode 100644 pkg/astvalidation/operation_rule_valid_arguments.go delete mode 100644 pkg/astvalidation/operation_rule_validate_field_selections.go delete mode 100644 pkg/astvalidation/operation_rule_values.go delete mode 100644 pkg/astvalidation/operation_rule_variable_uniqueness.go delete mode 100644 pkg/astvalidation/operation_rule_variables_are_input_types.go delete mode 100644 pkg/astvalidation/operation_validation.go delete mode 100644 pkg/astvalidation/operation_validation_test.go delete mode 100644 pkg/astvalidation/overlapping_fields_test.go delete mode 100644 pkg/astvalidation/reference/.gitignore delete mode 100644 pkg/astvalidation/reference/__tests__/ExecutableDefinitionsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/FieldsOnCorrectTypeRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/FragmentsOnCompositeTypesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/KnownArgumentNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/KnownDirectivesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/KnownFragmentNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/KnownTypeNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/LoneAnonymousOperationRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/LoneSchemaDefinitionRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/NoDeprecatedCustomRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/NoFragmentCyclesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/NoSchemaIntrospectionCustomRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/NoUndefinedVariablesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/NoUnusedFragmentsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/NoUnusedVariablesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/OverlappingFieldsCanBeMergedRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/PossibleFragmentSpreadsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/PossibleTypeExtensionsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/ProvidedRequiredArgumentsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/ScalarLeafsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/SingleFieldSubscriptionsRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueArgumentNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueDirectiveNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueDirectivesPerLocationRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueEnumValueNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueFieldDefinitionNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueFragmentNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueInputFieldNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueOperationNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueOperationTypesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueTypeNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/UniqueVariableNamesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/ValuesOfCorrectTypeRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/VariablesAreInputTypesRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/VariablesInAllowedPositionRule-test.js delete mode 100644 pkg/astvalidation/reference/__tests__/harness.js delete mode 100644 pkg/astvalidation/reference/__tests__/validation-test.js delete mode 100755 pkg/astvalidation/reference/gen.sh delete mode 100644 pkg/astvalidation/reference/main.go delete mode 100644 pkg/astvalidation/reference/replacements.yml delete mode 100755 pkg/astvalidation/reference/testsgo/ExecutableDefinitionsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/FieldsOnCorrectTypeRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/FragmentsOnCompositeTypesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/KnownArgumentNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/KnownDirectivesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/KnownFragmentNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/KnownTypeNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/LoneAnonymousOperationRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/LoneSchemaDefinitionRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/NoFragmentCyclesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/NoUndefinedVariablesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/NoUnusedFragmentsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/NoUnusedVariablesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/OverlappingFieldsCanBeMergedRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/PossibleFragmentSpreadsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/PossibleTypeExtensionsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/ProvidedRequiredArgumentsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/ScalarLeafsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/SingleFieldSubscriptionsRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueArgumentNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueDirectiveNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueDirectivesPerLocationRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueEnumValueNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueFieldDefinitionNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueFragmentNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueInputFieldNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueOperationNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueOperationTypesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueTypeNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/UniqueVariableNamesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/ValuesOfCorrectTypeRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/VariablesAreInputTypesRule_test.go delete mode 100755 pkg/astvalidation/reference/testsgo/VariablesInAllowedPositionRule_test.go delete mode 100644 pkg/astvalidation/reference/testsgo/harness_test.go delete mode 100644 pkg/astvalidation/reference/testsgo/test_schema.graphql delete mode 100644 pkg/astvalidation/rule.go delete mode 100644 pkg/astvalidation/rule_implement_transitive_interfaces.go delete mode 100644 pkg/astvalidation/rule_implement_transitive_interfaces_test.go delete mode 100644 pkg/astvalidation/rule_implementing_types_are_supersets.go delete mode 100644 pkg/astvalidation/rule_implementing_types_are_supersets_test.go delete mode 100644 pkg/astvalidation/rule_known_type_names.go delete mode 100644 pkg/astvalidation/rule_known_type_names_test.go delete mode 100644 pkg/astvalidation/rule_populated_type_bodies.go delete mode 100644 pkg/astvalidation/rule_populated_type_bodies_test.go delete mode 100644 pkg/astvalidation/rule_require_defined_types_for_extensions.go delete mode 100644 pkg/astvalidation/rule_require_defined_types_for_extensions_test.go delete mode 100644 pkg/astvalidation/rule_unique_enum_value_names.go delete mode 100644 pkg/astvalidation/rule_unique_enum_value_names_test.go delete mode 100644 pkg/astvalidation/rule_unique_field_definition_names.go delete mode 100644 pkg/astvalidation/rule_unique_field_definition_names_test.go delete mode 100644 pkg/astvalidation/rule_unique_operation_types.go delete mode 100644 pkg/astvalidation/rule_unique_operation_types_test.go delete mode 100644 pkg/astvalidation/rule_unique_type_names.go delete mode 100644 pkg/astvalidation/rule_unique_type_names_test.go delete mode 100644 pkg/astvalidation/rule_unique_union_member_types.go delete mode 100644 pkg/astvalidation/rule_unique_union_member_types_test.go delete mode 100644 pkg/astvalidation/validation_state.go delete mode 100644 pkg/astvalidation/validation_state_string.go delete mode 100644 pkg/astvisitor/astvisitor.go delete mode 100644 pkg/astvisitor/fixtures/path.golden delete mode 100644 pkg/astvisitor/fixtures/schema_visitor.golden delete mode 100644 pkg/astvisitor/fixtures/visitor.golden delete mode 100644 pkg/astvisitor/fixtures/visitor_skip.golden delete mode 100644 pkg/astvisitor/simplevisitor.go delete mode 100644 pkg/astvisitor/simplevisitor_test.go delete mode 100644 pkg/astvisitor/visitor.go delete mode 100644 pkg/astvisitor/visitor_test.go delete mode 100644 pkg/codegen/codegen.go delete mode 100644 pkg/codegen/codegen_test.go delete mode 100644 pkg/codegen/fixtures/DataSource.golden delete mode 100644 pkg/codegen/manual.go delete mode 100644 pkg/codegen/manual_test.go delete mode 100644 pkg/codegen/testdata/schema.graphql delete mode 100644 pkg/engine/datasource/graphql_datasource/batch.go delete mode 100644 pkg/engine/datasource/graphql_datasource/batch_test.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_datasource.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_sse_handler.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_sse_handler_test.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_subscription_client.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_subscription_client_test.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_tws_handler.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_tws_handler_test.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_ws_handler.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_ws_handler_test.go delete mode 100644 pkg/engine/datasource/graphql_datasource/graphql_ws_proto_types.go delete mode 100644 pkg/engine/datasource/httpclient/httpclient.go delete mode 100644 pkg/engine/datasource/httpclient/httpclient_test.go delete mode 100644 pkg/engine/datasource/httpclient/nethttpclient.go delete mode 100644 pkg/engine/datasource/introspection_datasource/config_factory.go delete mode 100644 pkg/engine/datasource/introspection_datasource/factory.go delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/enum_values_with_deprecated.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/enum_values_without_deprecated.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/fields_with_deprecated.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/fields_without_deprecated.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/not_existing_type.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection_with_custom_root_operation_types.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/fixtures/type_introspection.golden delete mode 100644 pkg/engine/datasource/introspection_datasource/input.go delete mode 100644 pkg/engine/datasource/introspection_datasource/input_test.go delete mode 100644 pkg/engine/datasource/introspection_datasource/planner.go delete mode 100644 pkg/engine/datasource/introspection_datasource/planner_test.go delete mode 100644 pkg/engine/datasource/introspection_datasource/source.go delete mode 100644 pkg/engine/datasource/introspection_datasource/source_test.go delete mode 100644 pkg/engine/datasource/rest_datasource/rest_datasource.go delete mode 100644 pkg/engine/datasource/rest_datasource/rest_datasource_test.go delete mode 100644 pkg/engine/datasource/staticdatasource/static_datasource.go delete mode 100644 pkg/engine/datasource/staticdatasource/static_datasource_test.go delete mode 100644 pkg/engine/datasourcetesting/datasourcetesting.go delete mode 100644 pkg/engine/plan/analyze_plan_kind.go delete mode 100644 pkg/engine/plan/analyze_plan_kind_test.go delete mode 100644 pkg/engine/plan/local_type_field_extractor.go delete mode 100644 pkg/engine/plan/local_type_field_extractor_test.go delete mode 100644 pkg/engine/plan/plan.go delete mode 100644 pkg/engine/plan/plan_closer_test.go delete mode 100644 pkg/engine/plan/plan_test.go delete mode 100644 pkg/engine/plan/required_field_extractor.go delete mode 100644 pkg/engine/plan/required_field_extractor_test.go delete mode 100644 pkg/engine/resolve/dataloader.go delete mode 100644 pkg/engine/resolve/dataloader.md delete mode 100644 pkg/engine/resolve/dataloader_test.go delete mode 100644 pkg/engine/resolve/defer_test.go delete mode 100644 pkg/engine/resolve/engine.md delete mode 100644 pkg/engine/resolve/fetcher.go delete mode 100644 pkg/engine/resolve/inputtemplate.go delete mode 100644 pkg/engine/resolve/inputtemplate_test.go delete mode 100644 pkg/engine/resolve/resolve.go delete mode 100644 pkg/engine/resolve/resolve_mock_test.go delete mode 100644 pkg/engine/resolve/resolve_test.go delete mode 100644 pkg/engine/resolve/stream_test.go delete mode 100644 pkg/engine/resolve/testdata/defer_1.json delete mode 100644 pkg/engine/resolve/testdata/defer_2.json delete mode 100644 pkg/engine/resolve/testdata/defer_3.json delete mode 100644 pkg/engine/resolve/testdata/posts.json delete mode 100644 pkg/engine/resolve/testdata/response_without_defer.json delete mode 100644 pkg/engine/resolve/testdata/stream_1.json delete mode 100644 pkg/engine/resolve/testdata/stream_2.json delete mode 100644 pkg/engine/resolve/testdata/stream_3.json delete mode 100644 pkg/engine/resolve/testdata/stream_4.json delete mode 100644 pkg/engine/resolve/testdata/stream_5.json delete mode 100644 pkg/engine/resolve/testdata/stream_6.json delete mode 100644 pkg/engine/resolve/testdata/stream_7.json delete mode 100644 pkg/engine/resolve/testdata/stream_8.json delete mode 100644 pkg/engine/resolve/testdata/stream_9.json delete mode 100644 pkg/engine/resolve/testdata/users.json delete mode 100644 pkg/engine/resolve/variable.go delete mode 100644 pkg/escape/bytes.go delete mode 100644 pkg/escape/bytes_test.go delete mode 100644 pkg/escape/escape.go delete mode 100644 pkg/execution/datasource/datasource.go delete mode 100644 pkg/execution/datasource/datasource_graphql.go delete mode 100644 pkg/execution/datasource/datasource_http_json.go delete mode 100644 pkg/execution/datasource/datasource_http_polling_stream.go delete mode 100644 pkg/execution/datasource/datasource_mqtt.go delete mode 100644 pkg/execution/datasource/datasource_nats.go delete mode 100644 pkg/execution/datasource/datasource_pipeline.go delete mode 100644 pkg/execution/datasource/datasource_schema.go delete mode 100644 pkg/execution/datasource/datasource_static.go delete mode 100644 pkg/execution/datasource/datasource_type.go delete mode 100644 pkg/execution/datasource/hooks.go delete mode 100644 pkg/execution/datasource_config.go delete mode 100644 pkg/execution/datasource_graphql_test.go delete mode 100644 pkg/execution/datasource_http_json_test.go delete mode 100644 pkg/execution/datasource_pipeline_test.go delete mode 100644 pkg/execution/execution.go delete mode 100644 pkg/execution/execution_test.go delete mode 100644 pkg/execution/fixtures/execution.golden delete mode 100644 pkg/execution/fixtures/handler_render_graphql_definitions.golden delete mode 100644 pkg/execution/fixtures/introspection_execution.golden delete mode 100644 pkg/execution/fixtures/render_graphql_definitions.golden delete mode 100644 pkg/execution/graphql_definitions/directives/graphql_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/http_json_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/http_polling_stream_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/mapping.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/mqtt_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/nats_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/pipeline_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/static_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/transformation.graphql delete mode 100644 pkg/execution/graphql_definitions/directives/wasm_datasource.graphql delete mode 100644 pkg/execution/graphql_definitions/enums/http_method.graphql delete mode 100644 pkg/execution/graphql_definitions/enums/mapping_mode.graphql delete mode 100644 pkg/execution/graphql_definitions/enums/parameter_source.graphql delete mode 100644 pkg/execution/graphql_definitions/enums/transformation_mode.graphql delete mode 100644 pkg/execution/graphql_definitions/inputs/header.graphql delete mode 100644 pkg/execution/graphql_definitions/inputs/parameter.graphql delete mode 100644 pkg/execution/graphql_definitions/inputs/statuscode_typename_mapping.graphql delete mode 100644 pkg/execution/handler.go delete mode 100644 pkg/execution/handler_test.go delete mode 100644 pkg/execution/jsonvaluetype.go delete mode 100644 pkg/execution/jsonvaluetype_string.go delete mode 100644 pkg/execution/jsonvaluetype_test.go delete mode 100644 pkg/execution/planning.go delete mode 100644 pkg/execution/planning_test.go delete mode 100755 pkg/execution/testdata/memory.wasm delete mode 100644 pkg/execution/testdata/simple_pipeline.json delete mode 100644 pkg/execution/transformation.go delete mode 100644 pkg/execution/transformation_test.go delete mode 100644 pkg/fastbuffer/fastbuffer.go delete mode 100644 pkg/fastbuffer/fastbuffer_test.go delete mode 100644 pkg/federation/fixtures/federated_schema.golden delete mode 100644 pkg/federation/schema.go delete mode 100644 pkg/federation/schema_test.go delete mode 100644 pkg/federation/sdlmerge/collect_entities.go delete mode 100644 pkg/federation/sdlmerge/collect_entities_test.go delete mode 100644 pkg/federation/sdlmerge/enum_type_extending.go delete mode 100644 pkg/federation/sdlmerge/enum_type_extending_test.go delete mode 100644 pkg/federation/sdlmerge/input_type_extending.go delete mode 100644 pkg/federation/sdlmerge/input_type_extending_test.go delete mode 100644 pkg/federation/sdlmerge/interface_type_extending.go delete mode 100644 pkg/federation/sdlmerge/interface_type_extending_test.go delete mode 100644 pkg/federation/sdlmerge/merge_duplicated_fields.go delete mode 100644 pkg/federation/sdlmerge/object_type_extending.go delete mode 100644 pkg/federation/sdlmerge/object_type_extending_test.go delete mode 100644 pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types.go delete mode 100644 pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types_test.go delete mode 100644 pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types.go delete mode 100644 pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types_test.go delete mode 100644 pkg/federation/sdlmerge/remove_empty_object_type_definition.go delete mode 100644 pkg/federation/sdlmerge/remove_empty_object_type_definition_test.go delete mode 100644 pkg/federation/sdlmerge/remove_field_definition_by_directive.go delete mode 100644 pkg/federation/sdlmerge/remove_field_definition_by_directive_test.go delete mode 100644 pkg/federation/sdlmerge/remove_field_definition_directive.go delete mode 100644 pkg/federation/sdlmerge/remove_field_definition_directive_test.go delete mode 100644 pkg/federation/sdlmerge/remove_interface_definition_directive.go delete mode 100644 pkg/federation/sdlmerge/remove_interface_definition_directive_test.go delete mode 100644 pkg/federation/sdlmerge/remove_object_type_definition_directive.go delete mode 100644 pkg/federation/sdlmerge/remove_object_type_definition_directive_test.go delete mode 100644 pkg/federation/sdlmerge/remove_type_extensions.go delete mode 100644 pkg/federation/sdlmerge/remove_type_extensions_test.go delete mode 100644 pkg/federation/sdlmerge/scalar_type_extending.go delete mode 100644 pkg/federation/sdlmerge/scalar_type_extending_test.go delete mode 100644 pkg/federation/sdlmerge/sdlmerge.go delete mode 100644 pkg/federation/sdlmerge/sdlmerge_test.go delete mode 100644 pkg/federation/sdlmerge/shared_types.go delete mode 100644 pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition-non-null.graphqls delete mode 100644 pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition.graphqls delete mode 100644 pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition-non-null.graphqls delete mode 100644 pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition.graphqls delete mode 100644 pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined-non-null.graphqls delete mode 100644 pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined.graphqls delete mode 100644 pkg/federation/sdlmerge/union_type_extending.go delete mode 100644 pkg/federation/sdlmerge/union_type_extending_test.go delete mode 100644 pkg/graphql/complexity.go delete mode 100644 pkg/graphql/config_factory_federation.go delete mode 100644 pkg/graphql/config_factory_federation_test.go delete mode 100644 pkg/graphql/config_factory_proxy.go delete mode 100644 pkg/graphql/config_factory_proxy_test.go delete mode 100644 pkg/graphql/engine_config_v2.go delete mode 100644 pkg/graphql/engine_config_v2_test.go delete mode 100644 pkg/graphql/errors.go delete mode 100644 pkg/graphql/errors_test.go delete mode 100644 pkg/graphql/execution_engine.go delete mode 100644 pkg/graphql/execution_engine_test.go delete mode 100644 pkg/graphql/execution_engine_v2.go delete mode 100644 pkg/graphql/execution_engine_v2_norace_test.go delete mode 100644 pkg/graphql/execution_engine_v2_test.go delete mode 100644 pkg/graphql/extractor.go delete mode 100644 pkg/graphql/extractor_test.go delete mode 100644 pkg/graphql/fixtures/introspection_response.golden delete mode 100644 pkg/graphql/lookup.go delete mode 100644 pkg/graphql/lookup_test.go delete mode 100644 pkg/graphql/normalization.go delete mode 100644 pkg/graphql/normalization_test.go delete mode 100644 pkg/graphql/request.go delete mode 100644 pkg/graphql/request_fields_validator.go delete mode 100644 pkg/graphql/request_fields_validator_test.go delete mode 100644 pkg/graphql/request_test.go delete mode 100644 pkg/graphql/response.go delete mode 100644 pkg/graphql/schema.go delete mode 100644 pkg/graphql/schema_test.go delete mode 100644 pkg/graphql/starwars_helpers_test.go delete mode 100644 pkg/graphql/subscription.go delete mode 100644 pkg/graphql/types.go delete mode 100644 pkg/graphql/validation.go delete mode 100644 pkg/graphql/validation_test.go delete mode 100644 pkg/graphqlerrors/location.go delete mode 100644 pkg/graphqljsonschema/jsonschema.go delete mode 100644 pkg/graphqljsonschema/jsonschema_test.go delete mode 100644 pkg/http/handler.go delete mode 100644 pkg/http/handler_test.go delete mode 100644 pkg/http/http.go delete mode 100644 pkg/http/ws.go delete mode 100644 pkg/http/ws_connection_init.json delete mode 100644 pkg/http/ws_start.json delete mode 100644 pkg/http/ws_test.go delete mode 100644 pkg/imports/fixtures/render_result.golden delete mode 100644 pkg/imports/fixtures/render_result_windows.golden delete mode 100644 pkg/imports/fixtures/scanner_regex.golden delete mode 100644 pkg/imports/fixtures/scanner_regex_render.golden delete mode 100644 pkg/imports/fixtures/scanner_regex_windows.golden delete mode 100644 pkg/imports/fixtures/scanner_result.golden delete mode 100644 pkg/imports/fixtures/scanner_result_windows.golden delete mode 100644 pkg/imports/graphql_file.go delete mode 100644 pkg/imports/graphql_file_test.go delete mode 100644 pkg/imports/imports.go delete mode 100644 pkg/imports/imports_test.go delete mode 100644 pkg/imports/testdata/cycle/a/a.graphql delete mode 100644 pkg/imports/testdata/cycle/b/b.graphql delete mode 100644 pkg/imports/testdata/deep/deeper/custom_types.graphql delete mode 100644 pkg/imports/testdata/deep/deeper/non_graphql.txt delete mode 100644 pkg/imports/testdata/import_cycle.graphql delete mode 100644 pkg/imports/testdata/nested/nested.graphql delete mode 100644 pkg/imports/testdata/nested2/nested2.graphql delete mode 100644 pkg/imports/testdata/regexonly/flat.graphql delete mode 100644 pkg/imports/testdata/regexonly/mutation.graphql delete mode 100644 pkg/imports/testdata/regexonly/query.graphql delete mode 100644 pkg/imports/testdata/scalars/json.graphql delete mode 100644 pkg/imports/testdata/schema.graphql delete mode 100644 pkg/imports/testdata/types/mutation.graphql delete mode 100644 pkg/imports/testdata/types/query.graphql delete mode 100644 pkg/internal/quotes/quotes.go delete mode 100644 pkg/internal/quotes/quotes_test.go delete mode 100644 pkg/internal/unsafebytes/unsafebytes.go delete mode 100644 pkg/internal/unsafebytes/unsafebytes_test.go delete mode 100644 pkg/internal/unsafeparser/unsafeparser.go delete mode 100644 pkg/internal/unsafeprinter/unsafeprinter.go delete mode 100644 pkg/introspection/converter.go delete mode 100644 pkg/introspection/converter_test.go delete mode 100644 pkg/introspection/fixtures/interfaces_implementing_interfaces.golden delete mode 100644 pkg/introspection/fixtures/starwars.golden delete mode 100644 pkg/introspection/fixtures/starwars_introspected.golden delete mode 100644 pkg/introspection/generator.go delete mode 100644 pkg/introspection/generator_test.go delete mode 100644 pkg/introspection/introspection.go delete mode 100644 pkg/introspection/introspection_enum.go delete mode 100644 pkg/introspection/introspection_test.go delete mode 100644 pkg/introspection/testdata/interfaces_implementing_interfaces.graphql delete mode 100755 pkg/introspection/testdata/out_swapi_introspection_response.json delete mode 100644 pkg/introspection/testdata/starwars.schema.graphql delete mode 100644 pkg/introspection/testdata/swapi_introspection_response.json delete mode 100644 pkg/lexer/fixtures/introspection_lexed.golden delete mode 100644 pkg/lexer/identkeyword/identkeyword.go delete mode 100644 pkg/lexer/identkeyword/identkeyword_string.go delete mode 100644 pkg/lexer/keyword/keyword.go delete mode 100644 pkg/lexer/keyword/keyword_string.go delete mode 100644 pkg/lexer/lexer.go delete mode 100644 pkg/lexer/lexer_test.go delete mode 100644 pkg/lexer/literal/literal.go delete mode 100644 pkg/lexer/position/position.go delete mode 100644 pkg/lexer/runes/runes.go delete mode 100644 pkg/lexer/token/token.go delete mode 100644 pkg/middleware/middleware.go delete mode 100644 pkg/middleware/operation_complexity/operation_complexity.go delete mode 100644 pkg/middleware/operation_complexity/operation_complexity_test.go delete mode 100644 pkg/operationreport/externalerror.go delete mode 100644 pkg/operationreport/externalerror_test.go delete mode 100644 pkg/operationreport/operationreport.go delete mode 100644 pkg/operationreport/operationreport_test.go delete mode 100644 pkg/playground/files/favicon.png delete mode 100644 pkg/playground/files/logo.png delete mode 100644 pkg/playground/files/playground.css delete mode 100644 pkg/playground/files/playground.html delete mode 100644 pkg/playground/files/playground.js delete mode 100644 pkg/playground/fixtures/handlers.golden delete mode 100644 pkg/playground/playground.go delete mode 100644 pkg/playground/playground_test.go delete mode 100644 pkg/pool/bytesbuffer.go delete mode 100644 pkg/pool/fastbuffer.go delete mode 100644 pkg/pool/hash64.go delete mode 100644 pkg/postprocess/datasourceinput.go delete mode 100644 pkg/postprocess/datasourceinput_test.go delete mode 100644 pkg/postprocess/defer.go delete mode 100644 pkg/postprocess/defer_test.go delete mode 100644 pkg/postprocess/postprocess.go delete mode 100644 pkg/postprocess/postprocess_test.go delete mode 100644 pkg/postprocess/stream.go delete mode 100644 pkg/postprocess/stream_test.go delete mode 100644 pkg/repair/repair.go delete mode 100644 pkg/repair/sdl.go delete mode 100644 pkg/repair/sdl_test.go delete mode 100644 pkg/starwars/starwars.go delete mode 100644 pkg/starwars/testdata/mutations/create_review.mutation delete mode 100644 pkg/starwars/testdata/queries/directives_include.query delete mode 100644 pkg/starwars/testdata/queries/directives_skip.query delete mode 100644 pkg/starwars/testdata/queries/droid_with_arg.query delete mode 100644 pkg/starwars/testdata/queries/droid_with_arg_and_var.query delete mode 100644 pkg/starwars/testdata/queries/fragments.query delete mode 100644 pkg/starwars/testdata/queries/hero_with_aliases.query delete mode 100644 pkg/starwars/testdata/queries/hero_with_operation_name.query delete mode 100644 pkg/starwars/testdata/queries/inline_fragments.query delete mode 100644 pkg/starwars/testdata/queries/interface_fragments_on_union.graphql delete mode 100644 pkg/starwars/testdata/queries/introspection.query delete mode 100644 pkg/starwars/testdata/queries/invalid.query delete mode 100644 pkg/starwars/testdata/queries/invalid_fragments.query delete mode 100644 pkg/starwars/testdata/queries/multi_queries.query delete mode 100644 pkg/starwars/testdata/queries/multi_queries_with_arguments.query delete mode 100644 pkg/starwars/testdata/queries/simple_hero.query delete mode 100644 pkg/starwars/testdata/queries/union.query delete mode 100644 pkg/starwars/testdata/star_wars.graphql delete mode 100644 pkg/starwars/testdata/subscriptions/remaining_jedis.subscription delete mode 100644 pkg/subscription/constants.go delete mode 100644 pkg/subscription/context.go delete mode 100644 pkg/subscription/context_test.go delete mode 100644 pkg/subscription/engine.go delete mode 100644 pkg/subscription/engine_mock_test.go delete mode 100644 pkg/subscription/engine_test.go delete mode 100644 pkg/subscription/executor.go delete mode 100644 pkg/subscription/executor_mock_test.go delete mode 100644 pkg/subscription/executor_v1.go delete mode 100644 pkg/subscription/executor_v2.go delete mode 100644 pkg/subscription/handler.go delete mode 100644 pkg/subscription/handler_mock_test.go delete mode 100644 pkg/subscription/handler_test.go delete mode 100644 pkg/subscription/init.go delete mode 100644 pkg/subscription/legacy_handler.go delete mode 100644 pkg/subscription/legacy_handler_test.go delete mode 100644 pkg/subscription/mock_client_test.go delete mode 100644 pkg/subscription/time_out.go delete mode 100644 pkg/subscription/time_out_test.go delete mode 100644 pkg/subscription/transport_client.go delete mode 100644 pkg/subscription/transport_client_mock_test.go delete mode 100644 pkg/subscription/websocket/client.go delete mode 100644 pkg/subscription/websocket/client_test.go delete mode 100644 pkg/subscription/websocket/engine_mock_test.go delete mode 100644 pkg/subscription/websocket/handler.go delete mode 100644 pkg/subscription/websocket/handler_test.go delete mode 100644 pkg/subscription/websocket/init.go delete mode 100644 pkg/subscription/websocket/protocol_graphql_transport_ws.go delete mode 100644 pkg/subscription/websocket/protocol_graphql_transport_ws_test.go delete mode 100644 pkg/subscription/websocket/protocol_graphql_ws.go delete mode 100644 pkg/subscription/websocket/protocol_graphql_ws_test.go delete mode 100644 pkg/testing/federationtesting/accounts/gqlgen.yml delete mode 100644 pkg/testing/federationtesting/accounts/graph/entity.resolvers.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/generated/federation.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/generated/generated.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/handler.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/histories.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/model/models_gen.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/resolver.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/schema.graphqls delete mode 100644 pkg/testing/federationtesting/accounts/graph/schema.resolvers.go delete mode 100644 pkg/testing/federationtesting/accounts/graph/wallets.go delete mode 100644 pkg/testing/federationtesting/accounts/handler.go delete mode 100644 pkg/testing/federationtesting/federation_integration_test.go delete mode 100644 pkg/testing/federationtesting/gateway/datasource_poller.go delete mode 100644 pkg/testing/federationtesting/gateway/gateway.go delete mode 100644 pkg/testing/federationtesting/gateway/http/handler.go delete mode 100644 pkg/testing/federationtesting/gateway/http/http.go delete mode 100644 pkg/testing/federationtesting/gateway/http/ws.go delete mode 100644 pkg/testing/federationtesting/gateway/main.go delete mode 100644 pkg/testing/federationtesting/graphql_client_test.go delete mode 100644 pkg/testing/federationtesting/products/gqlgen.yml delete mode 100644 pkg/testing/federationtesting/products/graph/entity.resolvers.go delete mode 100644 pkg/testing/federationtesting/products/graph/generated/federation.go delete mode 100644 pkg/testing/federationtesting/products/graph/generated/generated.go delete mode 100644 pkg/testing/federationtesting/products/graph/handler.go delete mode 100644 pkg/testing/federationtesting/products/graph/model/models_gen.go delete mode 100644 pkg/testing/federationtesting/products/graph/products.go delete mode 100644 pkg/testing/federationtesting/products/graph/resolver.go delete mode 100644 pkg/testing/federationtesting/products/graph/schema.graphqls delete mode 100644 pkg/testing/federationtesting/products/graph/schema.resolvers.go delete mode 100644 pkg/testing/federationtesting/products/graph/variables.go delete mode 100644 pkg/testing/federationtesting/products/handler.go delete mode 100644 pkg/testing/federationtesting/reviews/gqlgen.yml delete mode 100644 pkg/testing/federationtesting/reviews/graph/attachments.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/entity.resolvers.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/generated/federation.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/generated/generated.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/handler.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/model/models.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/model/models_gen.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/resolver.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/reviews.go delete mode 100644 pkg/testing/federationtesting/reviews/graph/schema.graphqls delete mode 100644 pkg/testing/federationtesting/reviews/graph/schema.resolvers.go delete mode 100644 pkg/testing/federationtesting/reviews/handler.go delete mode 100644 pkg/testing/federationtesting/testdata/mutations/mutation_with_variables.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/complex_nesting.graphql delete mode 100644 pkg/testing/federationtesting/testdata/queries/interface.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/interface_fragment_on_object.graphql delete mode 100644 pkg/testing/federationtesting/testdata/queries/interface_fragments_on_union.graphql delete mode 100644 pkg/testing/federationtesting/testdata/queries/merged_field.graphql delete mode 100644 pkg/testing/federationtesting/testdata/queries/multiple_queries.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/multiple_queries_with_nested_fragments.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/multiple_queries_with_union_return.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/multiple_upstream.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/object_fragment_on_interface.graphql delete mode 100644 pkg/testing/federationtesting/testdata/queries/single_upstream.query delete mode 100644 pkg/testing/federationtesting/testdata/queries/union.query delete mode 100644 pkg/testing/federationtesting/testdata/subscriptions/subscription.query delete mode 100644 pkg/testing/federationtesting/util.go delete mode 100644 pkg/testing/flags/flags.go delete mode 100644 pkg/testing/flags/flags_win.go delete mode 100644 pkg/testing/goldie/goldie.go delete mode 100644 pkg/testing/goldie/goldie_posix.go delete mode 100644 pkg/testing/goldie/goldie_win.go delete mode 100644 pkg/testing/subscriptiontesting/.gqlgen.yml delete mode 100644 pkg/testing/subscriptiontesting/chat_test.go delete mode 100644 pkg/testing/subscriptiontesting/generated.go delete mode 100644 pkg/testing/subscriptiontesting/handler.go delete mode 100644 pkg/testing/subscriptiontesting/models_gen.go delete mode 100644 pkg/testing/subscriptiontesting/resolvers.go delete mode 100644 pkg/testing/subscriptiontesting/schema.graphql delete mode 100644 pkg/testing/subscriptiontesting/util.go diff --git a/Makefile b/Makefile deleted file mode 100644 index 23fb63a45..000000000 --- a/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -.PHONY: test -test: - go test ./... - -.PHONY: test-quick -test-quick: - go test -count=1 ./... - -.PHONY: test-race -test-race: - go test -race ./... - -# updateTestFixtures will update all! golden fixtures -.PHONY: updateTestFixtures -updateTestFixtures: - go test ./pkg/... -update - -.PHONY: format -format: - go fmt ./... - -.PHONY: prepare-merge -prepare-merge: format test - -.PHONY: ci -ci: test - -.PHONY: ci-quick -ci-full: test-quick - -.PHONY: generate -generate: $(GOPATH)/bin/go-enum $(GOPATH)/bin/mockgen $(GOPATH)/bin/stringer - go generate ./... - go mod tidy - -$(GOPATH)/bin/go-enum: - go get -u github.com/abice/go-enum - go install github.com/abice/go-enum - -$(GOPATH)/bin/mockgen: - go get -u github.com/golang/mock/gomock - go install github.com/golang/mock/mockgen - -$(GOPATH)/bin/stringer: - go get -u -a golang.org/x/tools/cmd/stringer - go install golang.org/x/tools/cmd/stringer diff --git a/README.md b/README.md index 7a52ec2f3..422f3eb7e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Check out the [currently open positions](https://wundergraph.com/jobs#open-posit ## The State of GraphQL Federation 2024 -Get insights from industry experts and Federation practicioners across all industries and learn how companies are using GraphQL Federation. +Get insights from industry experts and Federation practitioners across all industries and learn how companies are using GraphQL Federation. Head over to the [State of GraphQL Federation 2024](https://wundergraph.com/state-of-graphql-federation/2024) page and download the full **48 page PDF report** for free! ## From the WunderGraph Blog @@ -63,22 +63,20 @@ This repository contains multiple packages joined via [workspace](https://github | [graphql-go-tools v2](https://github.com/wundergraph/graphql-go-tools/blob/master/v2/go.mod) | GraphQL engine implementation consisting of lexer, parser, ast, ast validation, ast normalization, datasources, query planner and resolver. Supports GraphQL Federation. Has built-in support for batching federation entity calls | - | actual version, active development | | [execution](https://github.com/wundergraph/graphql-go-tools/blob/master/execution/go.mod) | Execution helpers for the request handling and engine configuration builder | depends on [graphql-go-tools v2](https://github.com/wundergraph/graphql-go-tools/blob/master/v2/go.mod) and [composition](https://github.com/wundergraph/cosmo/blob/main/composition-go/go.mod) | actual version | | [examples/federation](https://github.com/wundergraph/graphql-go-tools/blob/master/examples/federation/go.mod) | Example implementation of graphql federation gateway. This example is not production ready. For production ready solution please consider using [cosmo router](https://github.com/wundergraph/cosmo/tree/main) | depends on [execution](https://github.com/wundergraph/graphql-go-tools/blob/master/execution/go.mod) package | actual federation gateway example | -| [graphql-go-tools v1](https://github.com/wundergraph/graphql-go-tools/blob/master/go.mod) | Legacy GraphQL engine implementation. This version 1 package is in maintenance mode and accepts only pull requests with critical bug fixes. All new features will be implemented in the version 2 package only. | - | deprecated, maintenance mode | +| [graphql-go-tools v1](https://github.com/wundergraph/graphql-go-tools/blob/v1.67.4/go.mod) | Deprecated and retracted GraphQL engine implementation. Not supported nor maintained. It was removed from the repo in v1.67.5. | - | deprecated | ## Notes This library is used in production at [WunderGraph](https://wundergraph.com/). -We've recently introduced a v2 module that is not completely backwards compatible with v1, hence the major version bump. -The v2 module contains big rewrites in the engine package, mainly to better support GraphQL Federation. -Please consider the v1 module as deprecated and move to v2 as soon as possible. +We support and actively improve only the v2 module. We have customers who pay us to maintain this library and steer the direction of the project. [Contact us](https://wundergraph.com/contact/sales) if you're looking for commercial support, features or consulting. ## Performance -The architecture of this library is designed for performance, high-throughput and low garbage collection overhead. +The architecture of this library is designed for performance, high throughput and low garbage collection overhead. The following benchmark measures the "overhead" of loading and resolving a GraphQL response from four static in-memory Subgraphs at 0,007459 ms/op. In more complete end-to-end benchmarks, we've measured up to 8x more requests per second and 8x lower p99 latency compared to Apollo Router, which is written in Rust. @@ -94,7 +92,7 @@ Benchmark_NestedBatchingWithoutChecks-10 473186 7134 ns/op ## Tutorial If you're here to learn how to use this library to build your own custom GraphQL Router or API Gateway, -here's a speed run tutorial for you, based on how we use this library in Cosmo Router. +here's a speed-run tutorial, based on how we use this library in Cosmo Router. ```go package main @@ -783,7 +781,7 @@ Following, here's a list of all the important packages in this library and what - Fixed various bugs in the parser & visitor & printer - Refactored and enhanced the astimport package - Current maintainer of the plan package -- [Patric Vormstein][patric-vormstein-github] (Active Maintainer) +- [Patric Vormstein][patric-vormstein-github] (Inactive) - Fixed lexer on windows - Author of the graphql package to simplify the usage of the library - Refactored the http package to simplify usage with http servers diff --git a/go.mod b/go.mod index 87af27c36..47aa44c3b 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,12 @@ -// Deprecated: use github.com/wundergraph/graphql-go-tools/v2 instead. module github.com/wundergraph/graphql-go-tools go 1.25 // Use github.com/wundergraph/graphql-go-tools/v2 instead. retract ( - v0.0.1 - v0.13.2 [v1.0.0, v1.67.4] + v0.13.2 + v0.0.1 ) require ( diff --git a/go.work b/go.work index bbf328927..4da85be03 100644 --- a/go.work +++ b/go.work @@ -3,15 +3,8 @@ go 1.25 toolchain go1.25.1 use ( - // v1 - . - // examples examples/federation - - // execution execution - - // v2 v2 ) diff --git a/go.work.sum b/go.work.sum index 5410886f1..f13214003 100644 --- a/go.work.sum +++ b/go.work.sum @@ -136,6 +136,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= +github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2 h1:rcanfLhLDA8nozr/K289V1zcntHr3V+SHlXwzz1ZI2g= github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= @@ -162,14 +164,24 @@ github.com/mark3labs/mcp-go v0.36.0/go.mod h1:T7tUa2jO6MavG+3P25Oy/jR7iCeJPHImCZ github.com/matryer/moq v0.2.7 h1:RtpiPUM8L7ZSCbSwK+QcZH/E9tgqAkFjKQxsRs25b4w= github.com/matryer/moq v0.5.2 h1:b2bsanSaO6IdraaIvPBzHnqcrkkQmk1/310HdT2nNQs= github.com/matryer/moq v0.5.2/go.mod h1:W/k5PLfou4f+bzke9VPXTbfJljxoeR1tLHigsmbshmU= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.74 h1:fTo/XlPBTSpo3BAMshlwKL5RspXRv9us5UeHEGYCFe0= github.com/minio/minio-go/v7 v7.0.74/go.mod h1:qydcVzV8Hqtj1VtEocfxbmVFa2siu6HGa+LDEPogjD8= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk= +github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= +github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= @@ -218,6 +230,7 @@ github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg= github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= @@ -282,6 +295,8 @@ golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/image v0.6.0 h1:bR8b5okrPI3g/gyZakLZHeWxAR8Dn5CyxXv1hLH5g/4= golang.org/x/image v0.6.0/go.mod h1:MXLdDR43H7cDJq5GEGXEVeeNhPgi+YYEQ2pC1byI1x0= golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= @@ -308,6 +323,7 @@ golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/ast/ast.go b/pkg/ast/ast.go deleted file mode 100644 index 61fce9c7d..000000000 --- a/pkg/ast/ast.go +++ /dev/null @@ -1,260 +0,0 @@ -//go:generate stringer -type=OperationType,ValueKind,TypeKind,SelectionKind,NodeKind,PathKind -output ast_string.go - -// Package ast defines the GraphQL AST and offers helper methods to interact with the AST, mostly to get the necessary information from the ast. -// -// The document struct is designed in a way to enable performant parsing while keeping the ast easy to use with helper methods. -package ast - -const InvalidRef = -1 - -type Document struct { - Input Input - RootNodes []Node - SchemaDefinitions []SchemaDefinition - SchemaExtensions []SchemaExtension - RootOperationTypeDefinitions []RootOperationTypeDefinition - Directives []Directive - Arguments []Argument - ObjectTypeDefinitions []ObjectTypeDefinition - ObjectTypeExtensions []ObjectTypeExtension - FieldDefinitions []FieldDefinition - Types []Type - InputValueDefinitions []InputValueDefinition - InputObjectTypeDefinitions []InputObjectTypeDefinition - InputObjectTypeExtensions []InputObjectTypeExtension - ScalarTypeDefinitions []ScalarTypeDefinition - ScalarTypeExtensions []ScalarTypeExtension - InterfaceTypeDefinitions []InterfaceTypeDefinition - InterfaceTypeExtensions []InterfaceTypeExtension - UnionTypeDefinitions []UnionTypeDefinition - UnionTypeExtensions []UnionTypeExtension - EnumTypeDefinitions []EnumTypeDefinition - EnumTypeExtensions []EnumTypeExtension - EnumValueDefinitions []EnumValueDefinition - DirectiveDefinitions []DirectiveDefinition - Values []Value - ListValues []ListValue - VariableValues []VariableValue - StringValues []StringValue - IntValues []IntValue - FloatValues []FloatValue - EnumValues []EnumValue - ObjectFields []ObjectField - ObjectValues []ObjectValue - Selections []Selection - SelectionSets []SelectionSet - Fields []Field - InlineFragments []InlineFragment - FragmentSpreads []FragmentSpread - OperationDefinitions []OperationDefinition - VariableDefinitions []VariableDefinition - FragmentDefinitions []FragmentDefinition - BooleanValues [2]BooleanValue - Refs [][8]int - RefIndex int - Index Index -} - -func NewDocument() *Document { - return &Document{ - RootNodes: make([]Node, 0, 48), - RootOperationTypeDefinitions: make([]RootOperationTypeDefinition, 0, 3), - SchemaDefinitions: make([]SchemaDefinition, 0, 2), - SchemaExtensions: make([]SchemaExtension, 0, 2), - Directives: make([]Directive, 0, 16), - Arguments: make([]Argument, 0, 48), - ObjectTypeDefinitions: make([]ObjectTypeDefinition, 0, 48), - ObjectTypeExtensions: make([]ObjectTypeExtension, 0, 4), - Types: make([]Type, 0, 48), - FieldDefinitions: make([]FieldDefinition, 0, 128), - InputValueDefinitions: make([]InputValueDefinition, 0, 128), - InputObjectTypeDefinitions: make([]InputObjectTypeDefinition, 0, 16), - InputObjectTypeExtensions: make([]InputObjectTypeExtension, 0, 4), - ScalarTypeDefinitions: make([]ScalarTypeDefinition, 0, 16), - ScalarTypeExtensions: make([]ScalarTypeExtension, 0, 4), - InterfaceTypeDefinitions: make([]InterfaceTypeDefinition, 0, 16), - InterfaceTypeExtensions: make([]InterfaceTypeExtension, 0, 4), - UnionTypeDefinitions: make([]UnionTypeDefinition, 0, 8), - UnionTypeExtensions: make([]UnionTypeExtension, 0, 4), - EnumTypeDefinitions: make([]EnumTypeDefinition, 0, 8), - EnumTypeExtensions: make([]EnumTypeExtension, 0, 4), - EnumValueDefinitions: make([]EnumValueDefinition, 0, 48), - DirectiveDefinitions: make([]DirectiveDefinition, 0, 8), - VariableValues: make([]VariableValue, 0, 8), - StringValues: make([]StringValue, 0, 24), - EnumValues: make([]EnumValue, 0, 24), - IntValues: make([]IntValue, 0, 128), - FloatValues: make([]FloatValue, 0, 128), - Values: make([]Value, 0, 64), - ListValues: make([]ListValue, 0, 4), - ObjectFields: make([]ObjectField, 0, 64), - ObjectValues: make([]ObjectValue, 0, 16), - Selections: make([]Selection, 0, 128), - SelectionSets: make([]SelectionSet, 0, 48), - Fields: make([]Field, 0, 128), - InlineFragments: make([]InlineFragment, 0, 16), - FragmentSpreads: make([]FragmentSpread, 0, 16), - OperationDefinitions: make([]OperationDefinition, 0, 8), - VariableDefinitions: make([]VariableDefinition, 0, 8), - FragmentDefinitions: make([]FragmentDefinition, 0, 8), - BooleanValues: [2]BooleanValue{false, true}, - Refs: make([][8]int, 48), - RefIndex: -1, - Index: Index{ - nodes: make(map[uint64][]Node, 48), - }, - } -} - -func (d *Document) Reset() { - d.RootNodes = d.RootNodes[:0] - d.SchemaDefinitions = d.SchemaDefinitions[:0] - d.SchemaExtensions = d.SchemaExtensions[:0] - d.RootOperationTypeDefinitions = d.RootOperationTypeDefinitions[:0] - d.Directives = d.Directives[:0] - d.Arguments = d.Arguments[:0] - d.ObjectTypeDefinitions = d.ObjectTypeDefinitions[:0] - d.ObjectTypeExtensions = d.ObjectTypeExtensions[:0] - d.Types = d.Types[:0] - d.FieldDefinitions = d.FieldDefinitions[:0] - d.InputValueDefinitions = d.InputValueDefinitions[:0] - d.InputObjectTypeDefinitions = d.InputObjectTypeDefinitions[:0] - d.InputObjectTypeExtensions = d.InputObjectTypeExtensions[:0] - d.ScalarTypeDefinitions = d.ScalarTypeDefinitions[:0] - d.ScalarTypeExtensions = d.ScalarTypeExtensions[:0] - d.InterfaceTypeDefinitions = d.InterfaceTypeDefinitions[:0] - d.InterfaceTypeExtensions = d.InterfaceTypeExtensions[:0] - d.UnionTypeDefinitions = d.UnionTypeDefinitions[:0] - d.UnionTypeExtensions = d.UnionTypeExtensions[:0] - d.EnumTypeDefinitions = d.EnumTypeDefinitions[:0] - d.EnumTypeExtensions = d.EnumTypeExtensions[:0] - d.EnumValueDefinitions = d.EnumValueDefinitions[:0] - d.DirectiveDefinitions = d.DirectiveDefinitions[:0] - d.VariableValues = d.VariableValues[:0] - d.StringValues = d.StringValues[:0] - d.EnumValues = d.EnumValues[:0] - d.IntValues = d.IntValues[:0] - d.FloatValues = d.FloatValues[:0] - d.Values = d.Values[:0] - d.ListValues = d.ListValues[:0] - d.ObjectFields = d.ObjectFields[:0] - d.ObjectValues = d.ObjectValues[:0] - d.Selections = d.Selections[:0] - d.SelectionSets = d.SelectionSets[:0] - d.Fields = d.Fields[:0] - d.InlineFragments = d.InlineFragments[:0] - d.FragmentSpreads = d.FragmentSpreads[:0] - d.OperationDefinitions = d.OperationDefinitions[:0] - d.VariableDefinitions = d.VariableDefinitions[:0] - d.FragmentDefinitions = d.FragmentDefinitions[:0] - - d.RefIndex = -1 - d.Index.Reset() - d.Input.Reset() -} - -func (d *Document) NextRefIndex() int { - d.RefIndex++ - if d.RefIndex == len(d.Refs) { - d.Refs = append(d.Refs, [8]int{}) - } - return d.RefIndex -} - -func (d *Document) NewEmptyRefs() []int { - return d.Refs[d.NextRefIndex()][:0] -} - -func (d *Document) copyByteSliceReference(ref ByteSliceReference) ByteSliceReference { - if ref.Length() == 0 { - return ByteSliceReference{} - } - src := d.Input.ByteSlice(ref) - dst := make([]byte, len(src)) - copy(dst, src) - return d.Input.AppendInputBytes(dst) -} - -func (d *Document) AddRootNode(node Node) { - d.RootNodes = append(d.RootNodes, node) - d.Index.AddNodeStr(d.NodeNameUnsafeString(node), node) -} - -func (d *Document) ImportRootNode(ref int, kind NodeKind) { - d.AddRootNode(Node{ - Kind: kind, - Ref: ref, - }) -} - -func (d *Document) DeleteRootNodes(nodes []Node) { - for i := range nodes { - d.DeleteRootNode(nodes[i]) - } -} - -func (d *Document) DeleteRootNode(node Node) { - for i := range d.RootNodes { - if d.RootNodes[i].Kind == node.Kind && d.RootNodes[i].Ref == node.Ref { - d.RootNodes = append(d.RootNodes[:i], d.RootNodes[i+1:]...) - return - } - } -} - -func (d *Document) RemoveMergedTypeExtensions() { - for _, node := range d.Index.MergedTypeExtensions { - d.RemoveRootNode(node) - } -} - -func (d *Document) RemoveRootNode(node Node) { - for i := range d.RootNodes { - if d.RootNodes[i] == node { - d.RootNodes = append(d.RootNodes[:i], d.RootNodes[i+1:]...) - return - } - } -} - -func (d *Document) NodeByName(name ByteSlice) (Node, bool) { - return d.Index.FirstNodeByNameBytes(name) -} - -func (d *Document) NodeByNameStr(name string) (Node, bool) { - return d.Index.FirstNodeByNameStr(name) -} - -func (d *Document) TypeDefinitionContainsImplementsInterface(typeName, interfaceName ByteSlice) bool { - typeDefinition, exists := d.Index.FirstNodeByNameBytes(typeName) - if !exists { - return false - } - if typeDefinition.Kind != NodeKindObjectTypeDefinition { - return false - } - return d.ObjectTypeDefinitionImplementsInterface(typeDefinition.Ref, interfaceName) -} - -func FilterIntSliceByWhitelist(intSlice []int, whitelist []int) []int { - if len(intSlice) == 0 || len(whitelist) == 0 { - return []int{} - } - n := 0 - for i := 0; i < len(intSlice); i++ { - if isWhitelisted(intSlice[i], whitelist) { - intSlice[n] = intSlice[i] - n++ - } - } - return intSlice[:n] -} - -func isWhitelisted(value int, whitelisted []int) bool { - for i := 0; i < len(whitelisted); i++ { - if whitelisted[i] == value { - return true - } - } - return false -} diff --git a/pkg/ast/ast_argument.go b/pkg/ast/ast_argument.go deleted file mode 100644 index 828993c31..000000000 --- a/pkg/ast/ast_argument.go +++ /dev/null @@ -1,196 +0,0 @@ -package ast - -import ( - "bytes" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type ArgumentList struct { - LPAREN position.Position - Refs []int // Argument - RPAREN position.Position -} - -type Argument struct { - Name ByteSliceReference // e.g. foo - Colon position.Position // : - Value Value // e.g. 100 or "Bar" - Position position.Position - PrintBeforeValue []byte - PrintAfterValue []byte -} - -func (d *Document) CopyArgument(ref int) int { - return d.AddArgument(Argument{ - Name: d.copyByteSliceReference(d.Arguments[ref].Name), - Value: Value{ - Kind: d.Arguments[ref].Value.Kind, - Ref: d.copyValueRef(d.Arguments[ref].Value.Kind, d.Arguments[ref].Value.Ref), - }, - }) -} - -func (d *Document) CopyArgumentList(list ArgumentList) ArgumentList { - refs := d.NewEmptyRefs() - for _, r := range list.Refs { - refs = append(refs, d.CopyArgument(r)) - } - return ArgumentList{Refs: refs} -} - -func (d *Document) PrintArgument(ref int, w io.Writer) error { - _, err := w.Write(d.Input.ByteSlice(d.Arguments[ref].Name)) - if err != nil { - return err - } - _, err = w.Write(literal.COLON) - if err != nil { - return err - } - _, err = w.Write(literal.SPACE) - if err != nil { - return err - } - if d.Arguments[ref].PrintBeforeValue != nil { - _, err = w.Write(d.Arguments[ref].PrintBeforeValue) - if err != nil { - return err - } - } - err = d.PrintValue(d.Arguments[ref].Value, w) - if err != nil { - return err - } - if d.Arguments[ref].PrintAfterValue != nil { - _, err = w.Write(d.Arguments[ref].PrintAfterValue) - if err != nil { - return err - } - } - return nil -} - -func (d *Document) PrintArguments(refs []int, w io.Writer) (err error) { - _, err = w.Write(literal.LPAREN) - if err != nil { - return - } - for i, j := range refs { - err = d.PrintArgument(j, w) - if err != nil { - return - } - if i != len(refs)-1 { - _, err = w.Write(literal.COMMA) - if err != nil { - return - } - _, err = w.Write(literal.SPACE) - if err != nil { - return - } - } - } - _, err = w.Write(literal.RPAREN) - return -} - -func (d *Document) ArgumentNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.Arguments[ref].Name) -} - -func (d *Document) ArgumentNameString(ref int) string { - return unsafebytes.BytesToString(d.ArgumentNameBytes(ref)) -} - -func (d *Document) ArgumentValue(ref int) Value { - return d.Arguments[ref].Value -} - -func (d *Document) ArgumentsAreEqual(left, right int) bool { - return bytes.Equal(d.ArgumentNameBytes(left), d.ArgumentNameBytes(right)) && - d.ValuesAreEqual(d.ArgumentValue(left), d.ArgumentValue(right)) -} - -func (d *Document) ArgumentSetsAreEquals(left, right []int) bool { - if len(left) != len(right) { - return false - } - for i := 0; i < len(left); i++ { - leftArgument, rightArgument := left[i], right[i] - if !d.ArgumentsAreEqual(leftArgument, rightArgument) { - return false - } - } - return true -} - -func (d *Document) ArgumentsBefore(ancestor Node, argument int) []int { - switch ancestor.Kind { - case NodeKindField: - for i, j := range d.Fields[ancestor.Ref].Arguments.Refs { - if argument == j { - return d.Fields[ancestor.Ref].Arguments.Refs[:i] - } - } - case NodeKindDirective: - for i, j := range d.Directives[ancestor.Ref].Arguments.Refs { - if argument == j { - return d.Directives[ancestor.Ref].Arguments.Refs[:i] - } - } - } - return nil -} - -func (d *Document) ArgumentsAfter(ancestor Node, argument int) []int { - switch ancestor.Kind { - case NodeKindField: - for i, j := range d.Fields[ancestor.Ref].Arguments.Refs { - if argument == j { - return d.Fields[ancestor.Ref].Arguments.Refs[i+1:] - } - } - case NodeKindDirective: - for i, j := range d.Directives[ancestor.Ref].Arguments.Refs { - if argument == j { - return d.Directives[ancestor.Ref].Arguments.Refs[i+1:] - } - } - } - return nil -} - -func (d *Document) AddArgument(argument Argument) (ref int) { - d.Arguments = append(d.Arguments, argument) - return len(d.Arguments) - 1 -} - -func (d *Document) ImportArgument(name string, value Value) (ref int) { - arg := Argument{ - Name: d.Input.AppendInputString(name), - Value: value, - } - - return d.AddArgument(arg) -} - -func (d *Document) ImportVariableValueArgument(argName, variableName ByteSlice) (variableValueRef, argRef int) { - variableValueRef = d.ImportVariableValue(variableName) - - arg := Argument{ - Name: d.Input.AppendInputBytes(argName), - Value: Value{ - Kind: ValueKindVariable, - Ref: variableValueRef, - }, - } - - argRef = d.AddArgument(arg) - - return -} diff --git a/pkg/ast/ast_description.go b/pkg/ast/ast_description.go deleted file mode 100644 index 4c039ac1c..000000000 --- a/pkg/ast/ast_description.go +++ /dev/null @@ -1,93 +0,0 @@ -package ast - -import ( - "io" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/runes" -) - -type Description struct { - IsDefined bool - IsBlockString bool // true if -> """content""" ; else "content" - Content ByteSliceReference // literal - Position position.Position -} - -// nolint -func (d *Document) PrintDescription(description Description, indent []byte, depth int, writer io.Writer) (err error) { - for i := 0; i < depth; i++ { - _, err = writer.Write(indent) - } - if description.IsBlockString { - _, err = writer.Write(literal.QUOTE) - _, err = writer.Write(literal.QUOTE) - _, err = writer.Write(literal.QUOTE) - _, err = writer.Write(literal.LINETERMINATOR) - for i := 0; i < depth; i++ { - _, err = writer.Write(indent) - } - } else { - _, err = writer.Write(literal.QUOTE) - } - - content := d.Input.ByteSlice(description.Content) - skipWhitespace := false - skippedWhitespace := 0.0 - depthToSkip := float64(depth) - for i := range content { - - if skipWhitespace && skippedWhitespace < depthToSkip { - switch content[i] { - case runes.TAB: - skippedWhitespace += 1 - continue - case runes.SPACE: - continue - } - } - - switch content[i] { - case runes.LINETERMINATOR: - skipWhitespace = true - default: - if skipWhitespace { - for j := 0; j < depth; j++ { - _, err = writer.Write(indent) - } - - skipWhitespace = false - skippedWhitespace = 0.0 - } - } - _, err = writer.Write(content[i : i+1]) - } - if description.IsBlockString { - _, err = writer.Write(literal.LINETERMINATOR) - for i := 0; i < depth; i++ { - _, err = writer.Write(indent) - } - _, err = writer.Write(literal.QUOTE) - _, err = writer.Write(literal.QUOTE) - _, err = writer.Write(literal.QUOTE) - } else { - _, err = writer.Write(literal.QUOTE) - } - return nil -} - -func (d *Document) ImportDescription(desc string) (description Description) { - if desc == "" { - return - } - - isBlockString := strings.Contains(desc, "\n") || strings.Contains(desc, `"`) - - return Description{ - IsDefined: true, - IsBlockString: isBlockString, - Content: d.Input.AppendInputString(desc), - } -} diff --git a/pkg/ast/ast_directive.go b/pkg/ast/ast_directive.go deleted file mode 100644 index c8b3dbf86..000000000 --- a/pkg/ast/ast_directive.go +++ /dev/null @@ -1,214 +0,0 @@ -package ast - -import ( - "bytes" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type DirectiveList struct { - Refs []int -} - -type Directive struct { - At position.Position // @ - Name ByteSliceReference // e.g. include - HasArguments bool - Arguments ArgumentList // e.g. (if: true) -} - -func (l *DirectiveList) HasDirectiveByName(document *Document, name string) bool { - for i := range l.Refs { - if document.DirectiveNameString(l.Refs[i]) == name { - return true - } - } - return false -} - -func (l *DirectiveList) RemoveDirectiveByName(document *Document, name string) { - for i := range l.Refs { - if document.DirectiveNameString(l.Refs[i]) == name { - if i < len(l.Refs)-1 { - l.Refs = append(l.Refs[:i], l.Refs[i+1:]...) - } else { - l.Refs = l.Refs[:i] - } - return - } - } -} - -func (d *Document) CopyDirective(ref int) int { - var arguments ArgumentList - if d.Directives[ref].HasArguments { - arguments = d.CopyArgumentList(d.Directives[ref].Arguments) - } - return d.AddDirective(Directive{ - Name: d.copyByteSliceReference(d.Directives[ref].Name), - HasArguments: d.Directives[ref].HasArguments, - Arguments: arguments, - }) -} - -func (d *Document) CopyDirectiveList(list DirectiveList) DirectiveList { - refs := d.NewEmptyRefs() - for _, r := range list.Refs { - refs = append(refs, d.CopyDirective(r)) - } - return DirectiveList{Refs: refs} -} - -func (d *Document) PrintDirective(ref int, w io.Writer) error { - _, err := w.Write(literal.AT) - if err != nil { - return err - } - _, err = w.Write(d.Input.ByteSlice(d.Directives[ref].Name)) - if err != nil { - return err - } - if d.Directives[ref].HasArguments { - err = d.PrintArguments(d.Directives[ref].Arguments.Refs, w) - } - return err -} - -func (d *Document) DirectiveName(ref int) ByteSliceReference { - return d.Directives[ref].Name -} - -func (d *Document) DirectiveNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.Directives[ref].Name) -} - -func (d *Document) DirectiveNameString(ref int) string { - return d.Input.ByteSliceString(d.Directives[ref].Name) -} - -func (d *Document) DirectiveIsFirst(directive int, ancestor Node) bool { - directives := d.NodeDirectives(ancestor) - return len(directives) != 0 && directives[0] == directive -} - -func (d *Document) DirectiveIsLast(directive int, ancestor Node) bool { - directives := d.NodeDirectives(ancestor) - return len(directives) != 0 && directives[len(directives)-1] == directive -} - -func (d *Document) DirectiveArgumentSet(ref int) []int { - return d.Directives[ref].Arguments.Refs -} - -func (d *Document) DirectiveArgumentValueByName(ref int, name ByteSlice) (Value, bool) { - for i := 0; i < len(d.Directives[ref].Arguments.Refs); i++ { - arg := d.Directives[ref].Arguments.Refs[i] - if bytes.Equal(d.ArgumentNameBytes(arg), name) { - return d.ArgumentValue(arg), true - } - } - return Value{}, false -} - -func (d *Document) DirectivesAreEqual(left, right int) bool { - return d.Input.ByteSliceReferenceContentEquals(d.DirectiveName(left), d.DirectiveName(right)) && - d.ArgumentSetsAreEquals(d.DirectiveArgumentSet(left), d.DirectiveArgumentSet(right)) -} - -func (d *Document) DirectiveSetsAreEqual(left, right []int) bool { - if len(left) != len(right) { - return false - } - for i := 0; i < len(left); i++ { - leftDirective, rightDirective := left[i], right[i] - if !d.DirectivesAreEqual(leftDirective, rightDirective) { - return false - } - } - return true -} - -func (d *Document) AddDirective(directive Directive) (ref int) { - d.Directives = append(d.Directives, directive) - return len(d.Directives) - 1 -} - -func (d *Document) ImportDirective(name string, argRefs []int) (ref int) { - directive := Directive{ - Name: d.Input.AppendInputString(name), - HasArguments: len(argRefs) > 0, - Arguments: ArgumentList{ - Refs: argRefs, - }, - } - - return d.AddDirective(directive) -} - -func (d *Document) AddDirectiveToNode(directiveRef int, node Node) bool { - switch node.Kind { - case NodeKindField: - d.Fields[node.Ref].Directives.Refs = append(d.Fields[node.Ref].Directives.Refs, directiveRef) - d.Fields[node.Ref].HasDirectives = true - return true - case NodeKindVariableDefinition: - d.VariableDefinitions[node.Ref].Directives.Refs = append(d.VariableDefinitions[node.Ref].Directives.Refs, directiveRef) - d.VariableDefinitions[node.Ref].HasDirectives = true - return true - case NodeKindOperationDefinition: - d.OperationDefinitions[node.Ref].Directives.Refs = append(d.OperationDefinitions[node.Ref].Directives.Refs, directiveRef) - d.OperationDefinitions[node.Ref].HasDirectives = true - return true - case NodeKindInputValueDefinition: - d.InputValueDefinitions[node.Ref].Directives.Refs = append(d.InputValueDefinitions[node.Ref].Directives.Refs, directiveRef) - d.InputValueDefinitions[node.Ref].HasDirectives = true - return true - case NodeKindInlineFragment: - d.InlineFragments[node.Ref].Directives.Refs = append(d.InlineFragments[node.Ref].Directives.Refs, directiveRef) - d.InlineFragments[node.Ref].HasDirectives = true - return true - case NodeKindFragmentSpread: - d.FragmentSpreads[node.Ref].Directives.Refs = append(d.FragmentSpreads[node.Ref].Directives.Refs, directiveRef) - d.FragmentSpreads[node.Ref].HasDirectives = true - return true - case NodeKindFragmentDefinition: - d.FragmentDefinitions[node.Ref].Directives.Refs = append(d.FragmentDefinitions[node.Ref].Directives.Refs, directiveRef) - d.FragmentDefinitions[node.Ref].HasDirectives = true - return true - default: - return false - } -} - -func (d *Document) DirectiveIsAllowedOnNodeKind(directiveName string, kind NodeKind, operationType OperationType) bool { - definition, ok := d.DirectiveDefinitionByName(directiveName) - if !ok { - return false - } - - switch kind { - case NodeKindOperationDefinition: - switch operationType { - case OperationTypeQuery: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationQuery) - case OperationTypeMutation: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationMutation) - case OperationTypeSubscription: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationSubscription) - } - case NodeKindField: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationField) - case NodeKindFragmentDefinition: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationFragmentDefinition) - case NodeKindFragmentSpread: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationFragmentSpread) - case NodeKindInlineFragment: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationInlineFragment) - case NodeKindVariableDefinition: - return d.DirectiveDefinitions[definition].DirectiveLocations.Get(ExecutableDirectiveLocationVariableDefinition) - } - - return false -} diff --git a/pkg/ast/ast_directive_definition.go b/pkg/ast/ast_directive_definition.go deleted file mode 100644 index 38941c93f..000000000 --- a/pkg/ast/ast_directive_definition.go +++ /dev/null @@ -1,157 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// DirectiveDefinition -// example: -// directive @example on FIELD -type DirectiveDefinition struct { - Description Description // optional, describes the directive - DirectiveLiteral position.Position // directive - At position.Position // @ - Name ByteSliceReference // e.g. example - HasArgumentsDefinitions bool - ArgumentsDefinition InputValueDefinitionList // optional, e.g. (if: Boolean) - On position.Position // on - DirectiveLocations DirectiveLocations // e.g. FIELD - Repeatable Repeatable -} - -type Repeatable struct { - IsRepeatable bool - Position position.Position -} - -func (d *Document) DirectiveDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.DirectiveDefinitions[ref].Name) -} - -func (d *Document) DirectiveDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.DirectiveDefinitions[ref].Name)) -} - -func (d *Document) DirectiveDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.DirectiveDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.DirectiveDefinitions[ref].Description.Content) -} - -func (d *Document) DirectiveDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.DirectiveDefinitionDescriptionBytes(ref)) -} - -func (d *Document) DirectiveArgumentInputValueDefinition(directiveName ByteSlice, argumentName ByteSlice) int { - for i := range d.DirectiveDefinitions { - if bytes.Equal(directiveName, d.Input.ByteSlice(d.DirectiveDefinitions[i].Name)) { - for _, j := range d.DirectiveDefinitions[i].ArgumentsDefinition.Refs { - if bytes.Equal(argumentName, d.Input.ByteSlice(d.InputValueDefinitions[j].Name)) { - return j - } - } - } - } - return -1 -} - -func (d *Document) DirectiveDefinitionArgumentDefaultValueString(directiveName, argumentName string) string { - inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName)) - if inputValueDefinition == -1 { - return "" - } - defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition) - if defaultValue.Kind != ValueKindString { - return "" - } - return d.StringValueContentString(defaultValue.Ref) -} - -func (d *Document) DirectiveDefinitionArgumentDefaultValueBool(directiveName, argumentName string) bool { - inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName)) - if inputValueDefinition == -1 { - return false - } - defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition) - if defaultValue.Kind != ValueKindBoolean { - return false - } - return bool(d.BooleanValue(defaultValue.Ref)) -} - -func (d *Document) DirectiveDefinitionArgumentDefaultValueInt64(directiveName, argumentName string) int64 { - inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName)) - if inputValueDefinition == -1 { - return -1 - } - defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition) - if defaultValue.Kind != ValueKindInteger { - return -1 - } - return d.IntValueAsInt(defaultValue.Ref) -} - -func (d *Document) DirectiveDefinitionArgumentDefaultValueFloat32(directiveName, argumentName string) float32 { - inputValueDefinition := d.DirectiveArgumentInputValueDefinition(unsafebytes.StringToBytes(directiveName), unsafebytes.StringToBytes(argumentName)) - if inputValueDefinition == -1 { - return -1 - } - defaultValue := d.InputValueDefinitionDefaultValue(inputValueDefinition) - if defaultValue.Kind != ValueKindFloat { - return -1 - } - return d.FloatValueAsFloat32(defaultValue.Ref) -} - -func (d *Document) AddDirectiveDefinition(directiveDefinition DirectiveDefinition) (ref int) { - d.DirectiveDefinitions = append(d.DirectiveDefinitions, directiveDefinition) - return len(d.DirectiveDefinitions) - 1 -} - -func (d *Document) ImportDirectiveDefinition(name, description string, argsRefs []int, locations []string) (ref int) { - directiveLocations := DirectiveLocations{} - for _, location := range locations { - _ = directiveLocations.SetFromRaw([]byte(location)) - } - - definition := DirectiveDefinition{ - Description: d.ImportDescription(description), - Name: d.Input.AppendInputString(name), - HasArgumentsDefinitions: len(argsRefs) > 0, - ArgumentsDefinition: InputValueDefinitionList{ - Refs: argsRefs, - }, - DirectiveLocations: directiveLocations, - } - - ref = d.AddDirectiveDefinition(definition) - d.ImportRootNode(ref, NodeKindDirectiveDefinition) - - return -} - -func (d *Document) DirectiveDefinitionByName(name string) (int, bool) { - for i := range d.DirectiveDefinitions { - if name == d.Input.ByteSliceString(d.DirectiveDefinitions[i].Name) { - return i, true - } - } - return -1, false -} - -func (d *Document) DirectiveDefinitionByNameBytes(name []byte) (int, bool) { - for i := range d.DirectiveDefinitions { - if bytes.Equal(name, d.Input.ByteSlice(d.DirectiveDefinitions[i].Name)) { - return i, true - } - } - return -1, false -} - -func (d *Document) DirectiveDefinitionIsRepeatable(ref int) bool { - return d.DirectiveDefinitions[ref].Repeatable.IsRepeatable -} diff --git a/pkg/ast/ast_enum_type_definition.go b/pkg/ast/ast_enum_type_definition.go deleted file mode 100644 index a38abe18d..000000000 --- a/pkg/ast/ast_enum_type_definition.go +++ /dev/null @@ -1,92 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// EnumTypeDefinition -// example: -// -// enum Direction { -// NORTH -// EAST -// SOUTH -// WEST -// } -type EnumTypeDefinition struct { - Description Description // optional, describes enum - EnumLiteral position.Position // enum - Name ByteSliceReference // e.g. Direction - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - HasEnumValuesDefinition bool - EnumValuesDefinition EnumValueDefinitionList // optional, e.g. { NORTH EAST } -} - -func (d *Document) EnumTypeDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Name) -} - -func (d *Document) EnumTypeDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Name)) -} - -func (d *Document) EnumTypeDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.EnumTypeDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.EnumTypeDefinitions[ref].Description.Content) -} - -func (d *Document) EnumTypeDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.EnumTypeDefinitionDescriptionBytes(ref)) -} - -func (d *Document) EnumTypeDefinitionHasDirectives(ref int) bool { - return d.EnumTypeDefinitions[ref].HasDirectives -} - -func (d *Document) EnumTypeDefinitionHasEnumValueDefinition(ref int) bool { - return d.EnumTypeDefinitions[ref].HasEnumValuesDefinition -} - -func (d *Document) EnumTypeDefinitionContainsEnumValue(enumTypeDef int, valueName ByteSlice) bool { - for _, i := range d.EnumTypeDefinitions[enumTypeDef].EnumValuesDefinition.Refs { - if bytes.Equal(valueName, d.EnumValueDefinitionNameBytes(i)) { - return true - } - } - return false -} - -func (d *Document) AddEnumTypeDefinition(definition EnumTypeDefinition) (ref int) { - d.EnumTypeDefinitions = append(d.EnumTypeDefinitions, definition) - return len(d.EnumTypeDefinitions) - 1 -} - -func (d *Document) ImportEnumTypeDefinition(name, description string, valueRefs []int) (ref int) { - return d.ImportEnumTypeDefinitionWithDirectives(name, description, valueRefs, nil) -} - -func (d *Document) ImportEnumTypeDefinitionWithDirectives(name, description string, valueRefs []int, directiveRefs []int) (ref int) { - definition := EnumTypeDefinition{ - Description: d.ImportDescription(description), - Name: d.Input.AppendInputString(name), - HasEnumValuesDefinition: len(valueRefs) > 0, - EnumValuesDefinition: EnumValueDefinitionList{ - Refs: valueRefs, - }, - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - } - - ref = d.AddEnumTypeDefinition(definition) - d.ImportRootNode(ref, NodeKindEnumTypeDefinition) - - return -} diff --git a/pkg/ast/ast_enum_type_extension.go b/pkg/ast/ast_enum_type_extension.go deleted file mode 100644 index 1f73114fc..000000000 --- a/pkg/ast/ast_enum_type_extension.go +++ /dev/null @@ -1,62 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type EnumTypeExtension struct { - ExtendLiteral position.Position - EnumTypeDefinition -} - -func (d *Document) EnumTypeExtensionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.EnumTypeExtensions[ref].Name) -} - -func (d *Document) EnumTypeExtensionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumTypeExtensions[ref].Name)) -} - -func (d *Document) EnumTypeExtensionDescriptionBytes(ref int) ByteSlice { - if !d.EnumTypeExtensions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.EnumTypeExtensions[ref].Description.Content) -} - -func (d *Document) EnumTypeExtensionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.EnumTypeExtensionDescriptionBytes(ref)) -} - -func (d *Document) EnumTypeExtensionHasEnumValueDefinition(ref int) bool { - return d.EnumTypeExtensions[ref].HasEnumValuesDefinition -} - -func (d *Document) EnumTypeExtensionHasDirectives(ref int) bool { - return d.EnumTypeExtensions[ref].HasDirectives -} - -func (d *Document) ExtendEnumTypeDefinitionByEnumTypeExtension(enumTypeDefinitionRef, enumTypeExtensionRef int) { - if d.EnumTypeExtensionHasDirectives(enumTypeExtensionRef) { - d.EnumTypeDefinitions[enumTypeDefinitionRef].Directives.Refs = append(d.EnumTypeDefinitions[enumTypeDefinitionRef].Directives.Refs, d.EnumTypeExtensions[enumTypeExtensionRef].Directives.Refs...) - d.EnumTypeDefinitions[enumTypeDefinitionRef].HasDirectives = true - } - - if d.EnumTypeExtensionHasEnumValueDefinition(enumTypeExtensionRef) { - d.EnumTypeDefinitions[enumTypeDefinitionRef].EnumValuesDefinition.Refs = append(d.EnumTypeDefinitions[enumTypeDefinitionRef].EnumValuesDefinition.Refs, d.EnumTypeExtensions[enumTypeExtensionRef].EnumValuesDefinition.Refs...) - d.EnumTypeDefinitions[enumTypeDefinitionRef].HasEnumValuesDefinition = true - } - - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: enumTypeExtensionRef, Kind: NodeKindEnumTypeExtension}) -} - -func (d *Document) ImportAndExtendEnumTypeDefinitionByEnumTypeExtension(enumTypeExtensionRef int) { - d.ImportEnumTypeDefinitionWithDirectives( - d.EnumTypeExtensionNameString(enumTypeExtensionRef), - d.EnumTypeExtensionDescriptionString(enumTypeExtensionRef), - d.EnumTypeExtensions[enumTypeExtensionRef].EnumValuesDefinition.Refs, - d.EnumTypeExtensions[enumTypeExtensionRef].Directives.Refs, - ) - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: enumTypeExtensionRef, Kind: NodeKindEnumTypeExtension}) -} diff --git a/pkg/ast/ast_enum_value_definition.go b/pkg/ast/ast_enum_value_definition.go deleted file mode 100644 index 15fa02b71..000000000 --- a/pkg/ast/ast_enum_value_definition.go +++ /dev/null @@ -1,104 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type EnumValueDefinitionList struct { - LBRACE position.Position // { - Refs []int // EnumValueDefinition - RBRACE position.Position // } -} - -// EnumValueDefinition -// example: -// "NORTH enum value" NORTH @foo -type EnumValueDefinition struct { - Description Description // optional, describes enum value - EnumValue ByteSliceReference // e.g. NORTH (Name but not true, false or null - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo -} - -func (d *Document) EnumValueDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.EnumValueDefinitions[ref].EnumValue) -} - -func (d *Document) EnumValueDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumValueDefinitions[ref].EnumValue)) -} - -func (d *Document) EnumValueDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.EnumValueDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.EnumValueDefinitions[ref].Description.Content) -} - -func (d *Document) EnumValueDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.EnumValueDefinitionDescriptionBytes(ref)) -} - -func (d *Document) EnumValueDefinitionHasDirectives(ref int) bool { - return d.EnumValueDefinitions[ref].HasDirectives -} - -func (d *Document) EnumValueDefinitionDirectives(ref int) (refs []int) { - return d.EnumValueDefinitions[ref].Directives.Refs -} - -func (d *Document) EnumValueDefinitionDirectiveByName(definitionRef int, directiveName ByteSlice) (ref int, exists bool) { - for _, i := range d.EnumValueDefinitions[definitionRef].Directives.Refs { - if bytes.Equal(directiveName, d.DirectiveNameBytes(i)) { - return i, true - } - } - return -} - -func (d *Document) EnumValueDefinitionIsFirst(ref int, ancestor Node) bool { - switch ancestor.Kind { - case NodeKindEnumTypeDefinition: - return d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs != nil && - d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs[0] == ref - case NodeKindEnumTypeExtension: - return d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs != nil && - d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs[0] == ref - default: - return false - } -} - -func (d *Document) EnumValueDefinitionIsLast(ref int, ancestor Node) bool { - switch ancestor.Kind { - case NodeKindEnumTypeDefinition: - return d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs != nil && - d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs[len(d.EnumTypeDefinitions[ancestor.Ref].EnumValuesDefinition.Refs)-1] == ref - case NodeKindEnumTypeExtension: - return d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs != nil && - d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs[len(d.EnumTypeExtensions[ancestor.Ref].EnumValuesDefinition.Refs)-1] == ref - default: - return false - } -} - -func (d *Document) AddEnumValueDefinition(inputValueDefinition EnumValueDefinition) (ref int) { - d.EnumValueDefinitions = append(d.EnumValueDefinitions, inputValueDefinition) - return len(d.EnumValueDefinitions) - 1 -} - -func (d *Document) ImportEnumValueDefinition(value, description string, directiveRefs []int) (ref int) { - inputValueDef := EnumValueDefinition{ - Description: d.ImportDescription(description), - EnumValue: d.Input.AppendInputString(value), - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - } - - return d.AddEnumValueDefinition(inputValueDef) -} diff --git a/pkg/ast/ast_field.go b/pkg/ast/ast_field.go deleted file mode 100644 index 525aef490..000000000 --- a/pkg/ast/ast_field.go +++ /dev/null @@ -1,130 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type Field struct { - Alias Alias // optional, e.g. renamed: - Name ByteSliceReference // field name, e.g. id - HasArguments bool - Arguments ArgumentList // optional - HasDirectives bool - Directives DirectiveList // optional - SelectionSet int // optional - HasSelections bool - Position position.Position -} - -func (d *Document) CopyField(ref int) int { - var arguments ArgumentList - var directives DirectiveList - var selectionSet int - if d.Fields[ref].HasArguments { - arguments = d.CopyArgumentList(d.Fields[ref].Arguments) - } - if d.Fields[ref].HasDirectives { - directives = d.CopyDirectiveList(d.Fields[ref].Directives) - } - if d.Fields[ref].HasSelections { - selectionSet = d.CopySelectionSet(d.Fields[ref].SelectionSet) - } - return d.AddField(Field{ - Name: d.copyByteSliceReference(d.Fields[ref].Name), - Alias: d.CopyAlias(d.Fields[ref].Alias), - HasArguments: d.Fields[ref].HasArguments, - Arguments: arguments, - HasDirectives: d.Fields[ref].HasDirectives, - Directives: directives, - HasSelections: d.Fields[ref].HasSelections, - SelectionSet: selectionSet, - }).Ref -} - -func (d *Document) FieldNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.Fields[ref].Name) -} - -// FieldNameUnsafeString - returns field name as a string which is unsafe pointer to document input content -func (d *Document) FieldNameUnsafeString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.Fields[ref].Name)) -} - -// FieldNameString - returns fied name as a string value -func (d *Document) FieldNameString(ref int) string { - return string(d.Input.ByteSlice(d.Fields[ref].Name)) -} - -func (d *Document) AddField(field Field) Node { - d.Fields = append(d.Fields, field) - return Node{ - Kind: NodeKindField, - Ref: len(d.Fields) - 1, - } -} - -func (d *Document) AddArgumentToField(fieldRef, argRef int) { - if !d.Fields[fieldRef].HasArguments { - d.Fields[fieldRef].HasArguments = true - d.Fields[fieldRef].Arguments.Refs = d.Refs[d.NextRefIndex()][:0] - } - d.Fields[fieldRef].Arguments.Refs = append(d.Fields[fieldRef].Arguments.Refs, argRef) -} - -func (d *Document) FieldArguments(ref int) []int { - return d.Fields[ref].Arguments.Refs -} - -func (d *Document) FieldArgument(field int, name ByteSlice) (ref int, exists bool) { - for _, i := range d.Fields[field].Arguments.Refs { - if bytes.Equal(d.ArgumentNameBytes(i), name) { - return i, true - } - } - return -1, false -} - -func (d *Document) FieldDirectives(ref int) []int { - return d.Fields[ref].Directives.Refs -} - -func (d *Document) FieldsHaveSameShape(left, right int) bool { - leftAliasDefined := d.FieldAliasIsDefined(left) - rightAliasDefined := d.FieldAliasIsDefined(right) - - switch { - case !leftAliasDefined && !rightAliasDefined: - return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Name, d.Fields[right].Name) - case leftAliasDefined && rightAliasDefined: - return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Alias.Name, d.Fields[right].Alias.Name) - case leftAliasDefined && !rightAliasDefined: - return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Alias.Name, d.Fields[right].Name) - case !leftAliasDefined && rightAliasDefined: - return d.Input.ByteSliceReferenceContentEquals(d.Fields[left].Name, d.Fields[right].Alias.Name) - default: - return false - } -} - -func (d *Document) FieldHasArguments(ref int) bool { - return d.Fields[ref].HasArguments -} - -func (d *Document) FieldHasSelections(ref int) bool { - return d.Fields[ref].HasSelections -} - -func (d *Document) FieldHasDirectives(ref int) bool { - return d.Fields[ref].HasDirectives -} - -func (d *Document) FieldsAreEqualFlat(left, right int) bool { - return bytes.Equal(d.FieldNameBytes(left), d.FieldNameBytes(right)) && // name - bytes.Equal(d.FieldAliasBytes(left), d.FieldAliasBytes(right)) && // alias - !d.FieldHasSelections(left) && !d.FieldHasSelections(right) && // selections - d.ArgumentSetsAreEquals(d.FieldArguments(left), d.FieldArguments(right)) && // arguments - d.DirectiveSetsAreEqual(d.FieldDirectives(left), d.FieldDirectives(right)) // directives -} diff --git a/pkg/ast/ast_field_alias.go b/pkg/ast/ast_field_alias.go deleted file mode 100644 index b8e549bf3..000000000 --- a/pkg/ast/ast_field_alias.go +++ /dev/null @@ -1,48 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type Alias struct { - IsDefined bool - Name ByteSliceReference // optional, e.g. renamedField - Colon position.Position // : -} - -func (d *Document) CopyAlias(alias Alias) Alias { - return Alias{ - IsDefined: alias.IsDefined, - Name: d.copyByteSliceReference(alias.Name), - } -} - -func (d *Document) FieldAliasOrNameBytes(ref int) ByteSlice { - if d.FieldAliasIsDefined(ref) { - return d.FieldAliasBytes(ref) - } - return d.FieldNameBytes(ref) -} - -func (d *Document) FieldAliasOrNameString(ref int) string { - return unsafebytes.BytesToString(d.FieldAliasOrNameBytes(ref)) -} - -func (d *Document) FieldAliasBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.Fields[ref].Alias.Name) -} - -func (d *Document) FieldAliasString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.Fields[ref].Alias.Name)) -} - -func (d *Document) FieldAliasIsDefined(ref int) bool { - return d.Fields[ref].Alias.IsDefined -} - -func (d *Document) RemoveFieldAlias(ref int) { - d.Fields[ref].Alias.IsDefined = false - d.Fields[ref].Alias.Name.Start = 0 - d.Fields[ref].Alias.Name.End = 0 -} diff --git a/pkg/ast/ast_field_definition.go b/pkg/ast/ast_field_definition.go deleted file mode 100644 index 3b5dc8079..000000000 --- a/pkg/ast/ast_field_definition.go +++ /dev/null @@ -1,152 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type FieldDefinitionList struct { - LBRACE position.Position // { - Refs []int // FieldDefinition - RBRACE position.Position // } -} - -type FieldDefinition struct { - Description Description // optional e.g. "FieldDefinition is ..." - Name ByteSliceReference // e.g. foo - HasArgumentsDefinitions bool - ArgumentsDefinition InputValueDefinitionList // optional - Colon position.Position // : - Type int // e.g. String - HasDirectives bool - Directives DirectiveList // e.g. @foo -} - -func (d *Document) FieldDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.FieldDefinitions[ref].Name) -} - -func (d *Document) FieldDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.FieldDefinitionNameBytes(ref)) -} - -func (d *Document) FieldDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.FieldDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.FieldDefinitions[ref].Description.Content) -} - -func (d *Document) FieldDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.FieldDefinitionDescriptionBytes(ref)) -} - -func (d *Document) FieldDefinitionIsFirst(field int, ancestor Node) bool { - definitions := d.NodeFieldDefinitions(ancestor) - return len(definitions) != 0 && definitions[0] == field -} - -func (d *Document) FieldDefinitionIsLast(field int, ancestor Node) bool { - definitions := d.NodeFieldDefinitions(ancestor) - return len(definitions) != 0 && definitions[len(definitions)-1] == field -} - -func (d *Document) FieldDefinitionHasDirectives(ref int) bool { - return d.FieldDefinitions[ref].HasDirectives -} - -func (d *Document) FieldDefinitionDirectives(fieldDefinition int) (refs []int) { - return d.FieldDefinitions[fieldDefinition].Directives.Refs -} - -func (d *Document) FieldDefinitionDirectiveByName(fieldDefinition int, directiveName ByteSlice) (ref int, exists bool) { - for _, i := range d.FieldDefinitions[fieldDefinition].Directives.Refs { - if bytes.Equal(directiveName, d.DirectiveNameBytes(i)) { - return i, true - } - } - return -} - -func (d *Document) FieldDefinitionHasNamedDirective(fieldDefinition int, directiveName string) bool { - _, exists := d.FieldDefinitionDirectiveByName(fieldDefinition, unsafebytes.StringToBytes(directiveName)) - return exists -} - -func (d *Document) FieldDefinitionResolverTypeName(enclosingType Node) ByteSlice { - switch enclosingType.Kind { - case NodeKindObjectTypeDefinition: - name := d.ObjectTypeDefinitionNameBytes(enclosingType.Ref) - switch { - case bytes.Equal(name, d.Index.QueryTypeName): - return literal.QUERY - case bytes.Equal(name, d.Index.MutationTypeName): - return literal.MUTATION - case bytes.Equal(name, d.Index.SubscriptionTypeName): - return literal.SUBSCRIPTION - } - } - return d.NodeNameBytes(enclosingType) -} - -func (d *Document) AddFieldDefinition(fieldDefinition FieldDefinition) (ref int) { - d.FieldDefinitions = append(d.FieldDefinitions, fieldDefinition) - return len(d.FieldDefinitions) - 1 -} - -func (d *Document) ImportFieldDefinition(name, description string, typeRef int, argsRefs []int, directiveRefs []int) (ref int) { - fieldDef := FieldDefinition{ - Name: d.Input.AppendInputString(name), - Type: typeRef, - Description: d.ImportDescription(description), - ArgumentsDefinition: InputValueDefinitionList{ - Refs: argsRefs, - }, - HasArgumentsDefinitions: len(argsRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - HasDirectives: len(directiveRefs) > 0, - } - - return d.AddFieldDefinition(fieldDef) -} - -func (d *Document) FieldDefinitionsContainField(definitions []int, field ByteSlice) bool { - for _, i := range definitions { - if bytes.Equal(field, d.FieldDefinitionNameBytes(i)) { - return true - } - } - return false -} - -func (d *Document) FieldDefinitionHasArgumentsDefinitions(ref int) bool { - return d.FieldDefinitions[ref].HasArgumentsDefinitions -} - -func (d *Document) FieldDefinitionArgumentsDefinitions(ref int) []int { - return d.FieldDefinitions[ref].ArgumentsDefinition.Refs -} - -func (d *Document) FieldDefinitionType(ref int) int { - return d.FieldDefinitions[ref].Type -} - -func (d *Document) FieldDefinitionTypeNode(ref int) Node { - typeName := d.ResolveTypeNameBytes(d.FieldDefinitions[ref].Type) - node, _ := d.Index.FirstNodeByNameBytes(typeName) - return node -} - -func (d *Document) RemoveFieldDefinitionsFromObjectTypeDefinition(fieldDefinitionRefs []int, objectTypeDefinitionRef int) { - for _, fieldRef := range fieldDefinitionRefs { - if i, ok := indexOf(d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, fieldRef); ok { - deleteRef(&d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, i) - } - } - d.ObjectTypeDefinitions[objectTypeDefinitionRef].HasFieldDefinitions = len(d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs) > 0 -} diff --git a/pkg/ast/ast_fragment_definition.go b/pkg/ast/ast_fragment_definition.go deleted file mode 100644 index 500634de7..000000000 --- a/pkg/ast/ast_fragment_definition.go +++ /dev/null @@ -1,73 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// TypeCondition -// example: -// on User -type TypeCondition struct { - On position.Position // on - Type int // NamedType -} - -// FragmentDefinition -// example: -// -// fragment friendFields on User { -// id -// name -// profilePic(size: 50) -// } -type FragmentDefinition struct { - FragmentLiteral position.Position // fragment - Name ByteSliceReference // Name but not on, e.g. friendFields - TypeCondition TypeCondition // e.g. on User - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - SelectionSet int // e.g. { id } - HasSelections bool -} - -func (d *Document) FragmentDefinitionRef(byName ByteSlice) (ref int, exists bool) { - for i := range d.FragmentDefinitions { - if bytes.Equal(byName, d.Input.ByteSlice(d.FragmentDefinitions[i].Name)) { - return i, true - } - } - return -1, false -} - -func (d *Document) FragmentDefinitionTypeName(ref int) ByteSlice { - return d.ResolveTypeNameBytes(d.FragmentDefinitions[ref].TypeCondition.Type) -} - -func (d *Document) FragmentDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.FragmentDefinitions[ref].Name) -} - -func (d *Document) FragmentDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.FragmentDefinitions[ref].Name)) -} - -func (d *Document) FragmentDefinitionIsLastRootNode(ref int) bool { - for i := range d.RootNodes { - if d.RootNodes[i].Kind == NodeKindFragmentDefinition && d.RootNodes[i].Ref == ref { - return len(d.RootNodes)-1 == i - } - } - return false -} - -func (d *Document) FragmentDefinitionIsUsed(name ByteSlice) bool { - for _, i := range d.Index.ReplacedFragmentSpreads { - if bytes.Equal(name, d.FragmentSpreadNameBytes(i)) { - return true - } - } - return false -} diff --git a/pkg/ast/ast_fragment_spread.go b/pkg/ast/ast_fragment_spread.go deleted file mode 100644 index ff7d142a1..000000000 --- a/pkg/ast/ast_fragment_spread.go +++ /dev/null @@ -1,80 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// FragmentSpread -// example: -// ...MyFragment -type FragmentSpread struct { - Spread position.Position // ... - FragmentName ByteSliceReference // Name but not on, e.g. MyFragment - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo -} - -func (d *Document) CopyFragmentSpread(ref int) int { - var directives DirectiveList - if d.FragmentSpreads[ref].HasDirectives { - directives = d.CopyDirectiveList(d.FragmentSpreads[ref].Directives) - } - return d.AddFragmentSpread(FragmentSpread{ - FragmentName: d.copyByteSliceReference(d.FragmentSpreads[ref].FragmentName), - HasDirectives: d.FragmentSpreads[ref].HasDirectives, - Directives: directives, - }) -} - -func (d *Document) AddFragmentSpread(spread FragmentSpread) int { - d.FragmentSpreads = append(d.FragmentSpreads, spread) - return len(d.FragmentSpreads) - 1 -} - -func (d *Document) FragmentSpreadNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.FragmentSpreads[ref].FragmentName) -} - -func (d *Document) FragmentSpreadNameString(ref int) string { - return unsafebytes.BytesToString(d.FragmentSpreadNameBytes(ref)) -} - -// ReplaceFragmentSpread replaces a fragment spread with a given selection set -// attention! this might lead to duplicate field problems because the same field with its unique field reference might be copied into the same selection set -// possible problems: changing directives or sub selections will affect both fields with the same id -// simple solution: run normalization deduplicate fields -// as part of the normalization flow this problem will be handled automatically -// just be careful in case you use this function outside of the normalization package -func (d *Document) ReplaceFragmentSpread(selectionSet int, spreadRef int, replaceWithSelectionSet int) { - for i, j := range d.SelectionSets[selectionSet].SelectionRefs { - if d.Selections[j].Kind == SelectionKindFragmentSpread && d.Selections[j].Ref == spreadRef { - d.SelectionSets[selectionSet].SelectionRefs = append(d.SelectionSets[selectionSet].SelectionRefs[:i], append(d.SelectionSets[replaceWithSelectionSet].SelectionRefs, d.SelectionSets[selectionSet].SelectionRefs[i+1:]...)...) - d.Index.ReplacedFragmentSpreads = append(d.Index.ReplacedFragmentSpreads, spreadRef) - return - } - } -} - -// ReplaceFragmentSpreadWithInlineFragment replaces a given fragment spread with a inline fragment -// attention! the same rules apply as for 'ReplaceFragmentSpread', look above! -func (d *Document) ReplaceFragmentSpreadWithInlineFragment(selectionSet int, spreadRef int, replaceWithSelectionSet int, typeCondition TypeCondition) { - d.InlineFragments = append(d.InlineFragments, InlineFragment{ - TypeCondition: typeCondition, - SelectionSet: replaceWithSelectionSet, - HasSelections: len(d.SelectionSets[replaceWithSelectionSet].SelectionRefs) != 0, - }) - ref := len(d.InlineFragments) - 1 - d.Selections = append(d.Selections, Selection{ - Kind: SelectionKindInlineFragment, - Ref: ref, - }) - selectionRef := len(d.Selections) - 1 - for i, j := range d.SelectionSets[selectionSet].SelectionRefs { - if d.Selections[j].Kind == SelectionKindFragmentSpread && d.Selections[j].Ref == spreadRef { - d.SelectionSets[selectionSet].SelectionRefs = append(d.SelectionSets[selectionSet].SelectionRefs[:i], append([]int{selectionRef}, d.SelectionSets[selectionSet].SelectionRefs[i+1:]...)...) - d.Index.ReplacedFragmentSpreads = append(d.Index.ReplacedFragmentSpreads, spreadRef) - return - } - } -} diff --git a/pkg/ast/ast_inline_fragment.go b/pkg/ast/ast_inline_fragment.go deleted file mode 100644 index 322a09d39..000000000 --- a/pkg/ast/ast_inline_fragment.go +++ /dev/null @@ -1,72 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// InlineFragment -// example: -// -// ... on User { -// friends { -// count -// } -// } -type InlineFragment struct { - Spread position.Position // ... - TypeCondition TypeCondition // on NamedType, e.g. on User - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - SelectionSet int // optional, e.g. { nextField } - HasSelections bool -} - -func (d *Document) CopyInlineFragment(ref int) int { - var directives DirectiveList - var selectionSet int - if d.InlineFragments[ref].HasDirectives { - directives = d.CopyDirectiveList(d.InlineFragments[ref].Directives) - } - if d.InlineFragments[ref].HasSelections { - selectionSet = d.CopySelectionSet(d.InlineFragments[ref].SelectionSet) - } - return d.AddInlineFragment(InlineFragment{ - TypeCondition: d.InlineFragments[ref].TypeCondition, // Value type; doesn't need to be copied. - HasDirectives: d.InlineFragments[ref].HasDirectives, - Directives: directives, - SelectionSet: selectionSet, - HasSelections: d.InlineFragments[ref].HasSelections, - }) -} - -func (d *Document) InlineFragmentTypeConditionName(ref int) ByteSlice { - if d.InlineFragments[ref].TypeCondition.Type == -1 { - return nil - } - return d.Input.ByteSlice(d.Types[d.InlineFragments[ref].TypeCondition.Type].Name) -} - -func (d *Document) InlineFragmentTypeConditionNameString(ref int) string { - return unsafebytes.BytesToString(d.InlineFragmentTypeConditionName(ref)) -} - -func (d *Document) InlineFragmentHasTypeCondition(ref int) bool { - return d.InlineFragments[ref].TypeCondition.Type != -1 -} - -func (d *Document) InlineFragmentHasDirectives(ref int) bool { - return len(d.InlineFragments[ref].Directives.Refs) != 0 -} - -func (d *Document) InlineFragmentSelections(ref int) []int { - if !d.InlineFragments[ref].HasSelections { - return nil - } - return d.SelectionSets[d.InlineFragments[ref].SelectionSet].SelectionRefs -} - -func (d *Document) AddInlineFragment(fragment InlineFragment) int { - d.InlineFragments = append(d.InlineFragments, fragment) - return len(d.InlineFragments) - 1 -} diff --git a/pkg/ast/ast_input_object_type_definition.go b/pkg/ast/ast_input_object_type_definition.go deleted file mode 100644 index 21e6b074f..000000000 --- a/pkg/ast/ast_input_object_type_definition.go +++ /dev/null @@ -1,122 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type InputObjectTypeDefinition struct { - Description Description // optional, describes the input type - InputLiteral position.Position // input - Name ByteSliceReference // name of the input type - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - HasInputFieldsDefinition bool - InputFieldsDefinition InputValueDefinitionList // e.g. x:Float -} - -func (d *Document) InputObjectTypeDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.InputObjectTypeDefinitions[ref].Name) -} - -func (d *Document) InputObjectTypeDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.InputObjectTypeDefinitions[ref].Name)) -} - -func (d *Document) InputObjectTypeDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.InputObjectTypeDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.InputObjectTypeDefinitions[ref].Description.Content) -} - -func (d *Document) InputObjectTypeDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.InputObjectTypeDefinitionDescriptionBytes(ref)) -} - -func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueString(inputObjectTypeDefinitionName, inputValueDefinitionName string) string { - defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName) - if defaultValue.Kind != ValueKindString { - return "" - } - return d.StringValueContentString(defaultValue.Ref) -} - -func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueBool(inputObjectTypeDefinitionName, inputValueDefinitionName string) bool { - defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName) - if defaultValue.Kind != ValueKindBoolean { - return false - } - return bool(d.BooleanValue(defaultValue.Ref)) -} - -func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueInt64(inputObjectTypeDefinitionName, inputValueDefinitionName string) int64 { - defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName) - if defaultValue.Kind != ValueKindInteger { - return -1 - } - return d.IntValueAsInt(defaultValue.Ref) -} - -func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValueFloat32(inputObjectTypeDefinitionName, inputValueDefinitionName string) float32 { - defaultValue := d.InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName) - if defaultValue.Kind != ValueKindFloat { - return -1 - } - return d.FloatValueAsFloat32(defaultValue.Ref) -} - -func (d *Document) InputObjectTypeDefinitionInputValueDefinitionDefaultValue(inputObjectTypeDefinitionName, inputValueDefinitionName string) Value { - inputObjectTypeDefinition, exists := d.Index.FirstNodeByNameStr(inputObjectTypeDefinitionName) - if !exists { - return Value{} - } - if inputObjectTypeDefinition.Kind != NodeKindInputObjectTypeDefinition { - return Value{} - } - inputValueDefinition := d.InputObjectTypeDefinitionInputValueDefinitionByName(inputObjectTypeDefinition.Ref, unsafebytes.StringToBytes(inputValueDefinitionName)) - if inputValueDefinition == -1 { - return Value{} - } - return d.InputValueDefinitionDefaultValue(inputValueDefinition) -} - -func (d *Document) InputObjectTypeDefinitionInputValueDefinitionByName(definition int, inputValueDefinitionName ByteSlice) int { - for _, i := range d.InputObjectTypeDefinitions[definition].InputFieldsDefinition.Refs { - if bytes.Equal(inputValueDefinitionName, d.InputValueDefinitionNameBytes(i)) { - return i - } - } - return -1 -} - -func (d *Document) AddInputObjectTypeDefinition(definition InputObjectTypeDefinition) (ref int) { - d.InputObjectTypeDefinitions = append(d.InputObjectTypeDefinitions, definition) - return len(d.InputObjectTypeDefinitions) - 1 -} - -func (d *Document) ImportInputObjectTypeDefinition(name, description string, argsRefs []int) (ref int) { - return d.ImportInputObjectTypeDefinitionWithDirectives(name, description, argsRefs, nil) -} - -func (d *Document) ImportInputObjectTypeDefinitionWithDirectives(name, description string, argsRefs []int, directiveRefs []int) (ref int) { - definition := InputObjectTypeDefinition{ - Description: d.ImportDescription(description), - Name: d.Input.AppendInputString(name), - HasInputFieldsDefinition: len(argsRefs) > 0, - InputFieldsDefinition: InputValueDefinitionList{ - Refs: argsRefs, - }, - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - directiveRefs, - }, - } - - ref = d.AddInputObjectTypeDefinition(definition) - d.ImportRootNode(ref, NodeKindInputObjectTypeDefinition) - - return -} diff --git a/pkg/ast/ast_input_object_type_extension.go b/pkg/ast/ast_input_object_type_extension.go deleted file mode 100644 index 1107408b9..000000000 --- a/pkg/ast/ast_input_object_type_extension.go +++ /dev/null @@ -1,62 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type InputObjectTypeExtension struct { - ExtendLiteral position.Position - InputObjectTypeDefinition -} - -func (d *Document) InputObjectTypeExtensionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.InputObjectTypeExtensions[ref].Name) -} - -func (d *Document) InputObjectTypeExtensionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.InputObjectTypeExtensions[ref].Name)) -} - -func (d *Document) InputObjectTypeExtensionDescriptionBytes(ref int) ByteSlice { - if !d.InputObjectTypeExtensions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.InputObjectTypeExtensions[ref].Description.Content) -} - -func (d *Document) InputObjectTypeExtensionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.InputObjectTypeExtensionDescriptionBytes(ref)) -} - -func (d *Document) InputObjectTypeExtensionHasInputFieldsDefinition(ref int) bool { - return d.InputObjectTypeExtensions[ref].HasInputFieldsDefinition -} - -func (d *Document) InputObjectTypeExtensionHasDirectives(ref int) bool { - return d.InputObjectTypeExtensions[ref].HasDirectives -} - -func (d *Document) ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(inputObjectTypeDefinitionRef, inputObjectTypeExtensionRef int) { - if d.InputObjectTypeExtensionHasDirectives(inputObjectTypeExtensionRef) { - d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].Directives.Refs = append(d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].Directives.Refs, d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].Directives.Refs...) - d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].HasDirectives = true - } - - if d.InputObjectTypeExtensionHasInputFieldsDefinition(inputObjectTypeExtensionRef) { - d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].InputFieldsDefinition.Refs = append(d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].InputFieldsDefinition.Refs, d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].InputFieldsDefinition.Refs...) - d.InputObjectTypeDefinitions[inputObjectTypeDefinitionRef].HasInputFieldsDefinition = true - } - - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: inputObjectTypeExtensionRef, Kind: NodeKindInputObjectTypeExtension}) -} - -func (d *Document) ImportAndExtendInputObjectTypeDefinitionByInputObjectTypeExtension(inputObjectTypeExtensionRef int) { - d.ImportInputObjectTypeDefinitionWithDirectives( - d.InputObjectTypeExtensionNameString(inputObjectTypeExtensionRef), - d.InputObjectTypeExtensionDescriptionString(inputObjectTypeExtensionRef), - d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].InputFieldsDefinition.Refs, - d.InputObjectTypeExtensions[inputObjectTypeExtensionRef].Directives.Refs, - ) - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: inputObjectTypeExtensionRef, Kind: NodeKindInputObjectTypeExtension}) -} diff --git a/pkg/ast/ast_input_value_definition.go b/pkg/ast/ast_input_value_definition.go deleted file mode 100644 index 87df77c12..000000000 --- a/pkg/ast/ast_input_value_definition.go +++ /dev/null @@ -1,95 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type InputValueDefinitionList struct { - LPAREN position.Position // ( - Refs []int // InputValueDefinition - RPAREN position.Position // ) -} - -type DefaultValue struct { - IsDefined bool - Equals position.Position // = - Value Value // e.g. "Foo" -} - -type InputValueDefinition struct { - Description Description // optional, e.g. "input Foo is..." - Name ByteSliceReference // e.g. Foo - Colon position.Position // : - Type int // e.g. String - DefaultValue DefaultValue // e.g. = "Bar" - HasDirectives bool - Directives DirectiveList // e.g. @baz -} - -func (d *Document) InputValueDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.InputValueDefinitions[ref].Name) -} - -func (d *Document) InputValueDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.InputValueDefinitions[ref].Name)) -} - -func (d *Document) InputValueDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.InputValueDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.InputValueDefinitions[ref].Description.Content) -} - -func (d *Document) InputValueDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.InputValueDefinitionDescriptionBytes(ref)) -} - -func (d *Document) InputValueDefinitionType(ref int) int { - return d.InputValueDefinitions[ref].Type -} - -func (d *Document) InputValueDefinitionHasDefaultValue(ref int) bool { - return d.InputValueDefinitions[ref].DefaultValue.IsDefined -} - -func (d *Document) InputValueDefinitionDefaultValue(ref int) Value { - return d.InputValueDefinitions[ref].DefaultValue.Value -} - -func (d *Document) InputValueDefinitionArgumentIsOptional(ref int) bool { - nonNull := d.Types[d.InputValueDefinitions[ref].Type].TypeKind == TypeKindNonNull - hasDefault := d.InputValueDefinitions[ref].DefaultValue.IsDefined - return !nonNull || hasDefault -} - -func (d *Document) InputValueDefinitionHasDirective(ref int, directiveName ByteSlice) bool { - if !d.InputValueDefinitions[ref].HasDirectives { - return false - } - for _, i := range d.InputValueDefinitions[ref].Directives.Refs { - if bytes.Equal(directiveName, d.DirectiveNameBytes(i)) { - return true - } - } - return false -} - -func (d *Document) AddInputValueDefinition(inputValueDefinition InputValueDefinition) (ref int) { - d.InputValueDefinitions = append(d.InputValueDefinitions, inputValueDefinition) - return len(d.InputValueDefinitions) - 1 -} - -func (d *Document) ImportInputValueDefinition(name, description string, typeRef int, defaultValue DefaultValue) (ref int) { - inputValueDef := InputValueDefinition{ - Description: d.ImportDescription(description), - Name: d.Input.AppendInputString(name), - Type: typeRef, - DefaultValue: defaultValue, - } - - return d.AddInputValueDefinition(inputValueDef) -} diff --git a/pkg/ast/ast_interface_type_definition.go b/pkg/ast/ast_interface_type_definition.go deleted file mode 100644 index 5b9306fe6..000000000 --- a/pkg/ast/ast_interface_type_definition.go +++ /dev/null @@ -1,152 +0,0 @@ -package ast - -import ( - "bytes" - "sort" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// InterfaceTypeDefinition -// example: -// -// interface NamedEntity { -// name: String -// } -type InterfaceTypeDefinition struct { - Description Description // optional, describes the interface - InterfaceLiteral position.Position // interface - Name ByteSliceReference // e.g. NamedEntity - ImplementsInterfaces TypeList // e.g implements Bar & Baz - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - HasFieldDefinitions bool - FieldsDefinition FieldDefinitionList // optional, e.g. { name: String } -} - -func (d *Document) InterfaceTypeDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Name) -} - -func (d *Document) InterfaceTypeDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Name)) -} - -func (d *Document) InterfaceTypeDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.InterfaceTypeDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.InterfaceTypeDefinitions[ref].Description.Content) -} - -func (d *Document) InterfaceTypeDefinitionImplementsInterface(definitionRef int, interfaceName ByteSlice) bool { - for _, iRef := range d.InterfaceTypeDefinitions[definitionRef].ImplementsInterfaces.Refs { - implements := d.ResolveTypeNameBytes(iRef) - if bytes.Equal(interfaceName, implements) { - return true - } - } - return false -} - -func (d *Document) InterfaceTypeDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.InterfaceTypeDefinitionDescriptionBytes(ref)) -} - -// InterfaceTypeDefinitionImplementedByRootNodes will return all RootNodes that implement the given interface type (by ref) -func (d *Document) InterfaceTypeDefinitionImplementedByRootNodes(ref int) []Node { - interfaceTypeName := d.InterfaceTypeDefinitionNameBytes(ref) - implementingRootNodes := make(map[Node]bool) - for i := 0; i < len(d.RootNodes); i++ { - if d.RootNodes[i].Kind == NodeKindInterfaceTypeDefinition && d.RootNodes[i].Ref == ref { - continue - } - - var rootNodeInterfaceRefs []int - switch d.RootNodes[i].Kind { - case NodeKindObjectTypeDefinition: - if len(d.ObjectTypeDefinitions[d.RootNodes[i].Ref].ImplementsInterfaces.Refs) == 0 { - continue - } - rootNodeInterfaceRefs = d.ObjectTypeDefinitions[d.RootNodes[i].Ref].ImplementsInterfaces.Refs - case NodeKindInterfaceTypeDefinition: - if len(d.InterfaceTypeDefinitions[d.RootNodes[i].Ref].ImplementsInterfaces.Refs) == 0 { - continue - } - rootNodeInterfaceRefs = d.InterfaceTypeDefinitions[d.RootNodes[i].Ref].ImplementsInterfaces.Refs - default: - continue - } - - for j := 0; j < len(rootNodeInterfaceRefs); j++ { - implementedInterfaceTypeName := d.TypeNameBytes(rootNodeInterfaceRefs[j]) - if !interfaceTypeName.Equals(implementedInterfaceTypeName) { - continue - } - - var typeName ByteSlice - switch d.RootNodes[i].Kind { - case NodeKindObjectTypeDefinition: - typeName = d.ObjectTypeDefinitionNameBytes(d.RootNodes[i].Ref) - case NodeKindInterfaceTypeDefinition: - typeName = d.InterfaceTypeDefinitionNameBytes(d.RootNodes[i].Ref) - } - - node, exists := d.Index.FirstNodeByNameBytes(typeName) - if !exists { - continue - } - - _, isAlreadyAdded := implementingRootNodes[node] - if isAlreadyAdded { - continue - } - - implementingRootNodes[node] = true - } - } - - var nodes []Node - for mapNode := range implementingRootNodes { - nodes = append(nodes, mapNode) - } - - sort.Slice(nodes, func(i, j int) bool { - return nodes[i].Ref < nodes[j].Ref - }) - - return nodes -} - -func (d *Document) AddInterfaceTypeDefinition(definition InterfaceTypeDefinition) (ref int) { - d.InterfaceTypeDefinitions = append(d.InterfaceTypeDefinitions, definition) - return len(d.InterfaceTypeDefinitions) - 1 -} - -func (d *Document) ImportInterfaceTypeDefinition(name, description string, fieldRefs []int) (ref int) { - return d.ImportInterfaceTypeDefinitionWithDirectives(name, description, fieldRefs, nil, nil) -} - -func (d *Document) ImportInterfaceTypeDefinitionWithDirectives(name, description string, fieldRefs []int, iRefs []int, directiveRefs []int) (ref int) { - definition := InterfaceTypeDefinition{ - Name: d.Input.AppendInputString(name), - Description: d.ImportDescription(description), - FieldsDefinition: FieldDefinitionList{ - Refs: fieldRefs, - }, - ImplementsInterfaces: TypeList{ - Refs: iRefs, - }, - HasFieldDefinitions: len(fieldRefs) > 0, - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - } - - ref = d.AddInterfaceTypeDefinition(definition) - d.ImportRootNode(ref, NodeKindInterfaceTypeDefinition) - - return -} diff --git a/pkg/ast/ast_interface_type_extension.go b/pkg/ast/ast_interface_type_extension.go deleted file mode 100644 index 0270e5eb1..000000000 --- a/pkg/ast/ast_interface_type_extension.go +++ /dev/null @@ -1,75 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type InterfaceTypeExtension struct { - ExtendLiteral position.Position - InterfaceTypeDefinition -} - -func (d *Document) InterfaceTypeExtensionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.InterfaceTypeExtensions[ref].Name) -} - -func (d *Document) InterfaceTypeExtensionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.InterfaceTypeExtensions[ref].Name)) -} - -func (d *Document) InterfaceTypeExtensionDescriptionBytes(ref int) ByteSlice { - if !d.InterfaceTypeExtensions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.InterfaceTypeExtensions[ref].Description.Content) -} - -func (d *Document) InterfaceTypeExtensionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.InterfaceTypeExtensionDescriptionBytes(ref)) -} - -func (d *Document) InterfaceTypeExtensionHasFieldDefinitions(ref int) bool { - return d.InterfaceTypeExtensions[ref].HasFieldDefinitions -} - -func (d *Document) InterfaceTypeExtensionHasDirectives(ref int) bool { - return d.InterfaceTypeExtensions[ref].HasDirectives -} - -func (d *Document) ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(interfaceTypeDefinitionRef, interfaceTypeExtensionRef int) { - if d.InterfaceTypeExtensionHasFieldDefinitions(interfaceTypeExtensionRef) { - d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].FieldsDefinition.Refs = append(d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].FieldsDefinition.Refs, d.InterfaceTypeExtensions[interfaceTypeExtensionRef].FieldsDefinition.Refs...) - d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].HasFieldDefinitions = true - } - - if d.InterfaceTypeExtensionHasDirectives(interfaceTypeExtensionRef) { - d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].Directives.Refs = append(d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].Directives.Refs, d.InterfaceTypeExtensions[interfaceTypeExtensionRef].Directives.Refs...) - d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].HasDirectives = true - } - - if len(d.InterfaceTypeExtensions[interfaceTypeExtensionRef].ImplementsInterfaces.Refs) > 0 { - d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].ImplementsInterfaces.Refs = append( - d.InterfaceTypeDefinitions[interfaceTypeDefinitionRef].ImplementsInterfaces.Refs, - d.InterfaceTypeExtensions[interfaceTypeExtensionRef].ImplementsInterfaces.Refs..., - ) - } - - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: interfaceTypeExtensionRef, Kind: NodeKindInterfaceTypeExtension}) -} - -func (d *Document) ImportAndExtendInterfaceTypeDefinitionByInterfaceTypeExtension(interfaceTypeExtensionRef int) { - d.ImportInterfaceTypeDefinitionWithDirectives( - d.InterfaceTypeExtensionNameString(interfaceTypeExtensionRef), - d.InterfaceTypeExtensionDescriptionString(interfaceTypeExtensionRef), - d.InterfaceTypeExtensions[interfaceTypeExtensionRef].FieldsDefinition.Refs, - d.InterfaceTypeExtensions[interfaceTypeExtensionRef].ImplementsInterfaces.Refs, - d.InterfaceTypeExtensions[interfaceTypeExtensionRef].Directives.Refs, - ) - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: interfaceTypeExtensionRef, Kind: NodeKindInterfaceTypeExtension}) -} - -func (d *Document) AddInterfaceTypeExtension(extension InterfaceTypeExtension) (ref int) { - d.InterfaceTypeExtensions = append(d.InterfaceTypeExtensions, extension) - return len(d.InterfaceTypeExtensions) - 1 -} diff --git a/pkg/ast/ast_node.go b/pkg/ast/ast_node.go deleted file mode 100644 index b4ac9aaa0..000000000 --- a/pkg/ast/ast_node.go +++ /dev/null @@ -1,542 +0,0 @@ -package ast - -import ( - "bytes" - "fmt" - "log" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -type Node struct { - Kind NodeKind - Ref int -} - -var InvalidNode = Node{Kind: NodeKindUnknown, Ref: InvalidRef} - -func (n *Node) IsExtensionKind() bool { - switch n.Kind { - case NodeKindSchemaExtension, - NodeKindObjectTypeExtension, - NodeKindInputObjectTypeExtension, - NodeKindInterfaceTypeExtension, - NodeKindEnumTypeExtension, - NodeKindScalarTypeExtension, - NodeKindUnionTypeExtension: - return true - } - - return false -} - -func (d *Document) NodeNameBytes(node Node) ByteSlice { - var ref ByteSliceReference - - switch node.Kind { - case NodeKindObjectTypeDefinition: - ref = d.ObjectTypeDefinitions[node.Ref].Name - case NodeKindInterfaceTypeDefinition: - ref = d.InterfaceTypeDefinitions[node.Ref].Name - case NodeKindInputObjectTypeDefinition: - ref = d.InputObjectTypeDefinitions[node.Ref].Name - case NodeKindUnionTypeDefinition: - ref = d.UnionTypeDefinitions[node.Ref].Name - case NodeKindScalarTypeDefinition: - ref = d.ScalarTypeDefinitions[node.Ref].Name - case NodeKindDirectiveDefinition: - ref = d.DirectiveDefinitions[node.Ref].Name - case NodeKindEnumTypeDefinition: - ref = d.EnumTypeDefinitions[node.Ref].Name - case NodeKindField: - ref = d.Fields[node.Ref].Name - case NodeKindDirective: - ref = d.Directives[node.Ref].Name - case NodeKindObjectTypeExtension: - ref = d.ObjectTypeExtensions[node.Ref].Name - case NodeKindInterfaceTypeExtension: - ref = d.InterfaceTypeExtensions[node.Ref].Name - case NodeKindUnionTypeExtension: - ref = d.UnionTypeExtensions[node.Ref].Name - case NodeKindEnumTypeExtension: - ref = d.EnumTypeExtensions[node.Ref].Name - } - - return d.Input.ByteSlice(ref) -} - -func (n Node) NameBytes(definition *Document) []byte { - return definition.NodeNameBytes(n) -} - -func (n Node) NameString(definition *Document) string { - return unsafebytes.BytesToString(definition.NodeNameBytes(n)) -} - -func (d *Document) UpdateRootNode(ref int, newNodeRef int, newNodeKind NodeKind) { - d.RootNodes[ref].Kind = newNodeKind - d.RootNodes[ref].Ref = newNodeRef -} - -// TODO: we could use node name directly -func (d *Document) NodeNameUnsafeString(node Node) string { - return unsafebytes.BytesToString(d.NodeNameBytes(node)) -} - -func (d *Document) NodeNameString(node Node) string { - return string(d.NodeNameBytes(node)) -} - -// Node directives - -// NodeHasDirectiveByNameString returns whether the given node has a directive with the given name as string. -func (d *Document) NodeHasDirectiveByNameString(node Node, directiveName string) bool { - for _, directiveRef := range d.NodeDirectives(node) { - if d.DirectiveNameString(directiveRef) == directiveName { - return true - } - } - return false -} - -func (d *Document) NodeDirectives(node Node) []int { - switch node.Kind { - case NodeKindField: - return d.Fields[node.Ref].Directives.Refs - case NodeKindInlineFragment: - return d.InlineFragments[node.Ref].Directives.Refs - case NodeKindFragmentSpread: - return d.FragmentSpreads[node.Ref].Directives.Refs - case NodeKindSchemaDefinition: - return d.SchemaDefinitions[node.Ref].Directives.Refs - case NodeKindSchemaExtension: - return d.SchemaExtensions[node.Ref].Directives.Refs - case NodeKindObjectTypeDefinition: - return d.ObjectTypeDefinitions[node.Ref].Directives.Refs - case NodeKindObjectTypeExtension: - return d.ObjectTypeExtensions[node.Ref].Directives.Refs - case NodeKindFieldDefinition: - return d.FieldDefinitions[node.Ref].Directives.Refs - case NodeKindInterfaceTypeDefinition: - return d.InterfaceTypeDefinitions[node.Ref].Directives.Refs - case NodeKindInterfaceTypeExtension: - return d.InterfaceTypeExtensions[node.Ref].Directives.Refs - case NodeKindInputObjectTypeDefinition: - return d.InputObjectTypeDefinitions[node.Ref].Directives.Refs - case NodeKindInputObjectTypeExtension: - return d.InputObjectTypeExtensions[node.Ref].Directives.Refs - case NodeKindScalarTypeDefinition: - return d.ScalarTypeDefinitions[node.Ref].Directives.Refs - case NodeKindScalarTypeExtension: - return d.ScalarTypeExtensions[node.Ref].Directives.Refs - case NodeKindUnionTypeDefinition: - return d.UnionTypeDefinitions[node.Ref].Directives.Refs - case NodeKindUnionTypeExtension: - return d.UnionTypeExtensions[node.Ref].Directives.Refs - case NodeKindEnumTypeDefinition: - return d.EnumTypeDefinitions[node.Ref].Directives.Refs - case NodeKindEnumTypeExtension: - return d.EnumTypeExtensions[node.Ref].Directives.Refs - case NodeKindFragmentDefinition: - return d.FragmentDefinitions[node.Ref].Directives.Refs - case NodeKindInputValueDefinition: - return d.InputValueDefinitions[node.Ref].Directives.Refs - case NodeKindEnumValueDefinition: - return d.EnumValueDefinitions[node.Ref].Directives.Refs - case NodeKindVariableDefinition: - return d.VariableDefinitions[node.Ref].Directives.Refs - case NodeKindOperationDefinition: - return d.OperationDefinitions[node.Ref].Directives.Refs - default: - return nil - } -} - -func (d *Document) RemoveDirectivesFromNode(node Node, directiveRefs []int) { - for _, ref := range directiveRefs { - d.RemoveDirectiveFromNode(node, ref) - } -} - -func (d *Document) RemoveDirectiveFromNode(node Node, directiveRef int) { - switch node.Kind { - case NodeKindFragmentSpread: - if i, ok := indexOf(d.FragmentSpreads[node.Ref].Directives.Refs, directiveRef); ok { - deleteRef(&d.FragmentSpreads[node.Ref].Directives.Refs, i) - d.FragmentSpreads[node.Ref].HasDirectives = len(d.FragmentSpreads[node.Ref].Directives.Refs) > 0 - } - case NodeKindInlineFragment: - if i, ok := indexOf(d.InlineFragments[node.Ref].Directives.Refs, directiveRef); ok { - deleteRef(&d.InlineFragments[node.Ref].Directives.Refs, i) - d.InlineFragments[node.Ref].HasDirectives = len(d.InlineFragments[node.Ref].Directives.Refs) > 0 - } - case NodeKindField: - if i, ok := indexOf(d.Fields[node.Ref].Directives.Refs, directiveRef); ok { - deleteRef(&d.Fields[node.Ref].Directives.Refs, i) - d.Fields[node.Ref].HasDirectives = len(d.Fields[node.Ref].Directives.Refs) > 0 - } - case NodeKindFieldDefinition: - if i, ok := indexOf(d.FieldDefinitions[node.Ref].Directives.Refs, directiveRef); ok { - deleteRef(&d.FieldDefinitions[node.Ref].Directives.Refs, i) - d.FieldDefinitions[node.Ref].HasDirectives = len(d.FieldDefinitions[node.Ref].Directives.Refs) > 0 - } - case NodeKindInterfaceTypeDefinition: - if i, ok := indexOf(d.InterfaceTypeDefinitions[node.Ref].Directives.Refs, directiveRef); ok { - deleteRef(&d.InterfaceTypeDefinitions[node.Ref].Directives.Refs, i) - d.InterfaceTypeDefinitions[node.Ref].HasDirectives = len(d.InterfaceTypeDefinitions[node.Ref].Directives.Refs) > 0 - } - case NodeKindObjectTypeDefinition: - if i, ok := indexOf(d.ObjectTypeDefinitions[node.Ref].Directives.Refs, directiveRef); ok { - deleteRef(&d.ObjectTypeDefinitions[node.Ref].Directives.Refs, i) - d.ObjectTypeDefinitions[node.Ref].HasDirectives = len(d.ObjectTypeDefinitions[node.Ref].Directives.Refs) > 0 - } - default: - log.Printf("RemoveDirectiveFromNode not implemented for node kind: %s", node.Kind) - } -} - -func (d *Document) NodeDirectiveLocation(node Node) (location DirectiveLocation, err error) { - switch node.Kind { - case NodeKindSchemaDefinition: - location = TypeSystemDirectiveLocationSchema - case NodeKindSchemaExtension: - location = TypeSystemDirectiveLocationSchema - case NodeKindObjectTypeDefinition: - location = TypeSystemDirectiveLocationObject - case NodeKindObjectTypeExtension: - location = TypeSystemDirectiveLocationObject - case NodeKindInterfaceTypeDefinition: - location = TypeSystemDirectiveLocationInterface - case NodeKindInterfaceTypeExtension: - location = TypeSystemDirectiveLocationInterface - case NodeKindUnionTypeDefinition: - location = TypeSystemDirectiveLocationUnion - case NodeKindUnionTypeExtension: - location = TypeSystemDirectiveLocationUnion - case NodeKindEnumTypeDefinition: - location = TypeSystemDirectiveLocationEnum - case NodeKindEnumTypeExtension: - location = TypeSystemDirectiveLocationEnum - case NodeKindInputObjectTypeDefinition: - location = TypeSystemDirectiveLocationInputObject - case NodeKindInputObjectTypeExtension: - location = TypeSystemDirectiveLocationInputObject - case NodeKindScalarTypeDefinition: - location = TypeSystemDirectiveLocationScalar - case NodeKindOperationDefinition: - switch d.OperationDefinitions[node.Ref].OperationType { - case OperationTypeQuery: - location = ExecutableDirectiveLocationQuery - case OperationTypeMutation: - location = ExecutableDirectiveLocationMutation - case OperationTypeSubscription: - location = ExecutableDirectiveLocationSubscription - } - case NodeKindField: - location = ExecutableDirectiveLocationField - case NodeKindFragmentSpread: - location = ExecutableDirectiveLocationFragmentSpread - case NodeKindInlineFragment: - location = ExecutableDirectiveLocationInlineFragment - case NodeKindFragmentDefinition: - location = ExecutableDirectiveLocationFragmentDefinition - case NodeKindVariableDefinition: - location = ExecutableDirectiveLocationVariableDefinition - default: - err = fmt.Errorf("node kind: %s is not allowed to have directives", node.Kind) - } - return -} - -// Node resolvers - -// NodeResolverTypeNameBytes returns lowercase query/mutation/subscription for Query/Mutation/Subscription -// for other type definitions it returns the default type name -func (d *Document) NodeResolverTypeNameBytes(node Node, path Path) ByteSlice { - if len(path) == 1 && path[0].Kind == FieldName { - return path[0].FieldName - } - switch node.Kind { - case NodeKindObjectTypeDefinition: - return d.ObjectTypeDefinitionNameBytes(node.Ref) - case NodeKindInterfaceTypeDefinition: - return d.InterfaceTypeDefinitionNameBytes(node.Ref) - case NodeKindUnionTypeDefinition: - return d.UnionTypeDefinitionNameBytes(node.Ref) - } - return nil -} - -func (d *Document) NodeResolverTypeNameString(node Node, path Path) string { - return unsafebytes.BytesToString(d.NodeResolverTypeNameBytes(node, path)) -} - -// Node field definitions - -func (d *Document) NodeFieldDefinitions(node Node) []int { - switch node.Kind { - case NodeKindObjectTypeDefinition: - return d.ObjectTypeDefinitions[node.Ref].FieldsDefinition.Refs - case NodeKindObjectTypeExtension: - return d.ObjectTypeExtensions[node.Ref].FieldsDefinition.Refs - case NodeKindInterfaceTypeDefinition: - return d.InterfaceTypeDefinitions[node.Ref].FieldsDefinition.Refs - case NodeKindInterfaceTypeExtension: - return d.InterfaceTypeExtensions[node.Ref].FieldsDefinition.Refs - case NodeKindUnionTypeDefinition: - return d.UnionTypeDefinitions[node.Ref].FieldsDefinition.Refs - default: - return nil - } -} - -func (d *Document) NodeInputFieldDefinitions(node Node) []int { - switch node.Kind { - case NodeKindInputObjectTypeDefinition: - return d.InputObjectTypeDefinitions[node.Ref].InputFieldsDefinition.Refs - default: - return nil - } -} - -func (d *Document) NodeInputFieldDefinitionByName(node Node, name ByteSlice) (int, bool) { - switch node.Kind { - case NodeKindInputObjectTypeDefinition: - refs := d.InputObjectTypeDefinitions[node.Ref].InputFieldsDefinition.Refs - for _, ref := range refs { - if bytes.Equal(d.Input.ByteSlice(d.InputValueDefinitions[ref].Name), name) { - return ref, true - } - } - } - return 0, false -} - -func (d *Document) NodeFieldDefinitionByName(node Node, fieldName ByteSlice) (definition int, exists bool) { - for _, i := range d.NodeFieldDefinitions(node) { - if bytes.Equal(d.Input.ByteSlice(d.FieldDefinitions[i].Name), fieldName) { - return i, true - } - } - return InvalidRef, false -} - -func (d *Document) NodeFieldDefinitionArgumentDefinitionByName(node Node, fieldName, argumentName ByteSlice) int { - fieldDefinition, exists := d.NodeFieldDefinitionByName(node, fieldName) - if !exists { - return -1 - } - argumentDefinitions := d.FieldDefinitionArgumentsDefinitions(fieldDefinition) - for _, i := range argumentDefinitions { - if bytes.Equal(argumentName, d.Input.ByteSlice(d.InputValueDefinitions[i].Name)) { - return i - } - } - return -1 -} - -func (d *Document) NodeFieldDefinitionArgumentsDefinitions(node Node, fieldName ByteSlice) []int { - fieldDefinition, exists := d.NodeFieldDefinitionByName(node, fieldName) - if !exists { - return nil - } - return d.FieldDefinitionArgumentsDefinitions(fieldDefinition) -} - -// Node input value definitions - -func (d *Document) NodeInputValueDefinitions(node Node) []int { - switch node.Kind { - case NodeKindInputObjectTypeDefinition: - return d.InputObjectTypeDefinitions[node.Ref].InputFieldsDefinition.Refs - case NodeKindInputObjectTypeExtension: - return d.InputObjectTypeExtensions[node.Ref].InputFieldsDefinition.Refs - case NodeKindFieldDefinition: - return d.FieldDefinitions[node.Ref].ArgumentsDefinition.Refs - case NodeKindDirectiveDefinition: - return d.DirectiveDefinitions[node.Ref].ArgumentsDefinition.Refs - default: - return nil - } -} - -func (d *Document) InputValueDefinitionIsFirst(inputValue int, ancestor Node) bool { - inputValues := d.NodeInputValueDefinitions(ancestor) - return inputValues != nil && inputValues[0] == inputValue -} - -func (d *Document) InputValueDefinitionIsLast(inputValue int, ancestor Node) bool { - inputValues := d.NodeInputValueDefinitions(ancestor) - return inputValues != nil && inputValues[len(inputValues)-1] == inputValue -} - -// Node misc - -func (d *Document) NodeImplementsInterface(node Node, interfaceNode Node) bool { - nodeFields := d.NodeFieldDefinitions(node) - interfaceFields := d.NodeFieldDefinitions(interfaceNode) - - for _, i := range interfaceFields { - interfaceFieldName := d.FieldDefinitionNameBytes(i) - if !d.FieldDefinitionsContainField(nodeFields, interfaceFieldName) { - return false - } - } - - return true -} - -func (d *Document) NodeIsUnionMember(node Node, union Node) bool { - nodeTypeName := d.NodeNameBytes(node) - for _, i := range d.UnionTypeDefinitions[union.Ref].UnionMemberTypes.Refs { - memberName := d.ResolveTypeNameBytes(i) - if bytes.Equal(nodeTypeName, memberName) { - return true - } - } - return false -} - -func (d *Document) NodeIsLastRootNode(node Node) bool { - if len(d.RootNodes) == 0 { - return false - } - for i := len(d.RootNodes) - 1; i >= 0; i-- { - if d.RootNodes[i].Kind == NodeKindUnknown { - continue - } - return d.RootNodes[i] == node - } - return false -} - -func (d *Document) RemoveNodeFromNode(remove, from Node) { - switch from.Kind { - case NodeKindSelectionSet: - d.RemoveNodeFromSelectionSet(from.Ref, remove) - default: - log.Printf("RemoveNodeFromNode not implemented for from: %s", from.Kind) - } -} - -func (d *Document) RemoveNodeFromSelectionSet(set int, node Node) { - var selectionKind SelectionKind - - switch node.Kind { - case NodeKindFragmentSpread: - selectionKind = SelectionKindFragmentSpread - case NodeKindInlineFragment: - selectionKind = SelectionKindInlineFragment - case NodeKindField: - selectionKind = SelectionKindField - default: - log.Printf("RemoveNodeFromSelectionSet not implemented for node: %s", node.Kind) - return - } - - for i, j := range d.SelectionSets[set].SelectionRefs { - if d.Selections[j].Kind == selectionKind && d.Selections[j].Ref == node.Ref { - d.SelectionSets[set].SelectionRefs = append(d.SelectionSets[set].SelectionRefs[:i], d.SelectionSets[set].SelectionRefs[i+1:]...) - return - } - } -} - -// NodeInterfaceRefs returns the interfaces implemented by the given node (this is -// only applicable to object kinds). -// Returns nil if node kind is not an object kind. -func (d *Document) NodeInterfaceRefs(node Node) (refs []int) { - switch node.Kind { - case NodeKindObjectTypeDefinition: - return d.ObjectTypeDefinitions[node.Ref].ImplementsInterfaces.Refs - case NodeKindObjectTypeExtension: - return d.ObjectTypeExtensions[node.Ref].ImplementsInterfaces.Refs - default: - return nil - } -} - -// NodeUnionMemberRefs returns the union members of the given node (this is only -// applicable to union kinds). -// Returns nil if node kind is not an object kind. -func (d *Document) NodeUnionMemberRefs(node Node) (refs []int) { - switch node.Kind { - case NodeKindUnionTypeDefinition: - return d.UnionTypeDefinitions[node.Ref].UnionMemberTypes.Refs - case NodeKindUnionTypeExtension: - return d.UnionTypeExtensions[node.Ref].UnionMemberTypes.Refs - default: - return nil - } -} - -// Node fragments - -func (d *Document) NodeFragmentIsAllowedOnNode(fragmentNode, onNode Node) bool { - switch onNode.Kind { - case NodeKindObjectTypeDefinition: - return d.NodeFragmentIsAllowedOnObjectTypeDefinition(fragmentNode, onNode) - case NodeKindInterfaceTypeDefinition: - return d.NodeFragmentIsAllowedOnInterfaceTypeDefinition(fragmentNode, onNode) - case NodeKindUnionTypeDefinition: - return d.NodeFragmentIsAllowedOnUnionTypeDefinition(fragmentNode, onNode) - default: - return false - } -} - -func (d *Document) NodeFragmentIsAllowedOnInterfaceTypeDefinition(fragmentNode, interfaceTypeNode Node) bool { - switch fragmentNode.Kind { - case NodeKindObjectTypeDefinition: - return d.NodeImplementsInterface(fragmentNode, interfaceTypeNode) - case NodeKindInterfaceTypeDefinition: - return bytes.Equal(d.InterfaceTypeDefinitionNameBytes(fragmentNode.Ref), d.InterfaceTypeDefinitionNameBytes(interfaceTypeNode.Ref)) - case NodeKindUnionTypeDefinition: - return d.UnionNodeIntersectsInterfaceNode(fragmentNode, interfaceTypeNode) - } - - return false -} - -func (d *Document) NodeFragmentIsAllowedOnUnionTypeDefinition(fragmentNode, unionTypeNode Node) bool { - switch fragmentNode.Kind { - case NodeKindObjectTypeDefinition: - return d.NodeIsUnionMember(fragmentNode, unionTypeNode) - case NodeKindInterfaceTypeDefinition: - return d.UnionNodeIntersectsInterfaceNode(unionTypeNode, fragmentNode) - case NodeKindUnionTypeDefinition: - return bytes.Equal(d.UnionTypeDefinitionNameBytes(fragmentNode.Ref), d.UnionTypeDefinitionNameBytes(unionTypeNode.Ref)) - } - - return false -} - -func (d *Document) NodeFragmentIsAllowedOnObjectTypeDefinition(fragmentNode, objectTypeNode Node) bool { - switch fragmentNode.Kind { - case NodeKindObjectTypeDefinition: - return bytes.Equal(d.ObjectTypeDefinitionNameBytes(fragmentNode.Ref), d.ObjectTypeDefinitionNameBytes(objectTypeNode.Ref)) - case NodeKindInterfaceTypeDefinition: - return d.NodeImplementsInterface(objectTypeNode, fragmentNode) - case NodeKindUnionTypeDefinition: - return d.NodeIsUnionMember(objectTypeNode, fragmentNode) - } - - return false -} - -func (d *Document) UnionNodeIntersectsInterfaceNode(unionNode, interfaceNode Node) bool { - for _, i := range d.UnionTypeDefinitions[unionNode.Ref].UnionMemberTypes.Refs { - memberName := d.ResolveTypeNameBytes(i) - node, exists := d.Index.FirstNodeByNameBytes(memberName) - if !exists { - continue - } - if node.Kind != NodeKindObjectTypeDefinition { - continue - } - if d.NodeImplementsInterface(node, interfaceNode) { - return true - } - } - return false -} diff --git a/pkg/ast/ast_node_kind.go b/pkg/ast/ast_node_kind.go deleted file mode 100644 index a278dbc53..000000000 --- a/pkg/ast/ast_node_kind.go +++ /dev/null @@ -1,90 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type NodeKind int - -const ( - NodeKindUnknown NodeKind = 22 + iota - NodeKindSchemaDefinition - NodeKindSchemaExtension - NodeKindObjectTypeDefinition - NodeKindObjectTypeExtension - NodeKindInterfaceTypeDefinition - NodeKindInterfaceTypeExtension - NodeKindUnionTypeDefinition - NodeKindUnionTypeExtension - NodeKindUnionMemberType - NodeKindEnumTypeDefinition - NodeKindEnumValueDefinition - NodeKindEnumTypeExtension - NodeKindInputObjectTypeDefinition - NodeKindInputValueDefinition - NodeKindInputObjectTypeExtension - NodeKindScalarTypeDefinition - NodeKindScalarTypeExtension - NodeKindDirectiveDefinition - NodeKindOperationDefinition - NodeKindSelectionSet - NodeKindField - NodeKindFieldDefinition - NodeKindFragmentSpread - NodeKindInlineFragment - NodeKindFragmentDefinition - NodeKindArgument - NodeKindDirective - NodeKindVariableDefinition -) - -func (n NodeKind) IsAbstractType() bool { - return n == NodeKindInterfaceTypeDefinition || n == NodeKindUnionTypeDefinition -} - -func (d *Document) NodeKindNameBytes(node Node) ByteSlice { - switch node.Kind { - case NodeKindOperationDefinition: - switch d.OperationDefinitions[node.Ref].OperationType { - case OperationTypeQuery: - return literal.LocationQuery - case OperationTypeMutation: - return literal.LocationMutation - case OperationTypeSubscription: - return literal.LocationSubscription - } - case NodeKindField: - return literal.LocationField - case NodeKindFragmentDefinition: - return literal.LocationFragmentDefinition - case NodeKindFragmentSpread: - return literal.LocationFragmentSpread - case NodeKindInlineFragment: - return literal.LocationInlineFragment - case NodeKindVariableDefinition: - return literal.LocationVariableDefinition - case NodeKindSchemaDefinition: - return literal.LocationSchema - case NodeKindScalarTypeDefinition: - return literal.LocationScalar - case NodeKindObjectTypeDefinition: - return literal.LocationObject - case NodeKindFieldDefinition: - return literal.LocationFieldDefinition - case NodeKindInterfaceTypeDefinition: - return literal.LocationInterface - case NodeKindUnionTypeDefinition: - return literal.LocationUnion - case NodeKindEnumTypeDefinition: - return literal.LocationEnum - case NodeKindEnumValueDefinition: - return literal.LocationEnumValue - case NodeKindInputObjectTypeDefinition: - return literal.LocationInputObject - case NodeKindInputValueDefinition: - return literal.LocationInputFieldDefinition - } - - return unsafebytes.StringToBytes(node.Kind.String()) -} diff --git a/pkg/ast/ast_node_kind_test.go b/pkg/ast/ast_node_kind_test.go deleted file mode 100644 index bbc632632..000000000 --- a/pkg/ast/ast_node_kind_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package ast - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestNodeKindIsAbstractType(t *testing.T) { - t.Run("Interface type returns true", func(t *testing.T) { - assert.Equal(t, NodeKindInterfaceTypeDefinition.IsAbstractType(), true) - }) - - t.Run("Union type returns true", func(t *testing.T) { - assert.Equal(t, NodeKindUnionTypeDefinition.IsAbstractType(), true) - }) - - t.Run("Enum type returns false", func(t *testing.T) { - assert.Equal(t, NodeKindEnumTypeDefinition.IsAbstractType(), false) - }) - - t.Run("Interface type returns false", func(t *testing.T) { - assert.Equal(t, NodeKindObjectTypeDefinition.IsAbstractType(), false) - }) - - t.Run("Scalar type returns false", func(t *testing.T) { - assert.Equal(t, NodeKindScalarTypeDefinition.IsAbstractType(), false) - }) -} diff --git a/pkg/ast/ast_object_field.go b/pkg/ast/ast_object_field.go deleted file mode 100644 index 75dcf77dc..000000000 --- a/pkg/ast/ast_object_field.go +++ /dev/null @@ -1,75 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// ObjectField -// example: -// lon: 12.43 -type ObjectField struct { - Name ByteSliceReference // e.g. lon - Colon position.Position // : - Value Value // e.g. 12.43 - Position position.Position -} - -func (d *Document) CopyObjectField(ref int) int { - return d.AddObjectField(ObjectField{ - Name: d.copyByteSliceReference(d.ObjectFields[ref].Name), - Value: Value{ - Kind: d.ObjectFields[ref].Value.Kind, - Ref: d.copyValueRef(d.ObjectFields[ref].Value.Kind, d.ObjectFields[ref].Value.Ref), - }, - }) -} - -func (d *Document) ObjectField(ref int) ObjectField { - return d.ObjectFields[ref] -} - -func (d *Document) ObjectFieldNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.ObjectFields[ref].Name) -} - -func (d *Document) ObjectFieldNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.ObjectFields[ref].Name)) -} - -func (d *Document) ObjectFieldValue(ref int) Value { - return d.ObjectFields[ref].Value -} - -func (d *Document) ObjectFieldsAreEqual(left, right int) bool { - return bytes.Equal(d.ObjectFieldNameBytes(left), d.ObjectFieldNameBytes(right)) && - d.ValuesAreEqual(d.ObjectFieldValue(left), d.ObjectFieldValue(right)) -} - -func (d *Document) ObjectValuesAreEqual(left, right int) bool { - leftFields, rightFields := d.ObjectValues[left].Refs, d.ObjectValues[right].Refs - if len(leftFields) != len(rightFields) { - return false - } - for i := 0; i < len(leftFields); i++ { - left, right = leftFields[i], rightFields[i] - if !d.ObjectFieldsAreEqual(left, right) { - return false - } - } - return true -} - -func (d *Document) AddObjectField(field ObjectField) (ref int) { - d.ObjectFields = append(d.ObjectFields, field) - return len(d.ObjectFields) - 1 -} - -func (d *Document) ImportObjectField(name ByteSlice, value Value) (ref int) { - return d.AddObjectField(ObjectField{ - Name: d.Input.AppendInputBytes(name), - Value: value, - }) -} diff --git a/pkg/ast/ast_object_type_definition.go b/pkg/ast/ast_object_type_definition.go deleted file mode 100644 index 37b86534b..000000000 --- a/pkg/ast/ast_object_type_definition.go +++ /dev/null @@ -1,119 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type TypeList struct { - Refs []int // Type -} - -type ObjectTypeDefinition struct { - Description Description // optional, e.g. "type Foo is ..." - TypeLiteral position.Position // type - Name ByteSliceReference // e.g. Foo - ImplementsInterfaces TypeList // e.g implements Bar & Baz - HasDirectives bool - Directives DirectiveList // e.g. @foo - HasFieldDefinitions bool - FieldsDefinition FieldDefinitionList // { foo:Bar bar(baz:String) } -} - -func (d *Document) ObjectTypeDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.ObjectTypeDefinitions[ref].Name) -} - -func (d *Document) ObjectTypeDefinitionNameRef(ref int) ByteSliceReference { - return d.ObjectTypeDefinitions[ref].Name -} - -func (d *Document) ObjectTypeDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.ObjectTypeDefinitions[ref].Name)) -} - -func (d *Document) ObjectTypeDescriptionNameBytes(ref int) ByteSlice { - if !d.ObjectTypeDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.ObjectTypeDefinitions[ref].Description.Content) -} - -func (d *Document) ObjectTypeDescriptionNameString(ref int) string { - return unsafebytes.BytesToString(d.ObjectTypeDescriptionNameBytes(ref)) -} - -func (d *Document) ObjectTypeDefinitionHasField(ref int, fieldName []byte) bool { - for _, fieldDefinitionRef := range d.ObjectTypeDefinitions[ref].FieldsDefinition.Refs { - currentFieldName := d.FieldDefinitionNameBytes(fieldDefinitionRef) - if currentFieldName.Equals(fieldName) { - return true - } - } - return false -} - -func (d *Document) ObjectTypeDefinitionImplementsInterface(definitionRef int, interfaceName ByteSlice) bool { - for _, iRef := range d.ObjectTypeDefinitions[definitionRef].ImplementsInterfaces.Refs { - implements := d.ResolveTypeNameBytes(iRef) - if bytes.Equal(interfaceName, implements) { - return true - } - } - return false -} - -func (d *Document) AddObjectTypeDefinition(definition ObjectTypeDefinition) (ref int) { - d.ObjectTypeDefinitions = append(d.ObjectTypeDefinitions, definition) - return len(d.ObjectTypeDefinitions) - 1 -} - -func (d *Document) ImportObjectTypeDefinition(name, description string, fieldRefs []int, iRefs []int) (ref int) { - return d.ImportObjectTypeDefinitionWithDirectives(name, description, fieldRefs, iRefs, nil) -} - -func (d *Document) ImportObjectTypeDefinitionWithDirectives(name, description string, fieldRefs []int, iRefs []int, directiveRefs []int) (ref int) { - definition := ObjectTypeDefinition{ - Name: d.Input.AppendInputString(name), - Description: d.ImportDescription(description), - FieldsDefinition: FieldDefinitionList{ - Refs: fieldRefs, - }, - HasFieldDefinitions: len(fieldRefs) > 0, - ImplementsInterfaces: TypeList{ - Refs: iRefs, - }, - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - } - - ref = d.AddObjectTypeDefinition(definition) - d.ImportRootNode(ref, NodeKindObjectTypeDefinition) - - return -} - -func (d *Document) RemoveObjectTypeDefinition(name ByteSlice) bool { - node, ok := d.Index.FirstNodeByNameBytes(name) - if !ok { - return false - } - - if node.Kind != NodeKindObjectTypeDefinition { - return false - } - - for i := range d.RootNodes { - if d.RootNodes[i].Kind == NodeKindObjectTypeDefinition && d.RootNodes[i].Ref == node.Ref { - d.RootNodes = append(d.RootNodes[:i], d.RootNodes[i+1:]...) - break - } - } - - d.Index.RemoveNodeByName(name) - return true -} diff --git a/pkg/ast/ast_object_type_definition_test.go b/pkg/ast/ast_object_type_definition_test.go deleted file mode 100644 index c006d0d78..000000000 --- a/pkg/ast/ast_object_type_definition_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package ast_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func TestDocument_RemoveObjectTypeDefinition(t *testing.T) { - schema := "type Query {queryName: String} type Mutation {mutationName: String} type Country {code: String} interface Model {id: String}" - - prepareDoc := func() *ast.Document { - doc := unsafeparser.ParseGraphqlDocumentString(schema) - return &doc - } - - t.Run("doc remains same when", func(t *testing.T) { - t.Run("try to remove not existing type", func(t *testing.T) { - doc := prepareDoc() - doc.RemoveObjectTypeDefinition([]byte("NotExisting")) - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, schema, docStr) - }) - - t.Run("try to remove interface type", func(t *testing.T) { - doc := prepareDoc() - doc.RemoveObjectTypeDefinition([]byte("Model")) - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, schema, docStr) - }) - }) - - t.Run("remove query type", func(t *testing.T) { - doc := prepareDoc() - doc.RemoveObjectTypeDefinition(ast.DefaultQueryTypeName) - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, "type Mutation {mutationName: String} type Country {code: String} interface Model {id: String}", docStr) - }) - - t.Run("remove query and mutations types", func(t *testing.T) { - doc := prepareDoc() - doc.RemoveObjectTypeDefinition(ast.DefaultQueryTypeName) - doc.RemoveObjectTypeDefinition(ast.DefaultMutationTypeName) - - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, "type Country {code: String} interface Model {id: String}", docStr) - }) - - t.Run("remove all types", func(t *testing.T) { - doc := prepareDoc() - doc.RemoveObjectTypeDefinition(ast.DefaultQueryTypeName) - doc.RemoveObjectTypeDefinition(ast.DefaultMutationTypeName) - doc.RemoveObjectTypeDefinition([]byte("Country")) - - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, "interface Model {id: String}", docStr) - }) - -} diff --git a/pkg/ast/ast_object_type_extension.go b/pkg/ast/ast_object_type_extension.go deleted file mode 100644 index bd7e1e8a0..000000000 --- a/pkg/ast/ast_object_type_extension.go +++ /dev/null @@ -1,75 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type ObjectTypeExtension struct { - ExtendLiteral position.Position - ObjectTypeDefinition -} - -func (d *Document) ObjectTypeExtensionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.ObjectTypeExtensions[ref].Name) -} - -func (d *Document) ObjectTypeExtensionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.ObjectTypeExtensions[ref].Name)) -} - -func (d *Document) ObjectTypeExtensionDescriptionNameBytes(ref int) ByteSlice { - if !d.ObjectTypeExtensions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.ObjectTypeExtensions[ref].Description.Content) -} - -func (d *Document) ObjectTypeExtensionDescriptionNameString(ref int) string { - return unsafebytes.BytesToString(d.ObjectTypeExtensionDescriptionNameBytes(ref)) -} - -func (d *Document) ObjectTypeExtensionHasFieldDefinitions(ref int) bool { - return d.ObjectTypeExtensions[ref].HasFieldDefinitions -} - -func (d *Document) ObjectTypeExtensionHasDirectives(ref int) bool { - return d.ObjectTypeExtensions[ref].HasDirectives -} - -func (d *Document) ExtendObjectTypeDefinitionByObjectTypeExtension(objectTypeDefinitionRef, objectTypeExtensionRef int) { - if d.ObjectTypeExtensionHasFieldDefinitions(objectTypeExtensionRef) { - d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs = append(d.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, d.ObjectTypeExtensions[objectTypeExtensionRef].FieldsDefinition.Refs...) - d.ObjectTypeDefinitions[objectTypeDefinitionRef].HasFieldDefinitions = true - } - - if d.ObjectTypeExtensionHasDirectives(objectTypeExtensionRef) { - d.ObjectTypeDefinitions[objectTypeDefinitionRef].Directives.Refs = append(d.ObjectTypeDefinitions[objectTypeDefinitionRef].Directives.Refs, d.ObjectTypeExtensions[objectTypeExtensionRef].Directives.Refs...) - d.ObjectTypeDefinitions[objectTypeDefinitionRef].HasDirectives = true - } - - if len(d.ObjectTypeExtensions[objectTypeExtensionRef].ImplementsInterfaces.Refs) > 0 { - d.ObjectTypeDefinitions[objectTypeDefinitionRef].ImplementsInterfaces.Refs = append( - d.ObjectTypeDefinitions[objectTypeDefinitionRef].ImplementsInterfaces.Refs, - d.ObjectTypeExtensions[objectTypeExtensionRef].ImplementsInterfaces.Refs..., - ) - } - - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: objectTypeExtensionRef, Kind: NodeKindObjectTypeExtension}) -} - -func (d *Document) ImportAndExtendObjectTypeDefinitionByObjectTypeExtension(objectTypeExtensionRef int) { - d.ImportObjectTypeDefinitionWithDirectives( - d.ObjectTypeExtensionNameBytes(objectTypeExtensionRef).String(), - d.ObjectTypeExtensionDescriptionNameString(objectTypeExtensionRef), - d.ObjectTypeExtensions[objectTypeExtensionRef].FieldsDefinition.Refs, - d.ObjectTypeExtensions[objectTypeExtensionRef].ImplementsInterfaces.Refs, - d.ObjectTypeExtensions[objectTypeExtensionRef].Directives.Refs, - ) - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: objectTypeExtensionRef, Kind: NodeKindObjectTypeExtension}) -} - -func (d *Document) AddObjectTypeDefinitionExtension(extension ObjectTypeExtension) (ref int) { - d.ObjectTypeExtensions = append(d.ObjectTypeExtensions, extension) - return len(d.ObjectTypeExtensions) - 1 -} diff --git a/pkg/ast/ast_operation_definition.go b/pkg/ast/ast_operation_definition.go deleted file mode 100644 index f53255203..000000000 --- a/pkg/ast/ast_operation_definition.go +++ /dev/null @@ -1,143 +0,0 @@ -package ast - -import ( - "fmt" - "math" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type OperationType int - -const ( - OperationTypeUnknown OperationType = iota - OperationTypeQuery - OperationTypeMutation - OperationTypeSubscription -) - -// Name returns a human-readable operation name for the given OperationType. -// If the operation is not one of the OperationType constants, it panics. -func (t OperationType) Name() string { - switch t { - case OperationTypeUnknown: - return "unknown" - case OperationTypeQuery: - return "query" - case OperationTypeMutation: - return "mutation" - case OperationTypeSubscription: - return "subscription" - } - panic(fmt.Errorf("unknown operation type %d", int(t))) -} - -type OperationDefinition struct { - OperationType OperationType // one of query, mutation, subscription - OperationTypeLiteral position.Position // position of the operation type literal, if present - Name ByteSliceReference // optional, user defined name of the operation - HasVariableDefinitions bool - VariableDefinitions VariableDefinitionList // optional, e.g. ($devicePicSize: Int) - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - SelectionSet int // e.g. {field} - HasSelections bool -} - -func (d *Document) OperationDefinitionHasVariableDefinition(ref int, variableName string) bool { - for _, i := range d.OperationDefinitions[ref].VariableDefinitions.Refs { - value := d.VariableDefinitions[i].VariableValue.Ref - if variableName == d.VariableValueNameString(value) { - return true - } - } - return false -} - -func (d *Document) OperationDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.OperationDefinitions[ref].Name) -} - -func (d *Document) OperationDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.OperationDefinitions[ref].Name)) -} - -func (d *Document) AddOperationDefinitionToRootNodes(definition OperationDefinition) Node { - d.OperationDefinitions = append(d.OperationDefinitions, definition) - node := Node{Kind: NodeKindOperationDefinition, Ref: len(d.OperationDefinitions) - 1} - d.RootNodes = append(d.RootNodes, node) - return node -} - -func (d *Document) AddVariableDefinitionToOperationDefinition(operationDefinitionRef, variableValueRef, typeRef int) { - if !d.OperationDefinitions[operationDefinitionRef].HasVariableDefinitions { - d.OperationDefinitions[operationDefinitionRef].HasVariableDefinitions = true - d.OperationDefinitions[operationDefinitionRef].VariableDefinitions.Refs = d.Refs[d.NextRefIndex()][:0] - } - variableDefinition := VariableDefinition{ - VariableValue: Value{ - Kind: ValueKindVariable, - Ref: variableValueRef, - }, - Type: typeRef, - } - d.VariableDefinitions = append(d.VariableDefinitions, variableDefinition) - ref := len(d.VariableDefinitions) - 1 - d.OperationDefinitions[operationDefinitionRef].VariableDefinitions.Refs = - append(d.OperationDefinitions[operationDefinitionRef].VariableDefinitions.Refs, ref) -} - -func (d *Document) AddImportedVariableDefinitionToOperationDefinition(operationDefinition, variableDefinition int) { - if !d.OperationDefinitions[operationDefinition].HasVariableDefinitions { - d.OperationDefinitions[operationDefinition].HasVariableDefinitions = true - d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs = d.Refs[d.NextRefIndex()][:0] - } - d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs = - append(d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs, variableDefinition) -} - -func (d *Document) OperationNameExists(operationName string) bool { - for i := range d.RootNodes { - if d.RootNodes[i].Kind != NodeKindOperationDefinition { - continue - } - if d.OperationDefinitionNameString(d.RootNodes[i].Ref) == operationName { - return true - } - } - - return false -} - -func (d *Document) NumOfOperationDefinitions() (n int) { - for i := range d.RootNodes { - if d.RootNodes[i].Kind == NodeKindOperationDefinition { - n++ - } - } - return -} - -const ( - alphabet = `abcdefghijklmnopqrstuvwxyz` -) - -func (d *Document) GenerateUnusedVariableDefinitionName(operationDefinition int) []byte { - var i, k int64 - - for i = 1; i < math.MaxInt64; i++ { - out := make([]byte, i) - for j := range alphabet { - for k = 0; k < i; k++ { - out[k] = alphabet[j] - } - _, exists := d.VariableDefinitionByNameAndOperation(operationDefinition, out) - if !exists { - return out - } - } - } - - return nil -} diff --git a/pkg/ast/ast_operation_definition_test.go b/pkg/ast/ast_operation_definition_test.go deleted file mode 100644 index 57017c85a..000000000 --- a/pkg/ast/ast_operation_definition_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package ast_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func TestDocument_OperationNameExists(t *testing.T) { - run := func(schema string, operationName string, expectedExists bool) func(t *testing.T) { - return func(t *testing.T) { - doc := unsafeparser.ParseGraphqlDocumentString(schema) - exists := doc.OperationNameExists(operationName) - assert.Equal(t, expectedExists, exists) - } - } - - t.Run("not found on empty document", run( - "", - "MyOperation", - false, - )) - - t.Run("not found on document with multiple operations", run( - "query OtherOperation {other} query AnotherOperation {another}", - "MyOperation", - false, - )) - - t.Run("found on document with a single operations", run( - "query MyOperation {}", - "MyOperation", - true, - )) - - t.Run("found on document with multiple operations", run( - "query OtherOperation {other} query AnotherOperation {another} query MyOperation {}", - "MyOperation", - true, - )) - - t.Run("found on a document with preceeding root nodes of not operation type", run( - "fragment F on T {field} query MyOperation {}", - "MyOperation", - true, - )) -} diff --git a/pkg/ast/ast_root_operation_type_definition.go b/pkg/ast/ast_root_operation_type_definition.go deleted file mode 100644 index 0f252dbc8..000000000 --- a/pkg/ast/ast_root_operation_type_definition.go +++ /dev/null @@ -1,148 +0,0 @@ -package ast - -import ( - "bytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -var DefaultQueryTypeName = []byte("Query") -var DefaultMutationTypeName = []byte("Mutation") -var DefaultSubscriptionTypeName = []byte("Subscription") - -type RootOperationTypeDefinitionList struct { - LBrace position.Position // { - Refs []int // RootOperationTypeDefinition - RBrace position.Position // } -} - -type RootOperationTypeDefinition struct { - OperationType OperationType // one of query, mutation, subscription - Colon position.Position // : - NamedType Type // e.g. Query -} - -func (d *Document) RootOperationTypeDefinitionNameString(ref int) string { - return d.RootOperationTypeDefinitions[ref].OperationType.String() -} - -func (d *Document) RootOperationTypeDefinitionIsFirstInSchemaDefinition(ref int, ancestor Node) bool { - switch ancestor.Kind { - case NodeKindSchemaDefinition: - if len(d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs) == 0 { - return false - } - return ref == d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs[0] - case NodeKindSchemaExtension: - if len(d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs) == 0 { - return false - } - return ref == d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs[0] - default: - return false - } -} - -func (d *Document) RootOperationTypeDefinitionIsLastInSchemaDefinition(ref int, ancestor Node) bool { - switch ancestor.Kind { - case NodeKindSchemaDefinition: - return d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs[len(d.SchemaDefinitions[ancestor.Ref].RootOperationTypeDefinitions.Refs)-1] == ref - case NodeKindSchemaExtension: - return d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs[len(d.SchemaExtensions[ancestor.Ref].RootOperationTypeDefinitions.Refs)-1] == ref - default: - return false - } -} - -func (d *Document) CreateRootOperationTypeDefinition(operationType OperationType, rootNodeRef int) (ref int) { - switch operationType { - case OperationTypeQuery: - d.Index.QueryTypeName = DefaultQueryTypeName - case OperationTypeMutation: - d.Index.MutationTypeName = DefaultMutationTypeName - case OperationTypeSubscription: - d.Index.SubscriptionTypeName = DefaultSubscriptionTypeName - default: - return - } - - nameRef := d.ObjectTypeDefinitionNameRef(d.RootNodes[rootNodeRef].Ref) - return d.AddRootOperationTypeDefinition(RootOperationTypeDefinition{ - OperationType: operationType, - NamedType: Type{ - TypeKind: TypeKindNamed, - Name: nameRef, - OfType: -1, - }, - }) -} - -func (d *Document) AddRootOperationTypeDefinition(rootOperationTypeDefinition RootOperationTypeDefinition) (ref int) { - d.RootOperationTypeDefinitions = append(d.RootOperationTypeDefinitions, rootOperationTypeDefinition) - return len(d.RootOperationTypeDefinitions) - 1 -} - -func (d *Document) ImportRootOperationTypeDefinition(name string, operationType OperationType) (ref int) { - nameBytes := []byte(name) - - switch operationType { - case OperationTypeQuery: - d.Index.QueryTypeName = nameBytes - case OperationTypeMutation: - d.Index.MutationTypeName = nameBytes - case OperationTypeSubscription: - d.Index.SubscriptionTypeName = nameBytes - default: - return -1 - } - - operationTypeDefinition := RootOperationTypeDefinition{ - OperationType: operationType, - NamedType: Type{ - Name: d.Input.AppendInputBytes(nameBytes), - TypeKind: TypeKindNamed, - OfType: -1, - }, - } - - return d.AddRootOperationTypeDefinition(operationTypeDefinition) -} - -func (d *Document) ImportRootOperationTypeDefinitions(queryTypeName, mutationTypeName, subscriptionTypeName string) (refs []int) { - if queryTypeName != "" { - refs = append(refs, d.ImportRootOperationTypeDefinition(queryTypeName, OperationTypeQuery)) - } - if mutationTypeName != "" { - refs = append(refs, d.ImportRootOperationTypeDefinition(mutationTypeName, OperationTypeMutation)) - } - if subscriptionTypeName != "" { - refs = append(refs, d.ImportRootOperationTypeDefinition(subscriptionTypeName, OperationTypeSubscription)) - } - - return refs -} - -func (d *Document) ReplaceRootOperationTypeDefinition(name string, operationType OperationType) (ref int, ok bool) { - node, exists := d.NodeByNameStr(name) - if !exists || node.Kind != NodeKindObjectTypeDefinition { - return -1, false - } - - var rootOperationFound bool - for i := range d.RootOperationTypeDefinitions { - if d.RootOperationTypeDefinitions[i].OperationType == operationType { - d.RootOperationTypeDefinitions = append(d.RootOperationTypeDefinitions[:i], d.RootOperationTypeDefinitions[i+1:]...) - rootOperationFound = true - break - } - } - if !rootOperationFound { - return -1, false - } - - ref = d.ImportRootOperationTypeDefinition(name, operationType) - return ref, true -} - -func IsRootType(nameBytes []byte) bool { - return bytes.Equal(DefaultQueryTypeName, nameBytes) || bytes.Equal(DefaultMutationTypeName, nameBytes) || bytes.Equal(DefaultSubscriptionTypeName, nameBytes) -} diff --git a/pkg/ast/ast_root_operation_type_definition_test.go b/pkg/ast/ast_root_operation_type_definition_test.go deleted file mode 100644 index cc254622e..000000000 --- a/pkg/ast/ast_root_operation_type_definition_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package ast_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func TestDocument_ReplaceRootOperationTypeDefinition(t *testing.T) { - schema := "schema {query: Query} type Query {queryName: String} type Country {code: String} interface Model {id: String}" - - prepareDoc := func() *ast.Document { - doc := unsafeparser.ParseGraphqlDocumentString(schema) - return &doc - } - - t.Run("should replace query type with existing type", func(t *testing.T) { - doc := prepareDoc() - ref, ok := doc.ReplaceRootOperationTypeDefinition("Country", ast.OperationTypeQuery) - assert.NotEqual(t, -1, ref) - assert.True(t, ok) - - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, "schema {query: Country} type Query {queryName: String} type Country {code: String} interface Model {id: String}", docStr) - }) - - t.Run("should not modify document", func(t *testing.T) { - t.Run("when replacing query type with not existing type", func(t *testing.T) { - doc := prepareDoc() - ref, ok := doc.ReplaceRootOperationTypeDefinition("NotExisting", ast.OperationTypeQuery) - assert.Equal(t, -1, ref) - assert.False(t, ok) - - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, schema, docStr) - }) - - t.Run("when replacing query type with not an object type", func(t *testing.T) { - doc := prepareDoc() - ref, ok := doc.ReplaceRootOperationTypeDefinition("Model", ast.OperationTypeQuery) - assert.Equal(t, -1, ref) - assert.False(t, ok) - - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, schema, docStr) - }) - - t.Run("when replacing mutation which was not defined", func(t *testing.T) { - doc := prepareDoc() - ref, ok := doc.ReplaceRootOperationTypeDefinition("Country", ast.OperationTypeMutation) - assert.Equal(t, -1, ref) - assert.False(t, ok) - - docStr, _ := astprinter.PrintString(doc, nil) - assert.Equal(t, schema, docStr) - }) - }) -} diff --git a/pkg/ast/ast_scalar_type_definition.go b/pkg/ast/ast_scalar_type_definition.go deleted file mode 100644 index eccc932f7..000000000 --- a/pkg/ast/ast_scalar_type_definition.go +++ /dev/null @@ -1,65 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// ScalarTypeDefinition -// example: -// scalar JSON -type ScalarTypeDefinition struct { - Description Description // optional, describes the scalar - ScalarLiteral position.Position // scalar - Name ByteSliceReference // e.g. JSON - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo -} - -func (d *Document) ScalarTypeDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.ScalarTypeDefinitions[ref].Name) -} - -func (d *Document) ScalarTypeDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.ScalarTypeDefinitions[ref].Name)) -} - -func (d *Document) ScalarTypeDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.ScalarTypeDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.ScalarTypeDefinitions[ref].Description.Content) -} - -func (d *Document) ScalarTypeDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.ScalarTypeDefinitionDescriptionBytes(ref)) -} - -func (d *Document) ScalarTypeDefinitionHasDirectives(ref int) bool { - return d.ScalarTypeDefinitions[ref].HasDirectives -} - -func (d *Document) AddScalarTypeDefinition(definition ScalarTypeDefinition) (ref int) { - d.ScalarTypeDefinitions = append(d.ScalarTypeDefinitions, definition) - return len(d.ScalarTypeDefinitions) - 1 -} - -func (d *Document) ImportScalarTypeDefinition(name, description string) (ref int) { - return d.ImportScalarTypeDefinitionWithDirectives(name, description, nil) -} - -func (d *Document) ImportScalarTypeDefinitionWithDirectives(name, description string, directiveRefs []int) (ref int) { - definition := ScalarTypeDefinition{ - Description: d.ImportDescription(description), - Name: d.Input.AppendInputString(name), - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - } - - ref = d.AddScalarTypeDefinition(definition) - d.ImportRootNode(ref, NodeKindScalarTypeDefinition) - - return -} diff --git a/pkg/ast/ast_scalar_type_extension.go b/pkg/ast/ast_scalar_type_extension.go deleted file mode 100644 index 5033dbf9a..000000000 --- a/pkg/ast/ast_scalar_type_extension.go +++ /dev/null @@ -1,52 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type ScalarTypeExtension struct { - ExtendLiteral position.Position - ScalarTypeDefinition -} - -func (d *Document) ScalarTypeExtensionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.ScalarTypeExtensions[ref].Name) -} - -func (d *Document) ScalarTypeExtensionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.ScalarTypeExtensions[ref].Name)) -} - -func (d *Document) ScalarTypeExtensionDescriptionBytes(ref int) ByteSlice { - if !d.ScalarTypeExtensions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.ScalarTypeExtensions[ref].Description.Content) -} - -func (d *Document) ScalarTypeExtensionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.ScalarTypeExtensionDescriptionBytes(ref)) -} - -func (d *Document) ScalarTypeExtensionHasDirectives(ref int) bool { - return d.ScalarTypeExtensions[ref].HasDirectives -} - -func (d *Document) ExtendScalarTypeDefinitionByScalarTypeExtension(scalarTypeDefinitionRef, scalarTypeExtensionRef int) { - if d.ScalarTypeExtensionHasDirectives(scalarTypeExtensionRef) { - d.ScalarTypeDefinitions[scalarTypeDefinitionRef].Directives.Refs = append(d.ScalarTypeDefinitions[scalarTypeDefinitionRef].Directives.Refs, d.ScalarTypeExtensions[scalarTypeExtensionRef].Directives.Refs...) - d.ScalarTypeDefinitions[scalarTypeDefinitionRef].HasDirectives = true - } - - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: scalarTypeExtensionRef, Kind: NodeKindScalarTypeExtension}) -} - -func (d *Document) ImportAndExtendScalarTypeDefinitionByScalarTypeExtension(scalarTypeExtensionRef int) { - d.ImportScalarTypeDefinitionWithDirectives( - d.ScalarTypeExtensionNameString(scalarTypeExtensionRef), - d.ScalarTypeExtensionDescriptionString(scalarTypeExtensionRef), - d.ScalarTypeExtensions[scalarTypeExtensionRef].Directives.Refs, - ) - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: scalarTypeExtensionRef, Kind: NodeKindScalarTypeExtension}) -} diff --git a/pkg/ast/ast_schema_definition.go b/pkg/ast/ast_schema_definition.go deleted file mode 100644 index ffa842f02..000000000 --- a/pkg/ast/ast_schema_definition.go +++ /dev/null @@ -1,60 +0,0 @@ -package ast - -import "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - -type SchemaDefinition struct { - SchemaLiteral position.Position // schema - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - RootOperationTypeDefinitions RootOperationTypeDefinitionList // e.g. query: Query, mutation: Mutation, subscription: Subscription -} - -func (s *SchemaDefinition) AddRootOperationTypeDefinitionRefs(refs ...int) { - s.RootOperationTypeDefinitions.Refs = append(s.RootOperationTypeDefinitions.Refs, refs...) -} - -func (d *Document) HasSchemaDefinition() bool { - return d.SchemaDefinitionRef() != InvalidRef -} - -func (d *Document) SchemaDefinitionRef() int { - for i := range d.RootNodes { - if d.RootNodes[i].Kind == NodeKindSchemaDefinition { - return d.RootNodes[i].Ref - } - } - - return InvalidRef -} - -func (d *Document) AddSchemaDefinition(schemaDefinition SchemaDefinition) (ref int) { - d.SchemaDefinitions = append(d.SchemaDefinitions, schemaDefinition) - return len(d.SchemaDefinitions) - 1 -} - -func (d *Document) AddSchemaDefinitionRootNode(schemaDefinition SchemaDefinition) { - ref := d.AddSchemaDefinition(schemaDefinition) - schemaNode := Node{ - Kind: NodeKindSchemaDefinition, - Ref: ref, - } - d.RootNodes = append([]Node{schemaNode}, d.RootNodes...) -} - -func (d *Document) ImportSchemaDefinition(queryTypeName, mutationTypeName, subscriptionTypeName string) { - rootOperationTypeRefs := d.ImportRootOperationTypeDefinitions(queryTypeName, mutationTypeName, subscriptionTypeName) - - schemaDefinition := SchemaDefinition{ - RootOperationTypeDefinitions: RootOperationTypeDefinitionList{ - Refs: rootOperationTypeRefs, - }, - } - - d.AddSchemaDefinitionRootNode(schemaDefinition) -} - -func (d *Document) ReplaceRootOperationTypesOfSchemaDefinition(schemaDefinitionRef int, queryTypeName, mutationTypeName, subscriptionTypeName string) { - d.RootOperationTypeDefinitions = d.RootOperationTypeDefinitions[:0] - rootOperationTypeRefs := d.ImportRootOperationTypeDefinitions(queryTypeName, mutationTypeName, subscriptionTypeName) - d.SchemaDefinitions[schemaDefinitionRef].RootOperationTypeDefinitions.Refs = rootOperationTypeRefs -} diff --git a/pkg/ast/ast_schema_extension.go b/pkg/ast/ast_schema_extension.go deleted file mode 100644 index b74122bdd..000000000 --- a/pkg/ast/ast_schema_extension.go +++ /dev/null @@ -1,8 +0,0 @@ -package ast - -import "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - -type SchemaExtension struct { - ExtendLiteral position.Position - SchemaDefinition -} diff --git a/pkg/ast/ast_selection.go b/pkg/ast/ast_selection.go deleted file mode 100644 index 61bae0bf5..000000000 --- a/pkg/ast/ast_selection.go +++ /dev/null @@ -1,181 +0,0 @@ -package ast - -import ( - "bytes" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type SelectionKind int - -const ( - SelectionKindUnknown SelectionKind = 18 + iota - SelectionKindField - SelectionKindFragmentSpread - SelectionKindInlineFragment -) - -type SelectionSet struct { - LBrace position.Position - RBrace position.Position - SelectionRefs []int -} - -type Selection struct { - Kind SelectionKind // one of Field, FragmentSpread, InlineFragment - Ref int // reference to the actual selection -} - -func (d *Document) CopySelection(ref int) int { - innerRef := -1 - - switch d.Selections[ref].Kind { - case SelectionKindField: - innerRef = d.CopyField(d.Selections[ref].Ref) - case SelectionKindFragmentSpread: - innerRef = d.CopyFragmentSpread(d.Selections[ref].Ref) - case SelectionKindInlineFragment: - innerRef = d.CopyInlineFragment(d.Selections[ref].Ref) - } - - return d.AddSelectionToDocument(Selection{ - Kind: d.Selections[ref].Kind, - Ref: innerRef, - }) -} - -func (d *Document) CopySelectionSet(ref int) int { - refs := d.NewEmptyRefs() - for _, r := range d.SelectionSets[ref].SelectionRefs { - refs = append(refs, d.CopySelection(r)) - } - return d.AddSelectionSetToDocument(SelectionSet{ - SelectionRefs: refs, - }) -} - -func (d *Document) PrintSelections(selections []int) (out string) { - out += "[" - for i, ref := range selections { - out += fmt.Sprintf("%+v", d.Selections[ref]) - if i != len(selections)-1 { - out += "," - } - } - out += "]" - return -} - -func (d *Document) SelectionsBeforeField(field int, selectionSet Node) bool { - if selectionSet.Kind != NodeKindSelectionSet { - return false - } - - if len(d.SelectionSets[selectionSet.Ref].SelectionRefs) == 1 { - return false - } - - for i, j := range d.SelectionSets[selectionSet.Ref].SelectionRefs { - if d.Selections[j].Kind == SelectionKindField && d.Selections[j].Ref == field { - return i != 0 - } - } - - return false -} - -func (d *Document) SelectionsAfter(selectionKind SelectionKind, selectionRef int, selectionSet Node) bool { - if selectionSet.Kind != NodeKindSelectionSet { - return false - } - - if len(d.SelectionSets[selectionSet.Ref].SelectionRefs) == 1 { - return false - } - - for i, j := range d.SelectionSets[selectionSet.Ref].SelectionRefs { - if d.Selections[j].Kind == selectionKind && d.Selections[j].Ref == selectionRef { - return i != len(d.SelectionSets[selectionSet.Ref].SelectionRefs)-1 - } - } - - return false -} - -func (d *Document) SelectionsAfterField(field int, selectionSet Node) bool { - return d.SelectionsAfter(SelectionKindField, field, selectionSet) -} - -func (d *Document) SelectionsAfterInlineFragment(inlineFragment int, selectionSet Node) bool { - return d.SelectionsAfter(SelectionKindInlineFragment, inlineFragment, selectionSet) -} - -func (d *Document) SelectionsAfterFragmentSpread(fragmentSpread int, selectionSet Node) bool { - return d.SelectionsAfter(SelectionKindFragmentSpread, fragmentSpread, selectionSet) -} - -func (d *Document) AddSelectionSetToDocument(set SelectionSet) int { - d.SelectionSets = append(d.SelectionSets, set) - return len(d.SelectionSets) - 1 -} - -func (d *Document) AddSelectionSet() Node { - return Node{ - Kind: NodeKindSelectionSet, - Ref: d.AddSelectionSetToDocument(SelectionSet{ - SelectionRefs: d.Refs[d.NextRefIndex()][:0], - }), - } -} - -func (d *Document) AddSelectionToDocument(selection Selection) int { - d.Selections = append(d.Selections, selection) - return len(d.Selections) - 1 -} - -func (d *Document) AddSelection(set int, selection Selection) { - d.SelectionSets[set].SelectionRefs = append(d.SelectionSets[set].SelectionRefs, d.AddSelectionToDocument(selection)) -} - -func (d *Document) EmptySelectionSet(ref int) { - d.SelectionSets[ref].SelectionRefs = d.SelectionSets[ref].SelectionRefs[:0] -} - -func (d *Document) AppendSelectionSet(ref int, appendRef int) { - d.SelectionSets[ref].SelectionRefs = append(d.SelectionSets[ref].SelectionRefs, d.SelectionSets[appendRef].SelectionRefs...) -} - -func (d *Document) ReplaceSelectionOnSelectionSet(ref, replace, with int) { - d.SelectionSets[ref].SelectionRefs = append(d.SelectionSets[ref].SelectionRefs[:replace], append(d.SelectionSets[with].SelectionRefs, d.SelectionSets[ref].SelectionRefs[replace+1:]...)...) -} - -func (d *Document) RemoveFromSelectionSet(ref int, index int) { - d.SelectionSets[ref].SelectionRefs = append(d.SelectionSets[ref].SelectionRefs[:index], d.SelectionSets[ref].SelectionRefs[index+1:]...) -} - -func (d *Document) SelectionSetHasFieldSelectionWithNameOrAliasBytes(set int, nameOrAlias []byte) bool { - for _, i := range d.SelectionSets[set].SelectionRefs { - if d.Selections[i].Kind != SelectionKindField { - continue - } - field := d.Selections[i].Ref - fieldName := d.FieldNameBytes(field) - if bytes.Equal(fieldName, nameOrAlias) { - return true - } - if !d.FieldAliasIsDefined(field) { - continue - } - fieldAlias := d.FieldAliasBytes(field) - if bytes.Equal(fieldAlias, nameOrAlias) { - return true - } - } - return false -} - -func (d *Document) SelectionSetHasFieldSelectionWithNameOrAliasString(set int, nameOrAlias string) bool { - return d.SelectionSetHasFieldSelectionWithNameOrAliasBytes(set, unsafebytes.StringToBytes(nameOrAlias)) -} diff --git a/pkg/ast/ast_string.go b/pkg/ast/ast_string.go deleted file mode 100644 index 74d7ec4d7..000000000 --- a/pkg/ast/ast_string.go +++ /dev/null @@ -1,160 +0,0 @@ -// Code generated by "stringer -type=OperationType,ValueKind,TypeKind,SelectionKind,NodeKind,PathKind -output ast_string.go"; DO NOT EDIT. - -package ast - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[OperationTypeUnknown-0] - _ = x[OperationTypeQuery-1] - _ = x[OperationTypeMutation-2] - _ = x[OperationTypeSubscription-3] -} - -const _OperationType_name = "OperationTypeUnknownOperationTypeQueryOperationTypeMutationOperationTypeSubscription" - -var _OperationType_index = [...]uint8{0, 20, 38, 59, 84} - -func (i OperationType) String() string { - if i < 0 || i >= OperationType(len(_OperationType_index)-1) { - return "OperationType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _OperationType_name[_OperationType_index[i]:_OperationType_index[i+1]] -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[ValueKindUnknown-4] - _ = x[ValueKindString-5] - _ = x[ValueKindBoolean-6] - _ = x[ValueKindInteger-7] - _ = x[ValueKindFloat-8] - _ = x[ValueKindVariable-9] - _ = x[ValueKindNull-10] - _ = x[ValueKindList-11] - _ = x[ValueKindObject-12] - _ = x[ValueKindEnum-13] -} - -const _ValueKind_name = "ValueKindUnknownValueKindStringValueKindBooleanValueKindIntegerValueKindFloatValueKindVariableValueKindNullValueKindListValueKindObjectValueKindEnum" - -var _ValueKind_index = [...]uint8{0, 16, 31, 47, 63, 77, 94, 107, 120, 135, 148} - -func (i ValueKind) String() string { - i -= 4 - if i < 0 || i >= ValueKind(len(_ValueKind_index)-1) { - return "ValueKind(" + strconv.FormatInt(int64(i+4), 10) + ")" - } - return _ValueKind_name[_ValueKind_index[i]:_ValueKind_index[i+1]] -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[TypeKindUnknown-14] - _ = x[TypeKindNamed-15] - _ = x[TypeKindList-16] - _ = x[TypeKindNonNull-17] -} - -const _TypeKind_name = "TypeKindUnknownTypeKindNamedTypeKindListTypeKindNonNull" - -var _TypeKind_index = [...]uint8{0, 15, 28, 40, 55} - -func (i TypeKind) String() string { - i -= 14 - if i < 0 || i >= TypeKind(len(_TypeKind_index)-1) { - return "TypeKind(" + strconv.FormatInt(int64(i+14), 10) + ")" - } - return _TypeKind_name[_TypeKind_index[i]:_TypeKind_index[i+1]] -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[SelectionKindUnknown-18] - _ = x[SelectionKindField-19] - _ = x[SelectionKindFragmentSpread-20] - _ = x[SelectionKindInlineFragment-21] -} - -const _SelectionKind_name = "SelectionKindUnknownSelectionKindFieldSelectionKindFragmentSpreadSelectionKindInlineFragment" - -var _SelectionKind_index = [...]uint8{0, 20, 38, 65, 92} - -func (i SelectionKind) String() string { - i -= 18 - if i < 0 || i >= SelectionKind(len(_SelectionKind_index)-1) { - return "SelectionKind(" + strconv.FormatInt(int64(i+18), 10) + ")" - } - return _SelectionKind_name[_SelectionKind_index[i]:_SelectionKind_index[i+1]] -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[NodeKindUnknown-22] - _ = x[NodeKindSchemaDefinition-23] - _ = x[NodeKindSchemaExtension-24] - _ = x[NodeKindObjectTypeDefinition-25] - _ = x[NodeKindObjectTypeExtension-26] - _ = x[NodeKindInterfaceTypeDefinition-27] - _ = x[NodeKindInterfaceTypeExtension-28] - _ = x[NodeKindUnionTypeDefinition-29] - _ = x[NodeKindUnionTypeExtension-30] - _ = x[NodeKindUnionMemberType-31] - _ = x[NodeKindEnumTypeDefinition-32] - _ = x[NodeKindEnumValueDefinition-33] - _ = x[NodeKindEnumTypeExtension-34] - _ = x[NodeKindInputObjectTypeDefinition-35] - _ = x[NodeKindInputValueDefinition-36] - _ = x[NodeKindInputObjectTypeExtension-37] - _ = x[NodeKindScalarTypeDefinition-38] - _ = x[NodeKindScalarTypeExtension-39] - _ = x[NodeKindDirectiveDefinition-40] - _ = x[NodeKindOperationDefinition-41] - _ = x[NodeKindSelectionSet-42] - _ = x[NodeKindField-43] - _ = x[NodeKindFieldDefinition-44] - _ = x[NodeKindFragmentSpread-45] - _ = x[NodeKindInlineFragment-46] - _ = x[NodeKindFragmentDefinition-47] - _ = x[NodeKindArgument-48] - _ = x[NodeKindDirective-49] - _ = x[NodeKindVariableDefinition-50] -} - -const _NodeKind_name = "NodeKindUnknownNodeKindSchemaDefinitionNodeKindSchemaExtensionNodeKindObjectTypeDefinitionNodeKindObjectTypeExtensionNodeKindInterfaceTypeDefinitionNodeKindInterfaceTypeExtensionNodeKindUnionTypeDefinitionNodeKindUnionTypeExtensionNodeKindUnionMemberTypeNodeKindEnumTypeDefinitionNodeKindEnumValueDefinitionNodeKindEnumTypeExtensionNodeKindInputObjectTypeDefinitionNodeKindInputValueDefinitionNodeKindInputObjectTypeExtensionNodeKindScalarTypeDefinitionNodeKindScalarTypeExtensionNodeKindDirectiveDefinitionNodeKindOperationDefinitionNodeKindSelectionSetNodeKindFieldNodeKindFieldDefinitionNodeKindFragmentSpreadNodeKindInlineFragmentNodeKindFragmentDefinitionNodeKindArgumentNodeKindDirectiveNodeKindVariableDefinition" - -var _NodeKind_index = [...]uint16{0, 15, 39, 62, 90, 117, 148, 178, 205, 231, 254, 280, 307, 332, 365, 393, 425, 453, 480, 507, 534, 554, 567, 590, 612, 634, 660, 676, 693, 719} - -func (i NodeKind) String() string { - i -= 22 - if i < 0 || i >= NodeKind(len(_NodeKind_index)-1) { - return "NodeKind(" + strconv.FormatInt(int64(i+22), 10) + ")" - } - return _NodeKind_name[_NodeKind_index[i]:_NodeKind_index[i+1]] -} -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[UnknownPathKind-0] - _ = x[ArrayIndex-1] - _ = x[FieldName-2] -} - -const _PathKind_name = "UnknownPathKindArrayIndexFieldName" - -var _PathKind_index = [...]uint8{0, 15, 25, 34} - -func (i PathKind) String() string { - if i < 0 || i >= PathKind(len(_PathKind_index)-1) { - return "PathKind(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _PathKind_name[_PathKind_index[i]:_PathKind_index[i+1]] -} diff --git a/pkg/ast/ast_test.go b/pkg/ast/ast_test.go deleted file mode 100644 index 76f919e30..000000000 --- a/pkg/ast/ast_test.go +++ /dev/null @@ -1,473 +0,0 @@ -package ast_test - -import ( - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -// Create a new document with initialized slices. -// In case you're on a hot path you always want to use a pre-initialized Document. -func ExampleNewDocument() { - schema := []byte(` - schema { - query: Query - } - - type Query { - hello: String! - } - `) - - doc := ast.NewDocument() - doc.Input.ResetInputBytes(schema) - - // ...then parse the Input -} - -// Create a new Document without pre-initializing slices. -// Use this if you want to manually create a new Document -func ExampleDocument() { - // create the same doc as in NewDocument() example but manually. - - doc := &ast.Document{} - - // add Query to the raw input - queryTypeName := doc.Input.AppendInputString("Query") - - // create a RootOperationTypeDefinition - rootOperationTypeDefinition := ast.RootOperationTypeDefinition{ - OperationType: ast.OperationTypeQuery, - NamedType: ast.Type{ - Name: queryTypeName, - }, - } - - // add the RootOperationTypeDefinition to the ast - doc.RootOperationTypeDefinitions = append(doc.RootOperationTypeDefinitions, rootOperationTypeDefinition) - // get a reference to the RootOperationTypeDefinition - queryRootOperationTypeRef := len(doc.RootOperationTypeDefinitions) - 1 - - // create a SchemaDefinition - schemaDefinition := ast.SchemaDefinition{ - RootOperationTypeDefinitions: ast.RootOperationTypeDefinitionList{ - // add the RootOperationTypeDefinition reference - Refs: []int{queryRootOperationTypeRef}, - }, - } - - // add the SchemaDefinition to the ast - doc.SchemaDefinitions = append(doc.SchemaDefinitions, schemaDefinition) - // get a reference to the SchemaDefinition - schemaDefinitionRef := len(doc.SchemaDefinitions) - 1 - - // add the SchemaDefinition to the RootNodes - // all root level nodes have to be added to the RootNodes slice in order to make them available to the Walker for traversal - doc.RootNodes = append(doc.RootNodes, ast.Node{Kind: ast.NodeKindSchemaDefinition, Ref: schemaDefinitionRef}) - - // add another string to the raw input - stringName := doc.Input.AppendInputString("String") - - // create a named Type - stringType := ast.Type{ - TypeKind: ast.TypeKindNamed, - Name: stringName, - } - - // add the Type to the ast - doc.Types = append(doc.Types, stringType) - // get a reference to the Type - stringTypeRef := len(doc.Types) - 1 - - // create another Type - nonNullStringType := ast.Type{ - TypeKind: ast.TypeKindNonNull, - // add a reference to the named type - OfType: stringTypeRef, - } - // Result: NonNull String / String! - - // add the Type to the ast - doc.Types = append(doc.Types, nonNullStringType) - // get a reference to the Type - nonNullStringTypeRef := len(doc.Types) - 1 - - // add another string to the raw input - helloName := doc.Input.AppendInputString("hello") - - // create a FieldDefinition - helloFieldDefinition := ast.FieldDefinition{ - Name: helloName, - // add the Type reference - Type: nonNullStringTypeRef, - } - - // add the FieldDefinition to the ast - doc.FieldDefinitions = append(doc.FieldDefinitions, helloFieldDefinition) - // get a reference to the FieldDefinition - helloFieldDefinitionRef := len(doc.FieldDefinitions) - 1 - - // create an ObjectTypeDefinition - queryTypeDefinition := ast.ObjectTypeDefinition{ - Name: queryTypeName, - // declare that this ObjectTypeDefinition has fields - // this is necessary for the Walker to understand it must walk FieldDefinitions - HasFieldDefinitions: true, - FieldsDefinition: ast.FieldDefinitionList{ - // add the FieldDefinition reference - Refs: []int{helloFieldDefinitionRef}, - }, - } - - // add ObjectTypeDefinition to the ast - doc.ObjectTypeDefinitions = append(doc.ObjectTypeDefinitions, queryTypeDefinition) - // get reference to ObjectTypeDefinition - queryTypeRef := len(doc.ObjectTypeDefinitions) - 1 - - // add ObjectTypeDefinition to the RootNodes - doc.RootNodes = append(doc.RootNodes, ast.Node{Kind: ast.NodeKindObjectTypeDefinition, Ref: queryTypeRef}) -} - -func TestCopying(t *testing.T) { - doc, report := astparser.ParseGraphqlDocumentString(` - query testQuery($someVariable: String!) { - user { - fieldToCopy { - booleanArgField(arg: true) - enumArgField(arg: SOME_ENUM_VALUE) - floatArgField(arg: 3.14) - intArgField(arg: 6) - listArgField(arg: [1, 2, 3, 4]) - objectArgField(arg: {key: "value"}) - stringArgField(arg: "hello") - variableArgField(arg: $someVariable) - twoArgField(argOne: true, argTwo: false) - scalarField - objectField { - fieldOne - fieldTwo - } - aliasedField: nonAliasedField - ...namedFragment - ... on SomeType { - inlineFragmentField - ... on AnotherType { - nestedInlineFragmentField - } - } - directiveField @requires(fields: "scalarField") @anotherDirective() - } - } - } - - fragment namedFragment on SomeType { - fragmentField - } - `) - - assert.False(t, report.HasErrors()) - - for ref := range doc.Fields { - if doc.FieldNameString(ref) == "user" { - selectionSet := doc.Fields[ref].SelectionSet - selectionToCopy := doc.SelectionSets[selectionSet].SelectionRefs[0] - doc.AddSelection(selectionSet, doc.Selections[doc.CopySelection(selectionToCopy)]) - break - } - } - - out, err := astprinter.PrintStringIndent(&doc, nil, " ") - - assert.NoError(t, err) - - expected := `query testQuery($someVariable: String!){ - user { - fieldToCopy { - booleanArgField(arg: true) - enumArgField(arg: SOME_ENUM_VALUE) - floatArgField(arg: 3.14) - intArgField(arg: 6) - listArgField(arg: [1,2,3,4]) - objectArgField(arg: {key: "value"}) - stringArgField(arg: "hello") - variableArgField(arg: $someVariable) - twoArgField(argOne: true, argTwo: false) - scalarField - objectField { - fieldOne - fieldTwo - } - aliasedField: nonAliasedField - ...namedFragment - ... on SomeType { - inlineFragmentField - ... on AnotherType { - nestedInlineFragmentField - } - } - directiveField @requires(fields: "scalarField") @anotherDirective - } - fieldToCopy { - booleanArgField(arg: true) - enumArgField(arg: SOME_ENUM_VALUE) - floatArgField(arg: 3.14) - intArgField(arg: 6) - listArgField(arg: [1,2,3,4]) - objectArgField(arg: {key: "value"}) - stringArgField(arg: "hello") - variableArgField(arg: $someVariable) - twoArgField(argOne: true, argTwo: false) - scalarField - objectField { - fieldOne - fieldTwo - } - aliasedField: nonAliasedField - ...namedFragment - ... on SomeType { - inlineFragmentField - ... on AnotherType { - nestedInlineFragmentField - } - } - directiveField @requires(fields: "scalarField") @anotherDirective - } - } -} - -fragment namedFragment on SomeType { - fragmentField -}` - - assert.Equal(t, expected, out) -} - -func TestKinds(t *testing.T) { - expectedArray := func(start, count int) (out []int) { - for i := start; i < start+count; i++ { - out = append(out, i) - } - return - } - - t.Run("operation types has correct values", func(t *testing.T) { - operationTypes := []ast.OperationType{ - ast.OperationTypeUnknown, - ast.OperationTypeQuery, - ast.OperationTypeMutation, - ast.OperationTypeSubscription, - } - actualValues := make([]int, 0, len(operationTypes)) - for _, t := range operationTypes { - actualValues = append(actualValues, int(t)) - } - assert.Equal(t, expectedArray(0, 4), actualValues) - }) - - t.Run("value kinds has correct values", func(t *testing.T) { - valueKinds := []ast.ValueKind{ - ast.ValueKindUnknown, - ast.ValueKindString, - ast.ValueKindBoolean, - ast.ValueKindInteger, - ast.ValueKindFloat, - ast.ValueKindVariable, - ast.ValueKindNull, - ast.ValueKindList, - ast.ValueKindObject, - ast.ValueKindEnum, - } - actualValues := make([]int, 0, len(valueKinds)) - for _, t := range valueKinds { - actualValues = append(actualValues, int(t)) - } - assert.Equal(t, expectedArray(4, 10), actualValues) - }) - - t.Run("type kinds has correct values", func(t *testing.T) { - typeKinds := []ast.TypeKind{ - ast.TypeKindUnknown, - ast.TypeKindNamed, - ast.TypeKindList, - ast.TypeKindNonNull, - } - actualValues := make([]int, 0, len(typeKinds)) - for _, t := range typeKinds { - actualValues = append(actualValues, int(t)) - } - assert.Equal(t, expectedArray(14, 4), actualValues) - }) - - t.Run("selection kinds has correct values", func(t *testing.T) { - selectionKinds := []ast.SelectionKind{ - ast.SelectionKindUnknown, - ast.SelectionKindField, - ast.SelectionKindFragmentSpread, - ast.SelectionKindInlineFragment, - } - actualValues := make([]int, 0, len(selectionKinds)) - for _, t := range selectionKinds { - actualValues = append(actualValues, int(t)) - } - assert.Equal(t, expectedArray(18, 4), actualValues) - }) - - t.Run("node kinds has correct values", func(t *testing.T) { - nodeKinds := []ast.NodeKind{ - ast.NodeKindUnknown, - ast.NodeKindSchemaDefinition, - ast.NodeKindSchemaExtension, - ast.NodeKindObjectTypeDefinition, - ast.NodeKindObjectTypeExtension, - ast.NodeKindInterfaceTypeDefinition, - ast.NodeKindInterfaceTypeExtension, - ast.NodeKindUnionTypeDefinition, - ast.NodeKindUnionTypeExtension, - ast.NodeKindUnionMemberType, - ast.NodeKindEnumTypeDefinition, - ast.NodeKindEnumValueDefinition, - ast.NodeKindEnumTypeExtension, - ast.NodeKindInputObjectTypeDefinition, - ast.NodeKindInputValueDefinition, - ast.NodeKindInputObjectTypeExtension, - ast.NodeKindScalarTypeDefinition, - ast.NodeKindScalarTypeExtension, - ast.NodeKindDirectiveDefinition, - ast.NodeKindOperationDefinition, - ast.NodeKindSelectionSet, - ast.NodeKindField, - ast.NodeKindFieldDefinition, - ast.NodeKindFragmentSpread, - ast.NodeKindInlineFragment, - ast.NodeKindFragmentDefinition, - ast.NodeKindArgument, - ast.NodeKindDirective, - ast.NodeKindVariableDefinition, - } - actualValues := make([]int, 0, len(nodeKinds)) - for _, t := range nodeKinds { - actualValues = append(actualValues, int(t)) - } - assert.Equal(t, expectedArray(22, 29), actualValues) - }) -} - -func TestFilterIntSliceByWhitelist(t *testing.T) { - run := func(inputIntSlice []int, inputWhitelistIntSlice []int, expectedFilteredIntSlice []int) func(t *testing.T) { - return func(t *testing.T) { - result := ast.FilterIntSliceByWhitelist(inputIntSlice, inputWhitelistIntSlice) - assert.Equal(t, expectedFilteredIntSlice, result) - } - } - - t.Run("should return empty slice when all input slices are nil", - run(nil, nil, []int{}), - ) - - t.Run("should return empty slice when all input slices are empty", - run([]int{}, []int{}, []int{}), - ) - - t.Run("should return empty slice when whitelisted is empty", - run([]int{1, 2, 3}, []int{}, []int{}), - ) - - t.Run("should return a slice with filtered int values", - run([]int{1, 2, 3, 4}, []int{2, 3, 10}, []int{2, 3}), - ) - - t.Run("should return all values when all are whitelisted", - run([]int{1, 2, 3}, []int{1, 2, 3, 4, 5}, []int{1, 2, 3}), - ) -} - -func TestDocument_NodeByName(t *testing.T) { - schema := "schema {query: Query} type Query {queryName: String}" - - prepareDoc := func() *ast.Document { - doc := unsafeparser.ParseGraphqlDocumentString(schema) - return &doc - } - - t.Run("should return a node", func(t *testing.T) { - doc := prepareDoc() - - t.Run("when node name is Query", func(t *testing.T) { - t.Run("NodeByName", func(t *testing.T) { - node, exists := doc.NodeByName(ast.DefaultQueryTypeName) - assert.Equal(t, ast.NodeKindObjectTypeDefinition, node.Kind) - assert.True(t, exists) - }) - - t.Run("NodeByNameStr", func(t *testing.T) { - node, exists := doc.NodeByNameStr("Query") - assert.Equal(t, ast.NodeKindObjectTypeDefinition, node.Kind) - assert.True(t, exists) - }) - }) - - t.Run("when node name is schema", func(t *testing.T) { - t.Run("NodeByName", func(t *testing.T) { - node, exists := doc.NodeByName([]byte("schema")) - assert.Equal(t, ast.NodeKindSchemaDefinition, node.Kind) - assert.True(t, exists) - }) - - t.Run("NodeByNameStr", func(t *testing.T) { - node, exists := doc.NodeByNameStr("schema") - assert.Equal(t, ast.NodeKindSchemaDefinition, node.Kind) - assert.True(t, exists) - }) - }) - }) - - t.Run("should return false for not existing node", func(t *testing.T) { - doc := prepareDoc() - - t.Run("NodeByName", func(t *testing.T) { - node, exists := doc.NodeByName([]byte("NotExisting")) - assert.Equal(t, ast.InvalidNode, node) - assert.False(t, exists) - }) - - t.Run("NodeByNameStr", func(t *testing.T) { - node, exists := doc.NodeByNameStr("NotExisting") - assert.Equal(t, ast.InvalidNode, node) - assert.False(t, exists) - }) - }) -} - -func TestDirectiveList_RemoveDirectiveByName(t *testing.T) { - const schema = "type User @directive1 @directive2 @directive3 @directive4 @directive5 { field: String! }" - doc, _ := astparser.ParseGraphqlDocumentString(schema) - replacer := strings.NewReplacer(" ", "", "\t", "", "\r", "", "\n", "") - // delete the last directive - doc.ObjectTypeDefinitions[0].Directives.RemoveDirectiveByName(&doc, "directive5") - // delete the middle directive - doc.ObjectTypeDefinitions[0].Directives.RemoveDirectiveByName(&doc, "directive3") - // delete the first directive - doc.ObjectTypeDefinitions[0].Directives.RemoveDirectiveByName(&doc, "directive1") - out, _ := astprinter.PrintString(&doc, nil) - assert.Equal(t, replacer.Replace("type User @directive2 @directive4 { field: String! }"), replacer.Replace(out)) -} - -func TestDirectiveList_HasDirectiveByName(t *testing.T) { - const schema = "type User @directive1 @directive2 @directive3 @directive4 @directive5 { field: String! }" - doc, _ := astparser.ParseGraphqlDocumentString(schema) - l := doc.ObjectTypeDefinitions[0].Directives - // search the last directive - assert.Equal(t, true, l.HasDirectiveByName(&doc, "directive5")) - // search the middle directive - assert.Equal(t, true, l.HasDirectiveByName(&doc, "directive3")) - // search the first directive - assert.Equal(t, true, l.HasDirectiveByName(&doc, "directive1")) - // search not found - assert.Equal(t, false, l.HasDirectiveByName(&doc, "directive0")) -} diff --git a/pkg/ast/ast_type.go b/pkg/ast/ast_type.go deleted file mode 100644 index 3c21ff89c..000000000 --- a/pkg/ast/ast_type.go +++ /dev/null @@ -1,249 +0,0 @@ -package ast - -import ( - "bytes" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type TypeKind int - -const ( - TypeKindUnknown TypeKind = 14 + iota - TypeKindNamed - TypeKindList - TypeKindNonNull -) - -type Type struct { - TypeKind TypeKind // one of Named,List,NonNull - Name ByteSliceReference // e.g. String (only on NamedType) - Position position.Position - Open position.Position // [ (only on ListType) - Close position.Position // ] (only on ListType) - Bang position.Position // ! (only on NonNullType) - OfType int -} - -func (d *Document) TypeNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.Types[ref].Name) -} - -func (d *Document) TypeNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.Types[ref].Name)) -} - -func (d *Document) PrintType(ref int, w io.Writer) error { - switch d.Types[ref].TypeKind { - case TypeKindNonNull: - err := d.PrintType(d.Types[ref].OfType, w) - if err != nil { - return err - } - _, err = w.Write(literal.BANG) - return err - case TypeKindNamed: - _, err := w.Write(d.Input.ByteSlice(d.Types[ref].Name)) - return err - case TypeKindList: - _, err := w.Write(literal.LBRACK) - if err != nil { - return err - } - err = d.PrintType(d.Types[ref].OfType, w) - if err != nil { - return err - } - _, err = w.Write(literal.RBRACK) - return err - } - return nil -} - -func (d *Document) PrintTypeBytes(ref int, buf []byte) ([]byte, error) { - if buf == nil { - buf = make([]byte, 0, 24) - } - b := bytes.NewBuffer(buf) - err := d.PrintType(ref, b) - return b.Bytes(), err -} - -func (d *Document) AddType(t Type) (ref int) { - d.Types = append(d.Types, t) - return len(d.Types) - 1 -} - -func (d *Document) AddNamedTypeWithPosition(nameRef ByteSliceReference, position position.Position) (ref int) { - return d.AddType(Type{ - TypeKind: TypeKindNamed, - Name: nameRef, - OfType: -1, - Position: position, - }) -} - -func (d *Document) AddNamedType(name []byte) (ref int) { - nameRef := d.Input.AppendInputBytes(name) - return d.AddNamedTypeWithPosition(nameRef, position.Position{}) -} - -func (d *Document) AddListType(ofType int) (ref int) { - return d.AddListTypeWithPosition(ofType, position.Position{}, position.Position{}) -} - -func (d *Document) AddListTypeWithPosition(ofType int, open position.Position, close position.Position) (ref int) { - return d.AddType(Type{ - TypeKind: TypeKindList, - Open: open, - Close: close, - OfType: ofType, - Position: open, - }) -} - -func (d *Document) AddNonNullType(ofType int) (ref int) { - return d.AddNonNullTypeWithBangPosition(ofType, position.Position{}) -} - -func (d *Document) AddNonNullTypeWithBangPosition(ofType int, bang position.Position) (ref int) { - return d.AddType(Type{ - TypeKind: TypeKindNonNull, - Bang: bang, - OfType: ofType, - Position: d.Types[ofType].Position, - }) -} - -func (d *Document) AddNonNullNamedType(name []byte) (ref int) { - namedRef := d.AddNamedType(name) - return d.AddNonNullType(namedRef) -} - -func (d *Document) TypesAreEqualDeep(left int, right int) bool { - for { - if left == -1 || right == -1 { - return false - } - if d.Types[left].TypeKind != d.Types[right].TypeKind { - return false - } - if d.Types[left].TypeKind == TypeKindNamed { - leftName := d.TypeNameBytes(left) - rightName := d.TypeNameBytes(right) - return bytes.Equal(leftName, rightName) - } - left = d.Types[left].OfType - right = d.Types[right].OfType - } -} - -func (d *Document) TypeIsScalar(ref int, definition *Document) bool { - switch d.Types[ref].TypeKind { - case TypeKindNamed: - typeName := d.TypeNameBytes(ref) - node, _ := definition.Index.FirstNodeByNameBytes(typeName) - return node.Kind == NodeKindScalarTypeDefinition - case TypeKindNonNull: - return d.TypeIsScalar(d.Types[ref].OfType, definition) - } - return false -} - -func (d *Document) TypeIsEnum(ref int, definition *Document) bool { - switch d.Types[ref].TypeKind { - case TypeKindNamed: - typeName := d.TypeNameBytes(ref) - node, _ := definition.Index.FirstNodeByNameBytes(typeName) - return node.Kind == NodeKindEnumTypeDefinition - case TypeKindNonNull: - return d.TypeIsEnum(d.Types[ref].OfType, definition) - } - return false -} - -func (d *Document) TypeIsNonNull(ref int) bool { - return d.Types[ref].TypeKind == TypeKindNonNull -} - -func (d *Document) TypeIsList(ref int) bool { - switch d.Types[ref].TypeKind { - case TypeKindList: - return true - case TypeKindNonNull: - return d.TypeIsList(d.Types[ref].OfType) - default: - return false - } -} - -func (d *Document) TypesAreCompatibleDeep(left int, right int) bool { - for { - if left == -1 || right == -1 { - return false - } - if d.Types[left].TypeKind != d.Types[right].TypeKind { - return false - } - if d.Types[left].TypeKind == TypeKindNamed { - leftName := d.TypeNameBytes(left) - rightName := d.TypeNameBytes(right) - if bytes.Equal(leftName, rightName) { - return true - } - leftNode, _ := d.Index.FirstNodeByNameBytes(leftName) - rightNode, _ := d.Index.FirstNodeByNameBytes(rightName) - if leftNode.Kind == rightNode.Kind { - return false - } - if leftNode.Kind == NodeKindInterfaceTypeDefinition && rightNode.Kind == NodeKindObjectTypeDefinition { - return d.NodeImplementsInterface(rightNode, leftNode) - } - if leftNode.Kind == NodeKindObjectTypeDefinition && rightNode.Kind == NodeKindInterfaceTypeDefinition { - return d.NodeImplementsInterface(leftNode, rightNode) - } - if leftNode.Kind == NodeKindUnionTypeDefinition && rightNode.Kind == NodeKindObjectTypeDefinition { - return d.NodeIsUnionMember(rightNode, leftNode) - } - if leftNode.Kind == NodeKindObjectTypeDefinition && rightNode.Kind == NodeKindUnionTypeDefinition { - return d.NodeIsUnionMember(leftNode, rightNode) - } - return false - } - left = d.Types[left].OfType - right = d.Types[right].OfType - } -} - -func (d *Document) ResolveTypeNameBytes(ref int) ByteSlice { - resolvedTypeRef := d.ResolveUnderlyingType(ref) - return d.TypeNameBytes(resolvedTypeRef) -} - -func (d *Document) ResolveTypeNameString(ref int) string { - return unsafebytes.BytesToString(d.ResolveTypeNameBytes(ref)) -} - -func (d *Document) ResolveUnderlyingType(ref int) (typeRef int) { - typeRef = ref - graphqlType := d.Types[ref] - for graphqlType.TypeKind != TypeKindNamed { - typeRef = graphqlType.OfType - graphqlType = d.Types[typeRef] - - } - return -} - -func (d *Document) ResolveListOrNameType(ref int) (typeRef int) { - typeRef = ref - graphqlType := d.Types[ref] - for (graphqlType.TypeKind != TypeKindNamed) && (graphqlType.TypeKind != TypeKindList) { - typeRef = graphqlType.OfType - graphqlType = d.Types[typeRef] - } - return -} diff --git a/pkg/ast/ast_type_test.go b/pkg/ast/ast_type_test.go deleted file mode 100644 index bd4129631..000000000 --- a/pkg/ast/ast_type_test.go +++ /dev/null @@ -1 +0,0 @@ -package ast diff --git a/pkg/ast/ast_union_type_definition.go b/pkg/ast/ast_union_type_definition.go deleted file mode 100644 index 78fdfef30..000000000 --- a/pkg/ast/ast_union_type_definition.go +++ /dev/null @@ -1,111 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// UnionTypeDefinition -// example: -// union SearchResult = Photo | Person -type UnionTypeDefinition struct { - Description Description // optional, describes union - UnionLiteral position.Position // union - Name ByteSliceReference // e.g. SearchResult - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo - Equals position.Position // = - HasUnionMemberTypes bool - UnionMemberTypes TypeList // optional, e.g. Photo | Person - HasFieldDefinitions bool - FieldsDefinition FieldDefinitionList // contains a single field: { __typename: String! } -} - -func (d *Document) UnionTypeDefinitionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.UnionTypeDefinitions[ref].Name) -} - -func (d *Document) UnionTypeDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.UnionTypeDefinitions[ref].Name)) -} - -func (d *Document) UnionTypeDefinitionDescriptionBytes(ref int) ByteSlice { - if !d.UnionTypeDefinitions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.UnionTypeDefinitions[ref].Description.Content) -} - -func (d *Document) UnionTypeDefinitionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.UnionTypeDefinitionDescriptionBytes(ref)) -} - -func (d *Document) UnionTypeDefinitionHasField(ref int, fieldName []byte) bool { - for _, fieldRef := range d.UnionTypeDefinitions[ref].FieldsDefinition.Refs { - if bytes.Equal(d.FieldDefinitionNameBytes(fieldRef), fieldName) { - return true - } - } - return false -} - -func (d *Document) UnionMemberTypeIsFirst(ref int, ancestor Node) bool { - switch ancestor.Kind { - case NodeKindUnionTypeDefinition: - return len(d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs) != 0 && - d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs[0] == ref - case NodeKindUnionTypeExtension: - return len(d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs) != 0 && - d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs[0] == ref - default: - return false - } -} - -func (d *Document) UnionMemberTypeIsLast(ref int, ancestor Node) bool { - switch ancestor.Kind { - case NodeKindUnionTypeDefinition: - return len(d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs) != 0 && - d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs[len(d.UnionTypeDefinitions[ancestor.Ref].UnionMemberTypes.Refs)-1] == ref - case NodeKindUnionTypeExtension: - return len(d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs) != 0 && - d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs[len(d.UnionTypeExtensions[ancestor.Ref].UnionMemberTypes.Refs)-1] == ref - default: - return false - } -} - -func (d *Document) UnionTypeDefinitionHasDirectives(ref int) bool { - return d.UnionTypeDefinitions[ref].HasDirectives -} - -func (d *Document) AddUnionTypeDefinition(definition UnionTypeDefinition) (ref int) { - d.UnionTypeDefinitions = append(d.UnionTypeDefinitions, definition) - return len(d.UnionTypeDefinitions) - 1 -} - -func (d *Document) ImportUnionTypeDefinition(name, description string, typeRefs []int) (ref int) { - return d.ImportUnionTypeDefinitionWithDirectives(name, description, typeRefs, nil) -} - -func (d *Document) ImportUnionTypeDefinitionWithDirectives(name, description string, typeRefs []int, directiveRefs []int) (ref int) { - definition := UnionTypeDefinition{ - Name: d.Input.AppendInputString(name), - Description: d.ImportDescription(description), - HasUnionMemberTypes: len(typeRefs) > 0, - UnionMemberTypes: TypeList{ - Refs: typeRefs, - }, - HasDirectives: len(directiveRefs) > 0, - Directives: DirectiveList{ - Refs: directiveRefs, - }, - } - - ref = d.AddUnionTypeDefinition(definition) - d.ImportRootNode(ref, NodeKindUnionTypeDefinition) - - return -} diff --git a/pkg/ast/ast_union_type_extension.go b/pkg/ast/ast_union_type_extension.go deleted file mode 100644 index 26a63a862..000000000 --- a/pkg/ast/ast_union_type_extension.go +++ /dev/null @@ -1,62 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type UnionTypeExtension struct { - ExtendLiteral position.Position - UnionTypeDefinition -} - -func (d *Document) UnionTypeExtensionNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.UnionTypeExtensions[ref].Name) -} - -func (d *Document) UnionTypeExtensionNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.UnionTypeExtensions[ref].Name)) -} - -func (d *Document) UnionTypeExtensionDescriptionBytes(ref int) ByteSlice { - if !d.UnionTypeExtensions[ref].Description.IsDefined { - return nil - } - return d.Input.ByteSlice(d.UnionTypeExtensions[ref].Description.Content) -} - -func (d *Document) UnionTypeExtensionDescriptionString(ref int) string { - return unsafebytes.BytesToString(d.UnionTypeExtensionDescriptionBytes(ref)) -} - -func (d *Document) UnionTypeExtensionHasUnionMemberTypes(ref int) bool { - return d.UnionTypeExtensions[ref].HasUnionMemberTypes -} - -func (d *Document) UnionTypeExtensionHasDirectives(ref int) bool { - return d.UnionTypeExtensions[ref].HasDirectives -} - -func (d *Document) ExtendUnionTypeDefinitionByUnionTypeExtension(unionTypeDefinitionRef, unionTypeExtensionRef int) { - if d.UnionTypeExtensionHasDirectives(unionTypeExtensionRef) { - d.UnionTypeDefinitions[unionTypeDefinitionRef].Directives.Refs = append(d.UnionTypeDefinitions[unionTypeDefinitionRef].Directives.Refs, d.UnionTypeExtensions[unionTypeExtensionRef].Directives.Refs...) - d.UnionTypeDefinitions[unionTypeDefinitionRef].HasDirectives = true - } - - if d.UnionTypeExtensionHasUnionMemberTypes(unionTypeExtensionRef) { - d.UnionTypeDefinitions[unionTypeDefinitionRef].UnionMemberTypes.Refs = append(d.UnionTypeDefinitions[unionTypeDefinitionRef].UnionMemberTypes.Refs, d.UnionTypeExtensions[unionTypeExtensionRef].UnionMemberTypes.Refs...) - d.UnionTypeDefinitions[unionTypeDefinitionRef].HasUnionMemberTypes = true - } - - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: unionTypeExtensionRef, Kind: NodeKindUnionTypeExtension}) -} - -func (d *Document) ImportAndExtendUnionTypeDefinitionByUnionTypeExtension(unionTypeExtensionRef int) { - d.ImportUnionTypeDefinitionWithDirectives( - d.UnionTypeExtensionNameString(unionTypeExtensionRef), - d.UnionTypeExtensionDescriptionString(unionTypeExtensionRef), - d.UnionTypeExtensions[unionTypeExtensionRef].UnionMemberTypes.Refs, - d.UnionTypeExtensions[unionTypeExtensionRef].Directives.Refs, - ) - d.Index.MergedTypeExtensions = append(d.Index.MergedTypeExtensions, Node{Ref: unionTypeExtensionRef, Kind: NodeKindUnionTypeExtension}) -} diff --git a/pkg/ast/ast_val_boolean_value.go b/pkg/ast/ast_val_boolean_value.go deleted file mode 100644 index f051a3f86..000000000 --- a/pkg/ast/ast_val_boolean_value.go +++ /dev/null @@ -1,13 +0,0 @@ -package ast - -// BooleanValues -// one of: true, false -type BooleanValue bool - -func (d *Document) BooleanValue(ref int) BooleanValue { - return d.BooleanValues[ref] -} - -func (d *Document) BooleanValuesAreEqual(left, right int) bool { - return d.BooleanValue(left) == d.BooleanValue(right) -} diff --git a/pkg/ast/ast_val_enum_value.go b/pkg/ast/ast_val_enum_value.go deleted file mode 100644 index a3423aa08..000000000 --- a/pkg/ast/ast_val_enum_value.go +++ /dev/null @@ -1,45 +0,0 @@ -package ast - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -// EnumValue -// example: -// Name but not true or false or null -type EnumValue struct { - Name ByteSliceReference // e.g. ORIGIN -} - -func (d *Document) CopyEnumValue(ref int) int { - return d.AddEnumValue(EnumValue{ - Name: d.copyByteSliceReference(d.EnumValues[ref].Name), - }) -} - -func (d *Document) EnumValueName(ref int) ByteSliceReference { - return d.EnumValues[ref].Name -} - -func (d *Document) EnumValueNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.EnumValues[ref].Name) -} - -func (d *Document) EnumValueNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.EnumValues[ref].Name)) -} - -func (d *Document) EnumValuesAreEqual(left, right int) bool { - return d.Input.ByteSliceReferenceContentEquals(d.EnumValueName(left), d.EnumValueName(right)) -} - -func (d *Document) AddEnumValue(value EnumValue) (ref int) { - d.EnumValues = append(d.EnumValues, value) - return len(d.EnumValues) - 1 -} - -func (d *Document) ImportEnumValue(name ByteSlice) (ref int) { - return d.AddEnumValue(EnumValue{ - Name: d.Input.AppendInputBytes(name), - }) -} diff --git a/pkg/ast/ast_val_float_value.go b/pkg/ast/ast_val_float_value.go deleted file mode 100644 index c155f44d4..000000000 --- a/pkg/ast/ast_val_float_value.go +++ /dev/null @@ -1,58 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// FloatValue -// example: -// 13.37 / -13.37 -type FloatValue struct { - Negative bool // indicates if the value is negative - NegativeSign position.Position // optional - - Raw ByteSliceReference // e.g. 13.37 -} - -func (d *Document) CopyFloatValue(ref int) int { - return d.AddFloatValue(FloatValue{ - Negative: d.FloatValues[ref].Negative, - Raw: d.copyByteSliceReference(d.FloatValues[ref].Raw), - }) -} - -func (d *Document) FloatValueAsFloat32(ref int) (out float32) { - in := d.Input.ByteSlice(d.FloatValues[ref].Raw) - out = unsafebytes.BytesToFloat32(in) - if d.FloatValues[ref].Negative { - out = -out - } - return -} - -func (d *Document) FloatValueIsNegative(ref int) bool { - return d.FloatValues[ref].Negative -} - -func (d *Document) FloatValueRaw(ref int) ByteSlice { - return d.Input.ByteSlice(d.FloatValues[ref].Raw) -} - -func (d *Document) FloatValuesAreEqual(left, right int) bool { - return d.FloatValueIsNegative(left) == d.FloatValueIsNegative(right) && - bytes.Equal(d.FloatValueRaw(left), d.FloatValueRaw(right)) -} - -func (d *Document) AddFloatValue(value FloatValue) (ref int) { - d.FloatValues = append(d.FloatValues, value) - return len(d.FloatValues) - 1 -} - -func (d *Document) ImportFloatValue(raw ByteSlice, isNegative bool) (ref int) { - return d.AddFloatValue(FloatValue{ - Negative: isNegative, - Raw: d.Input.AppendInputBytes(raw), - }) -} diff --git a/pkg/ast/ast_val_int_value.go b/pkg/ast/ast_val_int_value.go deleted file mode 100644 index aca0551b2..000000000 --- a/pkg/ast/ast_val_int_value.go +++ /dev/null @@ -1,76 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// IntValue -// example: -// 123 / -123 -type IntValue struct { - Negative bool // indicates if the value is negative - NegativeSign position.Position // optional - - Raw ByteSliceReference // e.g. 123 -} - -func (d *Document) CopyIntValue(ref int) int { - return d.AddIntValue(IntValue{ - Negative: d.IntValues[ref].Negative, - Raw: d.copyByteSliceReference(d.IntValues[ref].Raw), - }) -} - -func (d *Document) IntValueAsInt(ref int) (out int64) { - in := d.Input.ByteSlice(d.IntValues[ref].Raw) - out = unsafebytes.BytesToInt64(in) - if d.IntValues[ref].Negative { - out = -out - } - return -} - -func (d *Document) IntValueAsInt32(ref int) (out int32) { - in := d.Input.ByteSlice(d.IntValues[ref].Raw) - out = unsafebytes.BytesToInt32(in) - if d.IntValues[ref].Negative { - out = -out - } - return -} - -func (d *Document) IntValueValidInt32(ref int) bool { - in := d.Input.ByteSlice(d.IntValues[ref].Raw) - return unsafebytes.BytesIsValidInt32(in) -} - -func (d *Document) IntValue(ref int) IntValue { - return d.IntValues[ref] -} - -func (d *Document) IntValueIsNegative(ref int) bool { - return d.IntValues[ref].Negative -} - -func (d *Document) IntValueRaw(ref int) ByteSlice { - return d.Input.ByteSlice(d.IntValues[ref].Raw) -} - -func (d *Document) IntValuesAreEquals(left, right int) bool { - return d.IntValueIsNegative(left) == d.IntValueIsNegative(right) && - bytes.Equal(d.IntValueRaw(left), d.IntValueRaw(right)) -} - -func (d *Document) AddIntValue(value IntValue) (ref int) { - d.IntValues = append(d.IntValues, value) - return len(d.IntValues) - 1 -} - -func (d *Document) ImportIntValue(raw ByteSlice, isNegative bool) (ref int) { - return d.AddIntValue(IntValue{ - Negative: isNegative, - Raw: d.Input.AppendInputBytes(raw), - }) -} diff --git a/pkg/ast/ast_val_list_value.go b/pkg/ast/ast_val_list_value.go deleted file mode 100644 index 06d4a5a48..000000000 --- a/pkg/ast/ast_val_list_value.go +++ /dev/null @@ -1,45 +0,0 @@ -package ast - -import "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - -type ListValue struct { - LBRACK position.Position // [ - Refs []int // Value - RBRACK position.Position // ] -} - -func (d *Document) CopyListValue(ref int) int { - refs := d.NewEmptyRefs() - for _, r := range d.ListValues[ref].Refs { - refs = append(refs, d.CopyValue(r)) - } - return d.AddListValue(ListValue{ - Refs: refs, - }) -} - -func (d *Document) ListValuesAreEqual(left, right int) bool { - leftValues, rightValues := d.ListValues[left].Refs, d.ListValues[right].Refs - if len(leftValues) != len(rightValues) { - return false - } - for i := 0; i < len(leftValues); i++ { - left, right = leftValues[i], rightValues[i] - leftValue, rightValue := d.Value(left), d.Value(right) - if !d.ValuesAreEqual(leftValue, rightValue) { - return false - } - } - return true -} - -func (d *Document) AddListValue(value ListValue) (ref int) { - d.ListValues = append(d.ListValues, value) - return len(d.ListValues) - 1 -} - -func (d *Document) ImportListValue(valueRefs []int) (ref int) { - return d.AddListValue(ListValue{ - Refs: valueRefs, - }) -} diff --git a/pkg/ast/ast_val_object_value.go b/pkg/ast/ast_val_object_value.go deleted file mode 100644 index ed5c4f287..000000000 --- a/pkg/ast/ast_val_object_value.go +++ /dev/null @@ -1,33 +0,0 @@ -package ast - -import "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - -// ObjectValue -// example: -// { lon: 12.43, lat: -53.211 } -type ObjectValue struct { - LBRACE position.Position - Refs []int // ObjectField - RBRACE position.Position -} - -func (d *Document) CopyObjectValue(ref int) int { - refs := d.NewEmptyRefs() - for _, r := range d.ObjectValues[ref].Refs { - refs = append(refs, d.CopyObjectField(r)) - } - return d.AddObjectValue(ObjectValue{ - Refs: refs, - }) -} - -func (d *Document) AddObjectValue(value ObjectValue) (ref int) { - d.ObjectValues = append(d.ObjectValues, value) - return len(d.ObjectValues) - 1 -} - -func (d *Document) ImportObjectValue(fieldRefs []int) (ref int) { - return d.AddObjectValue(ObjectValue{ - Refs: fieldRefs, - }) -} diff --git a/pkg/ast/ast_val_string_value.go b/pkg/ast/ast_val_string_value.go deleted file mode 100644 index 2c3eef172..000000000 --- a/pkg/ast/ast_val_string_value.go +++ /dev/null @@ -1,149 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -// StringValue -// example: -// "foo" -type StringValue struct { - BlockString bool // """foo""" = blockString, "foo" string - Content ByteSliceReference // e.g. foo -} - -func (d *Document) CopyStringValue(ref int) int { - return d.AddStringValue(StringValue{ - BlockString: d.StringValues[ref].BlockString, - Content: d.copyByteSliceReference(d.StringValues[ref].Content), - }) -} - -func (d *Document) StringValue(ref int) StringValue { - return d.StringValues[ref] -} - -func (d *Document) StringValueContentBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.StringValues[ref].Content) -} - -func (d *Document) StringValueContentString(ref int) string { - return unsafebytes.BytesToString(d.StringValueContentBytes(ref)) -} - -func (d *Document) StringValueIsBlockString(ref int) bool { - return d.StringValues[ref].BlockString -} - -func (d *Document) BlockStringValueContentRawBytes(ref int) []byte { - - // Gets the full block string content, just inside the """ quotes. - // This is needed because the lexer ignores whitespace and we need to preserve it - // to account for the indentation of the block string. - - blockStart := 0 - for i := int(d.StringValues[ref].Content.Start) - 1; i >= 0; i-- { - if d.Input.RawBytes[i] == '"' { - blockStart = i + 1 - break - } - } - - blockEnd := d.Input.Length - for i := int(d.StringValues[ref].Content.End); i < d.Input.Length; i++ { - if d.Input.RawBytes[i] == '"' { - blockEnd = i - break - } - } - - return d.Input.RawBytes[blockStart:blockEnd] -} - -func (d *Document) BlockStringValueContentRawString(ref int) string { - return unsafebytes.BytesToString(d.BlockStringValueContentRawBytes(ref)) -} - -func (d *Document) BlockStringValueContentBytes(ref int) []byte { - - // Implements https://spec.graphql.org/October2021/#BlockStringValue() - - // NOTE: This implementation exactly follows the spec. - // It likely could be optimized for performance. - - // split the raw value into lines - rawValue := d.BlockStringValueContentRawBytes(ref) - lines := splitBytesIntoLines(rawValue) - - // find the common indent size (-1 means no common indent) - commonIndent := -1 - for i, line := range lines { - if i == 0 { - continue - } - indent := leadingWhitespaceCount(line) - if indent < len(line) { - if commonIndent == -1 || indent < commonIndent { - commonIndent = indent - } - } - } - - // remove the common indent from each line - if commonIndent != -1 { - for i := 1; i < len(lines); i++ { - var indent int - if len(lines[i]) > commonIndent { - indent = commonIndent - } else { - indent = len(lines[i]) - } - - lines[i] = lines[i][indent:] - } - } - - // find first non-whitespace-only line - firstLine := 0 - for i, line := range lines { - if leadingWhitespaceCount(line) != len(line) { - firstLine = i - break - } - } - - // find last non-whitespace-only line - lastLine := len(lines) - 1 - for i := len(lines) - 1; i >= 0; i-- { - if leadingWhitespaceCount(lines[i]) != len(lines[i]) { - lastLine = i - break - } - } - - // join the lines to keep and return the result - return bytes.Join(lines[firstLine:lastLine+1], []byte{'\n'}) -} - -func (d *Document) BlockStringValueContentString(ref int) string { - return unsafebytes.BytesToString(d.BlockStringValueContentBytes(ref)) -} - -func (d *Document) StringValuesAreEquals(left, right int) bool { - return d.StringValueIsBlockString(left) == d.StringValueIsBlockString(right) && - bytes.Equal(d.StringValueContentBytes(left), d.StringValueContentBytes(right)) -} - -func (d *Document) AddStringValue(value StringValue) (ref int) { - d.StringValues = append(d.StringValues, value) - return len(d.StringValues) - 1 -} - -func (d *Document) ImportStringValue(raw ByteSlice, isBlockString bool) (ref int) { - return d.AddStringValue(StringValue{ - BlockString: isBlockString, - Content: d.Input.AppendInputBytes(raw), - }) -} diff --git a/pkg/ast/ast_val_variable_value.go b/pkg/ast/ast_val_variable_value.go deleted file mode 100644 index a81efa285..000000000 --- a/pkg/ast/ast_val_variable_value.go +++ /dev/null @@ -1,63 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// VariableValue -// example: -// $devicePicSize -type VariableValue struct { - Dollar position.Position // $ - Name ByteSliceReference // e.g. devicePicSize -} - -func (d *Document) CopyVariableValue(ref int) int { - return d.AddVariableValue(VariableValue{ - Name: d.copyByteSliceReference(d.VariableValues[ref].Name), - }) -} - -func (d *Document) VariableValueNameBytes(ref int) ByteSlice { - return d.Input.ByteSlice(d.VariableValues[ref].Name) -} - -func (d *Document) VariableValueNameString(ref int) string { - return unsafebytes.BytesToString(d.Input.ByteSlice(d.VariableValues[ref].Name)) -} - -func (d *Document) VariableValuesAreEqual(left, right int) bool { - return bytes.Equal(d.VariableValueNameBytes(left), d.VariableValueNameBytes(right)) -} - -func (d *Document) AddVariableValue(value VariableValue) (ref int) { - d.VariableValues = append(d.VariableValues, value) - return len(d.VariableValues) - 1 -} - -func (d *Document) ImportVariableValue(name ByteSlice) (ref int) { - return d.AddVariableValue(VariableValue{ - Name: d.Input.AppendInputBytes(name), - }) -} - -func (d *Document) AddVariableValueArgument(argName, variableName []byte) (variableValueRef, argRef int) { - variable := VariableValue{ - Name: d.Input.AppendInputBytes(variableName), - } - d.VariableValues = append(d.VariableValues, variable) - variableValueRef = len(d.VariableValues) - 1 - arg := Argument{ - Name: d.Input.AppendInputBytes(argName), - Value: Value{ - Kind: ValueKindVariable, - Ref: variableValueRef, - }, - } - d.Arguments = append(d.Arguments, arg) - argRef = len(d.Arguments) - 1 - return -} diff --git a/pkg/ast/ast_value.go b/pkg/ast/ast_value.go deleted file mode 100644 index 17f385142..000000000 --- a/pkg/ast/ast_value.go +++ /dev/null @@ -1,333 +0,0 @@ -package ast - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/quotes" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type ValueKind int - -const ( - ValueKindUnknown ValueKind = 4 + iota - ValueKindString - ValueKindBoolean - ValueKindInteger - ValueKindFloat - ValueKindVariable - ValueKindNull - ValueKindList - ValueKindObject - ValueKindEnum -) - -type Value struct { - Kind ValueKind // e.g. 100 or "Bar" - Ref int - Position position.Position -} - -func (d *Document) CopyValue(ref int) int { - return d.AddValue(Value{ - Kind: d.Values[ref].Kind, - Ref: d.copyValueRef(d.Values[ref].Kind, d.Values[ref].Ref), - }) -} - -func (d *Document) copyValueRef(kind ValueKind, valueRef int) int { - switch kind { - case ValueKindString: - return d.CopyStringValue(valueRef) - case ValueKindBoolean: - // Nothing to copy! - return valueRef - case ValueKindInteger: - return d.CopyIntValue(valueRef) - case ValueKindFloat: - return d.CopyFloatValue(valueRef) - case ValueKindVariable: - return d.CopyVariableValue(valueRef) - case ValueKindNull: - // Nothing to copy! - return InvalidRef - case ValueKindList: - return d.CopyListValue(valueRef) - case ValueKindObject: - return d.CopyObjectValue(valueRef) - case ValueKindEnum: - return d.CopyEnumValue(valueRef) - default: - return InvalidRef - } -} - -func (d *Document) ValueContentBytes(value Value) ByteSlice { - switch value.Kind { - case ValueKindEnum: - return d.EnumValueNameBytes(value.Ref) - case ValueKindString: - return d.StringValueContentBytes(value.Ref) - case ValueKindInteger: - return d.IntValueRaw(value.Ref) - case ValueKindFloat: - return d.FloatValueRaw(value.Ref) - } - panic(fmt.Errorf("ValueContentBytes not implemented for ValueKind: %s", value.Kind)) -} - -func (d *Document) ValueContentString(value Value) string { - return unsafebytes.BytesToString(d.ValueContentBytes(value)) -} - -func (d *Document) ValueContainsVariable(value Value) bool { - switch value.Kind { - case ValueKindEnum: - return false - case ValueKindBoolean: - return false - case ValueKindFloat: - return false - case ValueKindList: - for _, ref := range d.ListValues[value.Ref].Refs { - if d.ValueContainsVariable(d.Value(ref)) { - return true - } - } - return false - case ValueKindObject: - for _, ref := range d.ObjectValues[value.Ref].Refs { - if d.ValueContainsVariable(d.ObjectFields[ref].Value) { - return true - } - } - return false - case ValueKindInteger: - return false - case ValueKindNull: - return false - case ValueKindString: - return false - case ValueKindVariable: - return true - default: - return false - } -} - -func (d *Document) writeJSONValue(buf *bytes.Buffer, value Value) error { - switch value.Kind { - case ValueKindNull: - buf.Write(literal.NULL) - case ValueKindEnum: - buf.Write(quotes.WrapBytes(d.EnumValueNameBytes(value.Ref))) - case ValueKindInteger: - intValueBytes := d.IntValueRaw(value.Ref) - if d.IntValueIsNegative(value.Ref) { - buf.WriteByte(literal.SUB_BYTE) - } - buf.Write(intValueBytes) - case ValueKindFloat: - floatValueBytes := d.FloatValueRaw(value.Ref) - if d.FloatValueIsNegative(value.Ref) { - buf.WriteByte(literal.SUB_BYTE) - } - buf.Write(floatValueBytes) - case ValueKindBoolean: - if value.Ref == 0 { - buf.Write(literal.FALSE) - } else { - buf.Write(literal.TRUE) - } - case ValueKindString: - if d.StringValueIsBlockString(value.Ref) { - content := d.BlockStringValueContentString(value.Ref) - - enc := json.NewEncoder(buf) - enc.SetEscapeHTML(false) - if err := enc.Encode(content); err != nil { - return err - } - - // Remove the extra newline that Encode adds - buf.Truncate(buf.Len() - 1) - } else { - buf.Write(quotes.WrapBytes(d.StringValueContentBytes(value.Ref))) - } - case ValueKindList: - buf.WriteByte(literal.LBRACK_BYTE) - for ii, ref := range d.ListValues[value.Ref].Refs { - if ii > 0 { - buf.WriteByte(literal.COMMA_BYTE) - } - if err := d.writeJSONValue(buf, d.Values[ref]); err != nil { - return err - } - } - buf.WriteByte(literal.RBRACK_BYTE) - case ValueKindObject: - buf.WriteByte(literal.LBRACE_BYTE) - for ii, ref := range d.ObjectValues[value.Ref].Refs { - if ii > 0 { - buf.WriteByte(literal.COMMA_BYTE) - } - fieldNameBytes := d.ObjectFieldNameBytes(ref) - buf.Write(quotes.WrapBytes(fieldNameBytes)) - buf.WriteByte(literal.COLON_BYTE) - if err := d.writeJSONValue(buf, d.ObjectFieldValue(ref)); err != nil { - return err - } - } - buf.WriteByte(literal.RBRACE_BYTE) - default: - return fmt.Errorf("ValueToJSON: not implemented for kind: %s", value.Kind.String()) - } - return nil -} - -func (d *Document) ValueToJSON(value Value) ([]byte, error) { - var buf bytes.Buffer - if err := d.writeJSONValue(&buf, value); err != nil { - return nil, err - } - return buf.Bytes(), nil -} - -// nolint -func (d *Document) PrintValue(value Value, w io.Writer) (err error) { - switch value.Kind { - case ValueKindBoolean: - if d.BooleanValues[value.Ref] { - _, err = w.Write(literal.TRUE) - } else { - _, err = w.Write(literal.FALSE) - } - case ValueKindString: - // This code assumes string content is valid for the associated string - // type (block/non-block) according to the GraphQL spec. Content IS NOT - // processed to quote characters that are invalid for the associated - // type. - // - // GraphQL spec: https://spec.graphql.org/June2018/#StringValue - isBlockString := d.StringValues[value.Ref].BlockString - _, err = w.Write(literal.QUOTE) - if isBlockString { - _, err = w.Write(literal.QUOTE) - _, err = w.Write(literal.QUOTE) - } - _, err = w.Write(d.Input.ByteSlice(d.StringValues[value.Ref].Content)) - _, err = w.Write(literal.QUOTE) - if isBlockString { - _, err = w.Write(literal.QUOTE) - _, err = w.Write(literal.QUOTE) - } - case ValueKindInteger: - if d.IntValues[value.Ref].Negative { - _, err = w.Write(literal.SUB) - } - _, err = w.Write(d.Input.ByteSlice(d.IntValues[value.Ref].Raw)) - case ValueKindFloat: - if d.FloatValues[value.Ref].Negative { - _, err = w.Write(literal.SUB) - } - _, err = w.Write(d.Input.ByteSlice(d.FloatValues[value.Ref].Raw)) - case ValueKindVariable: - _, err = w.Write(literal.DOLLAR) - _, err = w.Write(d.Input.ByteSlice(d.VariableValues[value.Ref].Name)) - case ValueKindNull: - _, err = w.Write(literal.NULL) - case ValueKindList: - _, err = w.Write(literal.LBRACK) - for i, j := range d.ListValues[value.Ref].Refs { - err = d.PrintValue(d.Value(j), w) - if err != nil { - return - } - if i != len(d.ListValues[value.Ref].Refs)-1 { - _, err = w.Write(literal.COMMA) - } - } - _, err = w.Write(literal.RBRACK) - case ValueKindObject: - _, err = w.Write(literal.LBRACE) - for i, j := range d.ObjectValues[value.Ref].Refs { - _, err = w.Write(d.ObjectFieldNameBytes(j)) - if err != nil { - return - } - _, err = w.Write(literal.COLON) - if err != nil { - return - } - _, err = w.Write(literal.SPACE) - if err != nil { - return - } - err = d.PrintValue(d.ObjectFieldValue(j), w) - if err != nil { - return - } - if i != len(d.ObjectValues[value.Ref].Refs)-1 { - _, err = w.Write(literal.COMMA) - if err != nil { - return - } - } - } - _, err = w.Write(literal.RBRACE) - case ValueKindEnum: - _, err = w.Write(d.Input.ByteSlice(d.EnumValues[value.Ref].Name)) - } - return -} - -func (d *Document) PrintValueBytes(value Value, buf []byte) ([]byte, error) { - if buf == nil { - buf = make([]byte, 0, 24) - } - b := bytes.NewBuffer(buf) - err := d.PrintValue(value, b) - return b.Bytes(), err -} - -func (d *Document) Value(ref int) Value { - return d.Values[ref] -} - -func (d *Document) ValuesAreEqual(left, right Value) bool { - if left.Kind != right.Kind { - return false - } - switch left.Kind { - case ValueKindString: - return d.StringValuesAreEquals(left.Ref, right.Ref) - case ValueKindBoolean: - return d.BooleanValuesAreEqual(left.Ref, right.Ref) - case ValueKindInteger: - return d.IntValuesAreEquals(left.Ref, right.Ref) - case ValueKindFloat: - return d.FloatValuesAreEqual(left.Ref, right.Ref) - case ValueKindVariable: - return d.VariableValuesAreEqual(left.Ref, right.Ref) - case ValueKindNull: - return true - case ValueKindList: - return d.ListValuesAreEqual(left.Ref, right.Ref) - case ValueKindObject: - return d.ObjectValuesAreEqual(left.Ref, right.Ref) - case ValueKindEnum: - return d.EnumValuesAreEqual(left.Ref, right.Ref) - default: - return false - } -} - -func (d *Document) AddValue(value Value) (ref int) { - d.Values = append(d.Values, value) - return len(d.Values) - 1 -} diff --git a/pkg/ast/ast_value_test.go b/pkg/ast/ast_value_test.go deleted file mode 100644 index e26856109..000000000 --- a/pkg/ast/ast_value_test.go +++ /dev/null @@ -1,245 +0,0 @@ -package ast - -import ( - "bytes" - "strconv" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestDocument_ValueToJSON(t *testing.T) { - run := func(prepareDoc func(doc *Document) Value, expectedOutput string) func(t *testing.T) { - operation := NewDocument() - return func(t *testing.T) { - out, err := operation.ValueToJSON(prepareDoc(operation)) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, string(out)) - } - } - - t.Run("ValueKindNull", run(func(doc *Document) Value { - return Value{ - Kind: ValueKindNull, - Ref: 0, - } - }, `null`)) - t.Run("ValueKindEnum", run(func(doc *Document) Value { - doc.EnumValues = append(doc.EnumValues, EnumValue{ - Name: doc.Input.AppendInputString("FOO"), - }) - return Value{ - Kind: ValueKindEnum, - Ref: 0, - } - }, `"FOO"`)) - t.Run("ValueKindInteger - positive", run(func(doc *Document) Value { - doc.IntValues = append(doc.IntValues, IntValue{ - Raw: doc.Input.AppendInputString("123"), - }) - return Value{ - Kind: ValueKindInteger, - Ref: 0, - } - }, `123`)) - t.Run("ValueKindInteger - negative", run(func(doc *Document) Value { - doc.IntValues = append(doc.IntValues, IntValue{ - Raw: doc.Input.AppendInputString("123"), - Negative: true, - }) - return Value{ - Kind: ValueKindInteger, - Ref: 0, - } - }, `-123`)) - t.Run("ValueKindFloat - positive", run(func(doc *Document) Value { - doc.FloatValues = append(doc.FloatValues, FloatValue{ - Raw: doc.Input.AppendInputString("12.34"), - }) - return Value{ - Kind: ValueKindFloat, - Ref: 0, - } - }, `12.34`)) - t.Run("ValueKindFloat - negative", run(func(doc *Document) Value { - doc.FloatValues = append(doc.FloatValues, FloatValue{ - Raw: doc.Input.AppendInputString("12.34"), - Negative: true, - }) - return Value{ - Kind: ValueKindFloat, - Ref: 0, - } - }, `-12.34`)) - t.Run("ValueKindBoolean - false", run(func(doc *Document) Value { - return Value{ - Kind: ValueKindBoolean, - Ref: 0, - } - }, `false`)) - t.Run("ValueKindBoolean - true", run(func(doc *Document) Value { - return Value{ - Kind: ValueKindBoolean, - Ref: 1, - } - }, `true`)) - t.Run("ValueKindString - non-block", run(func(doc *Document) Value { - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString(`foo\nbar\tbaz\"qux`), - }) - return Value{ - Kind: ValueKindString, - Ref: 0, - } - }, `"foo\nbar\tbaz\"qux"`)) - t.Run("ValueKindString - block", run(func(doc *Document) Value { - doc.Input.AppendInputString(`"""`) - doc.StringValues = append(doc.StringValues, StringValue{ - BlockString: true, - Content: doc.Input.AppendInputString("foo\nbar\tbaz\"qux"), - }) - doc.Input.AppendInputString(`"""`) - return Value{ - Kind: ValueKindString, - Ref: 0, - } - }, `"foo\nbar\tbaz\"qux"`)) - t.Run("ValueKindString - block with indent", run(func(doc *Document) Value { - doc.Input.AppendInputString(`"""`) - doc.Input.AppendInputString("\n") - doc.StringValues = append(doc.StringValues, StringValue{ - BlockString: true, - Content: doc.Input.AppendInputString(" foo\n bar"), - }) - doc.Input.AppendInputString("\n") - doc.Input.AppendInputString(`"""`) - return Value{ - Kind: ValueKindString, - Ref: 0, - } - }, `"foo\nbar"`)) - t.Run("ValueKindString - block with mixed indent", run(func(doc *Document) Value { - doc.Input.AppendInputString(`"""`) - doc.StringValues = append(doc.StringValues, StringValue{ - BlockString: true, - Content: doc.Input.AppendInputString("foo\n\t bar\n\t baz"), - }) - doc.Input.AppendInputString(`"""`) - return Value{ - Kind: ValueKindString, - Ref: 0, - } - }, `"foo\nbar\n baz"`)) - t.Run("ValueKindList", run(func(doc *Document) Value { - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString("foo"), - }) - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString("bar"), - }) - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString("baz"), - }) - for i := 0; i < 3; i++ { - doc.Values = append(doc.Values, Value{Kind: ValueKindString, Ref: i}) - } - doc.IntValues = append(doc.IntValues, IntValue{ - Raw: doc.Input.AppendInputString("123"), - }) - doc.Values = append(doc.Values, Value{Kind: ValueKindInteger, Ref: 0}) - doc.ListValues = append(doc.ListValues, ListValue{ - Refs: []int{0, 1, 2, 3}, - }) - return Value{ - Kind: ValueKindList, - Ref: 0, - } - }, `["foo","bar","baz",123]`)) - t.Run("ValueKindObject", run(func(doc *Document) Value { - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString("bar"), - }) - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString("bal"), - }) - doc.ObjectFields = append(doc.ObjectFields, ObjectField{ - Name: doc.Input.AppendInputString("bat"), - Value: Value{ - Kind: ValueKindString, - Ref: 1, - }, - }) - doc.ObjectFields = append(doc.ObjectFields, - ObjectField{ - Name: doc.Input.AppendInputString("foo"), - Value: Value{ - Kind: ValueKindString, - Ref: 0, - }, - }, - ObjectField{ - Name: doc.Input.AppendInputString("baz"), - Value: Value{ - Kind: ValueKindObject, - Ref: 1, - }, - }) - for i := 0; i < 3; i++ { - doc.IntValues = append(doc.IntValues, IntValue{ - Raw: doc.Input.AppendInputString(strconv.Itoa(i + 1)), - }) - doc.Values = append(doc.Values, Value{Kind: ValueKindInteger, Ref: i}) - } - doc.ListValues = append(doc.ListValues, ListValue{ - Refs: []int{0, 1, 2}, - }) - doc.ObjectFields = append(doc.ObjectFields, ObjectField{ - Name: doc.Input.AppendInputString("list"), - Value: Value{ - Kind: ValueKindList, - Ref: 0, - }, - }) - doc.ObjectValues = append(doc.ObjectValues, ObjectValue{ - Refs: []int{1, 2, 3}, - }) - doc.ObjectValues = append(doc.ObjectValues, ObjectValue{ - Refs: []int{0}, - }) - return Value{ - Kind: ValueKindObject, - Ref: 0, - } - }, `{"foo":"bar","baz":{"bat":"bal"},"list":[1,2,3]}`)) -} - -func TestDocument_PrintValue(t *testing.T) { - run := func(prepareDoc func(doc *Document) Value, expectedOutput string) func(t *testing.T) { - operation := NewDocument() - return func(t *testing.T) { - buf := new(bytes.Buffer) - err := operation.PrintValue(prepareDoc(operation), buf) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, buf.String()) - } - } - t.Run("ValueKindString - non-block", run(func(doc *Document) Value { - doc.StringValues = append(doc.StringValues, StringValue{ - Content: doc.Input.AppendInputString(`foo\nbar\tbaz\"qux`), - }) - return Value{ - Kind: ValueKindString, - Ref: 0, - } - }, `"foo\nbar\tbaz\"qux"`)) - t.Run("ValueKindString - block", run(func(doc *Document) Value { - doc.StringValues = append(doc.StringValues, StringValue{ - BlockString: true, - Content: doc.Input.AppendInputString("foo\nbar\tbaz\"qux"), - }) - return Value{ - Kind: ValueKindString, - Ref: 0, - } - }, "\"\"\"foo\nbar\tbaz\"qux\"\"\"")) -} diff --git a/pkg/ast/ast_variable_definition.go b/pkg/ast/ast_variable_definition.go deleted file mode 100644 index c6c265a21..000000000 --- a/pkg/ast/ast_variable_definition.go +++ /dev/null @@ -1,77 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type VariableDefinitionList struct { - LPAREN position.Position // ( - Refs []int // VariableDefinition - RPAREN position.Position // ) -} - -// VariableDefinition -// example: -// $devicePicSize: Int = 100 @small -type VariableDefinition struct { - VariableValue Value // $ Name - Colon position.Position // : - Type int // e.g. String - DefaultValue DefaultValue // optional, e.g. = "Default" - HasDirectives bool - Directives DirectiveList // optional, e.g. @foo -} - -func (d *Document) VariableDefinitionNameBytes(ref int) ByteSlice { - return d.VariableValueNameBytes(d.VariableDefinitions[ref].VariableValue.Ref) -} - -func (d *Document) VariableDefinitionNameString(ref int) string { - return unsafebytes.BytesToString(d.VariableValueNameBytes(d.VariableDefinitions[ref].VariableValue.Ref)) -} - -func (d *Document) VariableDefinitionHasDefaultValue(ref int) bool { - return d.VariableDefinitions[ref].DefaultValue.IsDefined -} - -func (d *Document) VariableDefinitionDefaultValue(ref int) Value { - return d.VariableDefinitions[ref].DefaultValue.Value -} - -func (d *Document) VariableDefinitionByNameAndOperation(operationDefinition int, name ByteSlice) (definition int, exists bool) { - if !d.OperationDefinitions[operationDefinition].HasVariableDefinitions { - return -1, false - } - for _, i := range d.OperationDefinitions[operationDefinition].VariableDefinitions.Refs { - definitionName := d.VariableValueNameBytes(d.VariableDefinitions[i].VariableValue.Ref) - if bytes.Equal(name, definitionName) { - return i, true - } - } - return -1, false -} - -func (d *Document) VariableDefinitionsBefore(variableDefinition int) bool { - for i := range d.OperationDefinitions { - for j, k := range d.OperationDefinitions[i].VariableDefinitions.Refs { - if k == variableDefinition { - return j != 0 - } - } - } - return false -} - -func (d *Document) VariableDefinitionsAfter(variableDefinition int) bool { - for i := range d.OperationDefinitions { - for j, k := range d.OperationDefinitions[i].VariableDefinitions.Refs { - if k == variableDefinition { - return j != len(d.OperationDefinitions[i].VariableDefinitions.Refs)-1 - } - } - } - return false -} diff --git a/pkg/ast/directive_location.go b/pkg/ast/directive_location.go deleted file mode 100644 index c9e4a3741..000000000 --- a/pkg/ast/directive_location.go +++ /dev/null @@ -1,162 +0,0 @@ -//go:generate stringer -type=DirectiveLocation -output directive_location_string.go - -package ast - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type DirectiveLocation int - -const ( - DirectiveLocationUnknown DirectiveLocation = iota - ExecutableDirectiveLocationQuery - ExecutableDirectiveLocationMutation - ExecutableDirectiveLocationSubscription - ExecutableDirectiveLocationField - ExecutableDirectiveLocationFragmentDefinition - ExecutableDirectiveLocationFragmentSpread - ExecutableDirectiveLocationInlineFragment - ExecutableDirectiveLocationVariableDefinition - - TypeSystemDirectiveLocationSchema - TypeSystemDirectiveLocationScalar - TypeSystemDirectiveLocationObject - TypeSystemDirectiveLocationFieldDefinition - TypeSystemDirectiveLocationArgumentDefinition - TypeSystemDirectiveLocationInterface - TypeSystemDirectiveLocationUnion - TypeSystemDirectiveLocationEnum - TypeSystemDirectiveLocationEnumValue - TypeSystemDirectiveLocationInputObject - TypeSystemDirectiveLocationInputFieldDefinition -) - -var ( - locations = map[string]DirectiveLocation{ - "QUERY": ExecutableDirectiveLocationQuery, - "MUTATION": ExecutableDirectiveLocationMutation, - "SUBSCRIPTION": ExecutableDirectiveLocationSubscription, - "FIELD": ExecutableDirectiveLocationField, - "FRAGMENT_DEFINITION": ExecutableDirectiveLocationFragmentDefinition, - "FRAGMENT_SPREAD": ExecutableDirectiveLocationFragmentSpread, - "INLINE_FRAGMENT": ExecutableDirectiveLocationInlineFragment, - "VARIABLE_DEFINITION": ExecutableDirectiveLocationVariableDefinition, - "SCHEMA": TypeSystemDirectiveLocationSchema, - "SCALAR": TypeSystemDirectiveLocationScalar, - "OBJECT": TypeSystemDirectiveLocationObject, - "FIELD_DEFINITION": TypeSystemDirectiveLocationFieldDefinition, - "ARGUMENT_DEFINITION": TypeSystemDirectiveLocationArgumentDefinition, - "INTERFACE": TypeSystemDirectiveLocationInterface, - "UNION": TypeSystemDirectiveLocationUnion, - "ENUM": TypeSystemDirectiveLocationEnum, - "ENUM_VALUE": TypeSystemDirectiveLocationEnumValue, - "INPUT_OBJECT": TypeSystemDirectiveLocationInputObject, - "INPUT_FIELD_DEFINITION": TypeSystemDirectiveLocationInputFieldDefinition, - } -) - -type DirectiveLocations struct { - storage [20]bool -} - -func (d *DirectiveLocations) Get(location DirectiveLocation) bool { - return d.storage[location] -} - -func (d *DirectiveLocations) Set(location DirectiveLocation) { - d.storage[location] = true -} - -func (d *DirectiveLocations) Unset(location DirectiveLocation) { - d.storage[location] = false -} - -func (d *DirectiveLocations) Iterable() DirectiveLocationIterable { - return DirectiveLocationIterable{ - locations: *d, - } -} - -func (d *DirectiveLocations) SetFromRaw(bytes []byte) error { - - location, exists := locations[string(bytes)] - if !exists { - return fmt.Errorf("invalid directive location: %s", string(bytes)) - } - - d.Set(location) - - return nil -} - -type DirectiveLocationIterable struct { - locations DirectiveLocations - current DirectiveLocation -} - -func (d *DirectiveLocationIterable) Next() bool { - for i := d.current + 1; i < 20; i++ { - if d.locations.storage[i] { - d.current = i - return true - } - } - return false -} - -func (d *DirectiveLocationIterable) Value() DirectiveLocation { - return d.current -} - -func (d DirectiveLocation) LiteralBytes() ByteSlice { - switch d { - case ExecutableDirectiveLocationQuery: - return literal.LocationQuery - case ExecutableDirectiveLocationMutation: - return literal.LocationMutation - case ExecutableDirectiveLocationSubscription: - return literal.LocationSubscription - case ExecutableDirectiveLocationField: - return literal.LocationField - case ExecutableDirectiveLocationFragmentDefinition: - return literal.LocationFragmentDefinition - case ExecutableDirectiveLocationFragmentSpread: - return literal.LocationFragmentSpread - case ExecutableDirectiveLocationInlineFragment: - return literal.LocationInlineFragment - case ExecutableDirectiveLocationVariableDefinition: - return literal.LocationVariableDefinition - case TypeSystemDirectiveLocationSchema: - return literal.LocationSchema - case TypeSystemDirectiveLocationScalar: - return literal.LocationScalar - case TypeSystemDirectiveLocationObject: - return literal.LocationObject - case TypeSystemDirectiveLocationFieldDefinition: - return literal.LocationFieldDefinition - case TypeSystemDirectiveLocationArgumentDefinition: - return literal.LocationArgumentDefinition - case TypeSystemDirectiveLocationInterface: - return literal.LocationInterface - case TypeSystemDirectiveLocationUnion: - return literal.LocationUnion - case TypeSystemDirectiveLocationEnum: - return literal.LocationEnum - case TypeSystemDirectiveLocationEnumValue: - return literal.LocationEnumValue - case TypeSystemDirectiveLocationInputObject: - return literal.LocationInputObject - case TypeSystemDirectiveLocationInputFieldDefinition: - return literal.LocationInputFieldDefinition - default: - return nil - } -} - -func (d DirectiveLocation) LiteralString() string { - return unsafebytes.BytesToString(d.LiteralBytes()) -} diff --git a/pkg/ast/directive_location_string.go b/pkg/ast/directive_location_string.go deleted file mode 100644 index 505cb729d..000000000 --- a/pkg/ast/directive_location_string.go +++ /dev/null @@ -1,42 +0,0 @@ -// Code generated by "stringer -type=DirectiveLocation"; DO NOT EDIT. - -package ast - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[DirectiveLocationUnknown-0] - _ = x[ExecutableDirectiveLocationQuery-1] - _ = x[ExecutableDirectiveLocationMutation-2] - _ = x[ExecutableDirectiveLocationSubscription-3] - _ = x[ExecutableDirectiveLocationField-4] - _ = x[ExecutableDirectiveLocationFragmentDefinition-5] - _ = x[ExecutableDirectiveLocationFragmentSpread-6] - _ = x[ExecutableDirectiveLocationInlineFragment-7] - _ = x[ExecutableDirectiveLocationVariableDefinition-8] - _ = x[TypeSystemDirectiveLocationSchema-9] - _ = x[TypeSystemDirectiveLocationScalar-10] - _ = x[TypeSystemDirectiveLocationObject-11] - _ = x[TypeSystemDirectiveLocationFieldDefinition-12] - _ = x[TypeSystemDirectiveLocationArgumentDefinition-13] - _ = x[TypeSystemDirectiveLocationInterface-14] - _ = x[TypeSystemDirectiveLocationUnion-15] - _ = x[TypeSystemDirectiveLocationEnum-16] - _ = x[TypeSystemDirectiveLocationEnumValue-17] - _ = x[TypeSystemDirectiveLocationInputObject-18] - _ = x[TypeSystemDirectiveLocationInputFieldDefinition-19] -} - -const _DirectiveLocation_name = "DirectiveLocationUnknownExecutableDirectiveLocationQueryExecutableDirectiveLocationMutationExecutableDirectiveLocationSubscriptionExecutableDirectiveLocationFieldExecutableDirectiveLocationFragmentDefinitionExecutableDirectiveLocationFragmentSpreadExecutableDirectiveLocationInlineFragmentExecutableDirectiveLocationVariableDefinitionTypeSystemDirectiveLocationSchemaTypeSystemDirectiveLocationScalarTypeSystemDirectiveLocationObjectTypeSystemDirectiveLocationFieldDefinitionTypeSystemDirectiveLocationArgumentDefinitionTypeSystemDirectiveLocationInterfaceTypeSystemDirectiveLocationUnionTypeSystemDirectiveLocationEnumTypeSystemDirectiveLocationEnumValueTypeSystemDirectiveLocationInputObjectTypeSystemDirectiveLocationInputFieldDefinition" - -var _DirectiveLocation_index = [...]uint16{0, 24, 56, 91, 130, 162, 207, 248, 289, 334, 367, 400, 433, 475, 520, 556, 588, 619, 655, 693, 740} - -func (d DirectiveLocation) String() string { - if d < 0 || d >= DirectiveLocation(len(_DirectiveLocation_index)-1) { - return "DirectiveLocation(" + strconv.FormatInt(int64(d), 10) + ")" - } - return _DirectiveLocation_name[_DirectiveLocation_index[d]:_DirectiveLocation_index[d+1]] -} diff --git a/pkg/ast/directive_location_test.go b/pkg/ast/directive_location_test.go deleted file mode 100644 index 9ddcc34c8..000000000 --- a/pkg/ast/directive_location_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package ast - -import "testing" - -func TestDirectiveLocations(t *testing.T) { - locations := DirectiveLocations{} - for i := range locations.storage { - if locations.storage[i] == true { - t.Fatal("want false") - } - } - - locations.Set(DirectiveLocationUnknown) - locations.Set(ExecutableDirectiveLocationQuery) - - if locations.Get(ExecutableDirectiveLocationQuery) != true { - t.Fatal("want true") - } - - locations.Set(ExecutableDirectiveLocationMutation) - - if locations.Get(ExecutableDirectiveLocationMutation) != true { - t.Fatal("want true") - } - - locations.Set(TypeSystemDirectiveLocationEnum) - - iter := locations.Iterable() - if !iter.Next() { - t.Fatal("want next") - } - if iter.Value() != ExecutableDirectiveLocationQuery { - t.Fatal("want ExecutableDirectiveLocationQuery") - } - if !iter.Next() { - t.Fatal("want next") - } - if iter.Value() != ExecutableDirectiveLocationMutation { - t.Fatal("want ExecutableDirectiveLocationMutation") - } - if !iter.Next() { - t.Fatal("want next") - } - if iter.Value() != TypeSystemDirectiveLocationEnum { - t.Fatal("want TypeSystemDirectiveLocationEnum") - } - if iter.Next() { - t.Fatal("want false") - } - - locations.Unset(ExecutableDirectiveLocationMutation) - - if locations.Get(ExecutableDirectiveLocationMutation) == true { - t.Fatal("want false") - } - - locations.Unset(TypeSystemDirectiveLocationEnum) - if locations.Get(TypeSystemDirectiveLocationEnum) == true { - t.Fatal("want false") - } -} diff --git a/pkg/ast/helpers.go b/pkg/ast/helpers.go deleted file mode 100644 index 3cebfd4cd..000000000 --- a/pkg/ast/helpers.go +++ /dev/null @@ -1,58 +0,0 @@ -package ast - -// indexOf - simple helper to find an index of a ref within refs slice -func indexOf(refs []int, ref int) (int, bool) { - for i, j := range refs { - if ref == j { - return i, true - } - } - return -1, false -} - -// deleteRef - is a slice trick to remove an item with preserving items order -// Note: danger modifies pointer to the arr -func deleteRef(refs *[]int, index int) { - *refs = append((*refs)[:index], (*refs)[index+1:]...) -} - -// Splits byte slices into lines based on line terminators (\n, \r, \r\n) -// defined by https://spec.graphql.org/October2021/#sec-Line-Terminators -func splitBytesIntoLines(data []byte) [][]byte { - var lines [][]byte - start := 0 - length := len(data) - - for i := 0; i < length; i++ { - switch c := data[i]; c { - case '\n', '\r': - if start <= i { - lines = append(lines, data[start:i]) - } - - if c == '\r' && i+1 < length && data[i+1] == '\n' { - i++ - } - - start = i + 1 - } - } - - if start <= length { - lines = append(lines, data[start:]) - } - - return lines -} - -// counts leading whitespace characters (spaces or tabs) in a byte slice -func leadingWhitespaceCount(line []byte) int { - count := 0 - for _, c := range line { - if c != ' ' && c != '\t' { - break - } - count++ - } - return count -} diff --git a/pkg/ast/index.go b/pkg/ast/index.go deleted file mode 100644 index 88ccd9518..000000000 --- a/pkg/ast/index.go +++ /dev/null @@ -1,174 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -// Index is a struct to easily look up objects in a document, e.g. find Nodes (type/interface/union definitions) by name -type Index struct { - // QueryTypeName is the name of the query type on the schema Node - // schema { query: Query } - QueryTypeName ByteSlice - // MutationTypeName is the name of the mutation type on the schema Node - // schema { mutation: Mutation } - MutationTypeName ByteSlice - // SubscriptionTypeName is the name of the subscription type on the schema Node - // schema { subscription: Subscription } - SubscriptionTypeName ByteSlice - // nodes is a list of all root nodes in a schema definition - // The map key is the result of the xxhash algorithm from the Node name. - nodes map[uint64][]Node - // ReplacedFragmentSpreads is a list of references (slice indices) of all FragmentSpreads that got replaced during normalization. - ReplacedFragmentSpreads []int - // MergedTypeExtensions is a list of Nodes (Node kind + reference) that got merged during type extension merging. - MergedTypeExtensions []Node -} - -// Reset empties the Index -func (i *Index) Reset() { - i.QueryTypeName = i.QueryTypeName[:0] - i.MutationTypeName = i.MutationTypeName[:0] - i.SubscriptionTypeName = i.SubscriptionTypeName[:0] - i.ReplacedFragmentSpreads = i.ReplacedFragmentSpreads[:0] - i.MergedTypeExtensions = i.MergedTypeExtensions[:0] - for j := range i.nodes { - delete(i.nodes, j) - } -} - -func (i *Index) AddNodeStr(name string, node Node) { - hash := xxhash.Sum64String(name) - _, exists := i.nodes[hash] - if !exists { - i.nodes[hash] = []Node{node} - return - } - i.nodes[hash] = append(i.nodes[hash], node) -} - -func (i *Index) AddNodeBytes(name []byte, node Node) { - hash := xxhash.Sum64(name) - _, exists := i.nodes[hash] - if !exists { - i.nodes[hash] = []Node{node} - return - } - i.nodes[hash] = append(i.nodes[hash], node) -} - -func (i *Index) NodesByNameStr(name string) ([]Node, bool) { - hash := xxhash.Sum64String(name) - node, exists := i.nodes[hash] - return node, exists -} - -func (i *Index) FirstNodeByNameStr(name string) (Node, bool) { - hash := xxhash.Sum64String(name) - node, exists := i.nodes[hash] - if !exists || len(node) == 0 { - return InvalidNode, false - } - return node[0], true -} - -func (i *Index) NodesByNameBytes(name []byte) ([]Node, bool) { - hash := xxhash.Sum64(name) - node, exists := i.nodes[hash] - return node, exists -} - -func (i *Index) FirstNodeByNameBytes(name []byte) (Node, bool) { - hash := xxhash.Sum64(name) - node, exists := i.nodes[hash] - if !exists || len(node) == 0 { - return InvalidNode, false - } - return node[0], true -} - -func (i *Index) FirstNonExtensionNodeByNameBytes(name []byte) (Node, bool) { - hash := xxhash.Sum64(name) - nodes, exists := i.nodes[hash] - if !exists || len(nodes) == 0 { - return InvalidNode, false - } - - for j := range nodes { - if nodes[j].IsExtensionKind() { - continue - } - - return nodes[j], true - } - - return InvalidNode, false -} - -func (i *Index) RemoveNodeByName(name []byte) { - hash := xxhash.Sum64(name) - delete(i.nodes, hash) - - if bytes.Equal(i.QueryTypeName, name) { - i.QueryTypeName = nil - } - - if bytes.Equal(i.MutationTypeName, name) { - i.MutationTypeName = nil - } - - if bytes.Equal(i.SubscriptionTypeName, name) { - i.SubscriptionTypeName = nil - } -} - -func (i *Index) ReplaceNode(name []byte, oldNode Node, newNode Node) { - nodes, ok := i.nodes[xxhash.Sum64(name)] - if !ok { - return - } - - for i := range nodes { - if nodes[i].Kind != oldNode.Kind || nodes[i].Ref != oldNode.Ref { - continue - } - - nodes[i].Kind = newNode.Kind - nodes[i].Ref = newNode.Ref - } -} - -func (i *Index) IsRootOperationTypeNameBytes(typeName []byte) bool { - if len(typeName) == 0 { - return false - } - if bytes.Equal(i.QueryTypeName, typeName) { - return true - } - if bytes.Equal(i.MutationTypeName, typeName) { - return true - } - if bytes.Equal(i.SubscriptionTypeName, typeName) { - return true - } - return false -} - -func (i *Index) IsRootOperationTypeNameString(typeName string) bool { - if typeName == "" { - return false - } - if unsafebytes.BytesToString(i.QueryTypeName) == typeName { - return true - } - if unsafebytes.BytesToString(i.MutationTypeName) == typeName { - return true - } - if unsafebytes.BytesToString(i.SubscriptionTypeName) == typeName { - return true - } - return false -} diff --git a/pkg/ast/index_test.go b/pkg/ast/index_test.go deleted file mode 100644 index 2d12ed1ea..000000000 --- a/pkg/ast/index_test.go +++ /dev/null @@ -1,225 +0,0 @@ -package ast - -import ( - "testing" - - "github.com/cespare/xxhash/v2" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func emptyIndex() Index { - return Index{nodes: make(map[uint64][]Node, 48)} -} - -func TestIndex_Add(t *testing.T) { - var ( - node = Node{Kind: NodeKindSchemaDefinition, Ref: 0} - name = "mynode" - nodeHash = uint64(8262329559045341693) - ) - - t.Run("AddNodeStr", func(t *testing.T) { - idx := emptyIndex() - - idx.AddNodeBytes([]byte(name), node) - expectedIdx := Index{nodes: map[uint64][]Node{nodeHash: {node}}} - assert.Equal(t, expectedIdx, idx) - - t.Run("add same node second time", func(t *testing.T) { - idx.AddNodeBytes([]byte(name), node) - expectedIdx = Index{nodes: map[uint64][]Node{nodeHash: {node, node}}} - assert.Equal(t, expectedIdx, idx) - }) - }) - - t.Run("AddNodeBytes", func(t *testing.T) { - idx := emptyIndex() - - idx.AddNodeStr(name, node) - expectedIdx := Index{nodes: map[uint64][]Node{nodeHash: {node}}} - assert.Equal(t, expectedIdx, idx) - - t.Run("add same node second time", func(t *testing.T) { - idx.AddNodeStr(name, node) - expectedIdx = Index{nodes: map[uint64][]Node{nodeHash: {node, node}}} - assert.Equal(t, expectedIdx, idx) - }) - }) - - t.Run("Add a few nodes", func(t *testing.T) { - var ( - otherNode = Node{Kind: NodeKindField, Ref: 0} - otherName = "myothernode" - otherNodeHash = uint64(3699437218065365471) - ) - - idx := emptyIndex() - idx.AddNodeStr(name, node) - idx.AddNodeStr(otherName, otherNode) - - expectedIdx := Index{nodes: map[uint64][]Node{ - nodeHash: {node}, - otherNodeHash: {otherNode}, - }} - assert.Equal(t, expectedIdx, idx) - }) -} - -func TestIndex_Reset(t *testing.T) { - var ( - nodeHash = uint64(8262329559045341693) - node = Node{Kind: NodeKindField, Ref: 0} - ) - - idx := Index{nodes: map[uint64][]Node{nodeHash: {node}}} - idx.Reset() - assert.Equal(t, emptyIndex(), idx) -} - -func TestIndex_RemoveNodeByName(t *testing.T) { - var ( - node = Node{Kind: NodeKindSchemaDefinition, Ref: 0} - nodeName = []byte("Schema") - nodeHash = uint64(419120142902365632) - - queryNode = Node{Kind: NodeKindObjectTypeDefinition, Ref: 1} - queryTypeName = []byte("QueryType") - queryNodeHash = uint64(11055297907069788501) - - mutationNode = Node{Kind: NodeKindObjectTypeDefinition, Ref: 2} - mutationTypeName = []byte("MutationType") - mutationNodeHash = uint64(11562542109605516176) - - subNode = Node{Kind: NodeKindObjectTypeDefinition, Ref: 3} - subTypeName = []byte("SubscriptionType") - subNodeHash = uint64(621582639512712731) - ) - - createIndex := func() Index { - return Index{ - QueryTypeName: queryTypeName, - MutationTypeName: mutationTypeName, - SubscriptionTypeName: subTypeName, - nodes: map[uint64][]Node{ - nodeHash: {node}, - queryNodeHash: {queryNode}, - mutationNodeHash: {mutationNode}, - subNodeHash: {subNode}, - }, - } - } - - t.Run("remove node", func(t *testing.T) { - idx := createIndex() - idx.RemoveNodeByName(nodeName) - expectedIdx := Index{ - QueryTypeName: queryTypeName, - MutationTypeName: mutationTypeName, - SubscriptionTypeName: subTypeName, - nodes: map[uint64][]Node{ - queryNodeHash: {queryNode}, - mutationNodeHash: {mutationNode}, - subNodeHash: {subNode}, - }, - } - assert.Equal(t, expectedIdx, idx) - }) - - t.Run("remove query", func(t *testing.T) { - idx := createIndex() - idx.RemoveNodeByName(queryTypeName) - expectedIdx := Index{ - MutationTypeName: mutationTypeName, - SubscriptionTypeName: subTypeName, - nodes: map[uint64][]Node{ - nodeHash: {node}, - mutationNodeHash: {mutationNode}, - subNodeHash: {subNode}, - }, - } - assert.Equal(t, expectedIdx, idx) - }) - - t.Run("remove mutation", func(t *testing.T) { - idx := createIndex() - idx.RemoveNodeByName(mutationTypeName) - expectedIdx := Index{ - QueryTypeName: queryTypeName, - SubscriptionTypeName: subTypeName, - nodes: map[uint64][]Node{ - nodeHash: {node}, - queryNodeHash: {queryNode}, - subNodeHash: {subNode}, - }, - } - assert.Equal(t, expectedIdx, idx) - }) - - t.Run("remove subscription", func(t *testing.T) { - idx := createIndex() - idx.RemoveNodeByName(subTypeName) - expectedIdx := Index{ - QueryTypeName: queryTypeName, - MutationTypeName: mutationTypeName, - nodes: map[uint64][]Node{ - nodeHash: {node}, - queryNodeHash: {queryNode}, - mutationNodeHash: {mutationNode}, - }, - } - assert.Equal(t, expectedIdx, idx) - }) - - t.Run("remove root types", func(t *testing.T) { - idx := createIndex() - idx.RemoveNodeByName(queryTypeName) - idx.RemoveNodeByName(mutationTypeName) - idx.RemoveNodeByName(subTypeName) - - expectedIdx := Index{ - nodes: map[uint64][]Node{ - nodeHash: {node}, - }, - } - assert.Equal(t, expectedIdx, idx) - }) -} - -func TestIndex_ReplaceNode(t *testing.T) { - t.Run("should replace node (kind) with a new node", func(t *testing.T) { - idx := emptyIndex() - - unrelatedNode := Node{ - Kind: NodeKindObjectTypeDefinition, - Ref: 5, - } - nodeBefore := Node{ - Kind: NodeKindObjectTypeDefinition, - Ref: 1, - } - - idx.AddNodeStr("User", unrelatedNode) - idx.AddNodeStr("User", nodeBefore) - expectedIndexBefore := Index{ - nodes: map[uint64][]Node{ - xxhash.Sum64String("User"): {unrelatedNode, nodeBefore}, - }, - } - - require.Equal(t, expectedIndexBefore, idx) - - newNode := Node{ - Kind: NodeKindObjectTypeExtension, - Ref: 2, - } - idx.ReplaceNode([]byte("User"), nodeBefore, newNode) - expectedIndexAfter := Index{ - nodes: map[uint64][]Node{ - xxhash.Sum64String("User"): {unrelatedNode, newNode}, - }, - } - - assert.Equal(t, expectedIndexAfter, idx) - }) -} diff --git a/pkg/ast/input.go b/pkg/ast/input.go deleted file mode 100644 index 262de545d..000000000 --- a/pkg/ast/input.go +++ /dev/null @@ -1,155 +0,0 @@ -package ast - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -// Input is a raw graphql document containing the raw input + meta data -type Input struct { - // RawBytes is the raw byte input - RawBytes []byte - // Length of RawBytes - Length int - // InputPosition is the current position in the RawBytes - InputPosition int - // TextPosition is the current position within the text (line and character information about the current Tokens) - TextPosition position.Position - // Variables are the json encoded variables of the operation - Variables []byte -} - -// Reset empties the Input -func (i *Input) Reset() { - i.RawBytes = i.RawBytes[:0] - i.Variables = i.Variables[:0] - i.InputPosition = 0 - i.TextPosition.Reset() -} - -// ResetInputBytes empties the input and sets it to bytes argument -func (i *Input) ResetInputBytes(bytes []byte) { - i.Reset() - i.AppendInputBytes(bytes) - i.Length = len(i.RawBytes) -} - -// ResetInputString empties the input and sets it to input string. -func (i *Input) ResetInputString(input string) { - i.ResetInputBytes([]byte(input)) -} - -// AppendInputBytes appends a byte slice to the current input and returns the ByteSliceReference -func (i *Input) AppendInputBytes(bytes []byte) (ref ByteSliceReference) { - ref.Start = uint32(len(i.RawBytes)) - i.RawBytes = append(i.RawBytes, bytes...) - i.Length = len(i.RawBytes) - ref.End = uint32(len(i.RawBytes)) - return -} - -// AppendInputString appends a string to the current input and returns the ByteSliceReference -func (i *Input) AppendInputString(input string) ByteSliceReference { - return i.AppendInputBytes([]byte(input)) -} - -// ByteSlice returns the byte slice for a given byte ByteSliceReference -func (i *Input) ByteSlice(reference ByteSliceReference) ByteSlice { - return i.RawBytes[reference.Start:reference.End] -} - -// ByteSliceString returns a string for a given ByteSliceReference -func (i *Input) ByteSliceString(reference ByteSliceReference) string { - return unsafebytes.BytesToString(i.ByteSlice(reference)) -} - -// ByteSliceReferenceContentEquals compares the content of two byte slices and returns true if they are the same -func (i *Input) ByteSliceReferenceContentEquals(left, right ByteSliceReference) bool { - if left.Length() != right.Length() { - return false - } - length := int(left.Length()) - for k := 0; k < length; k++ { - if i.RawBytes[int(left.Start)+k] != i.RawBytes[int(right.Start)+k] { - return false - } - } - return true -} - -// ByteSlice is an alias for []byte -type ByteSlice []byte - -// Equals compares a ByteSlice to another -func (b ByteSlice) Equals(another ByteSlice) bool { - if len(b) != len(another) { - return false - } - return bytes.Equal(b, another) -} - -func (b ByteSlice) String() string { - return unsafebytes.BytesToString(b) -} - -func (b ByteSlice) MarshalJSON() ([]byte, error) { - return append(append(literal.QUOTE, b...), literal.QUOTE...), nil -} - -type ByteSlices []ByteSlice - -func (b ByteSlices) String() string { - out := "[" - for i := range b { - if i != 0 { - out += "," - } - out += string(b[i]) - } - out += "]" - return out -} - -type ByteSliceReference struct { - Start uint32 - End uint32 -} - -func (b ByteSliceReference) Length() uint32 { - return b.End - b.Start -} - -// ByteSliceEquals compares two ByteSliceReferences from different Inputs -func ByteSliceEquals(left ByteSliceReference, leftInput Input, right ByteSliceReference, rightInput Input) bool { - if left.Length() != right.Length() { - return false - } - length := int(left.Length()) - for i := 0; i < length; i++ { - if leftInput.RawBytes[int(left.Start)+i] != rightInput.RawBytes[int(right.Start)+i] { - return false - } - } - return true -} - -type ByteSliceReferences []ByteSliceReference - -func (b ByteSliceReferences) String(input *Input) string { - out := "[" - for i := range b { - if i != 0 { - out += "," - } - if b[i].Length() == 0 { - out += "query" - } else { - out += input.ByteSliceString(b[i]) - } - } - out += "]" - return out -} diff --git a/pkg/ast/path.go b/pkg/ast/path.go deleted file mode 100644 index 06fff9da9..000000000 --- a/pkg/ast/path.go +++ /dev/null @@ -1,113 +0,0 @@ -package ast - -import ( - "bytes" - "fmt" - "strconv" - "unsafe" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -type PathKind int - -const ( - UnknownPathKind PathKind = iota - ArrayIndex - FieldName -) - -type PathItem struct { - Kind PathKind - ArrayIndex int - FieldName ByteSlice -} - -type Path []PathItem - -func (p Path) Equals(another Path) bool { - if len(p) != len(another) { - return false - } - for i := range p { - if p[i].Kind != another[i].Kind { - return false - } - if p[i].Kind == ArrayIndex && p[i].ArrayIndex != another[i].ArrayIndex { - return false - } else if !bytes.Equal(p[i].FieldName, another[i].FieldName) { - return false - } - } - return true -} - -func (p Path) String() string { - out := "[" - for i := range p { - if i != 0 { - out += "," - } - switch p[i].Kind { - case ArrayIndex: - out += strconv.Itoa(p[i].ArrayIndex) - case FieldName: - if len(p[i].FieldName) == 0 { - out += "query" - } else { - out += unsafebytes.BytesToString(p[i].FieldName) - } - } - } - out += "]" - return out -} - -func (p Path) DotDelimitedString() string { - out := "" - for i := range p { - if i != 0 { - out += "." - } - switch p[i].Kind { - case ArrayIndex: - out += strconv.Itoa(p[i].ArrayIndex) - case FieldName: - if len(p[i].FieldName) == 0 { - out += "query" - } else { - out += unsafebytes.BytesToString(p[i].FieldName) - } - } - } - return out -} - -func (p *PathItem) UnmarshalJSON(data []byte) error { - if data == nil { - return fmt.Errorf("data must not be nil") - } - if data[0] == '"' && data[len(data)-1] == '"' { - p.Kind = FieldName - p.FieldName = data[1 : len(data)-1] - return nil - } - out, err := strconv.ParseInt(*(*string)(unsafe.Pointer(&data)), 10, 32) - if err != nil { - return err - } - p.Kind = ArrayIndex - p.ArrayIndex = int(out) - return nil -} - -func (p PathItem) MarshalJSON() ([]byte, error) { - switch p.Kind { - case ArrayIndex: - return strconv.AppendInt(nil, int64(p.ArrayIndex), 10), nil - case FieldName: - return append([]byte("\""), append(p.FieldName, []byte("\"")...)...), nil - default: - return nil, fmt.Errorf("cannot marshal unknown PathKind") - } -} diff --git a/pkg/astimport/astimport.go b/pkg/astimport/astimport.go deleted file mode 100644 index f1c5030c0..000000000 --- a/pkg/astimport/astimport.go +++ /dev/null @@ -1,229 +0,0 @@ -// Package astimport can be used to import Nodes manually into an AST. -// -// This is useful when an AST should be created manually. -package astimport - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -// Importer imports Nodes into an existing AST. -// Always use NewImporter() to create a new Importer. -type Importer struct { -} - -func (i *Importer) ImportDirective(ref int, from, to *ast.Document) int { - name := string(from.Input.ByteSlice(from.Directives[ref].Name)) - args := i.ImportArguments(from.Directives[ref].Arguments.Refs, from, to) - return to.AddDirective(ast.Directive{ - Name: to.Input.AppendInputString(name), - HasArguments: len(args) != 0, - Arguments: ast.ArgumentList{ - Refs: args, - }, - }) -} - -func (i *Importer) ImportDirectiveWithRename(ref int, renameTo string, from, to *ast.Document) int { - args := i.ImportArguments(from.Directives[ref].Arguments.Refs, from, to) - return to.AddDirective(ast.Directive{ - Name: to.Input.AppendInputString(renameTo), - HasArguments: len(args) != 0, - Arguments: ast.ArgumentList{ - Refs: args, - }, - }) -} - -func (i *Importer) ImportType(ref int, from, to *ast.Document) int { - - astType := ast.Type{ - TypeKind: from.Types[ref].TypeKind, - OfType: -1, - } - - if astType.TypeKind == ast.TypeKindNamed { - astType.Name = to.Input.AppendInputBytes(from.TypeNameBytes(ref)) - } - - if from.Types[ref].OfType != -1 { - astType.OfType = i.ImportType(from.Types[ref].OfType, from, to) - } - - to.Types = append(to.Types, astType) - return len(to.Types) - 1 -} - -func (i *Importer) ImportTypeWithRename(ref int, from, to *ast.Document, renameTo string) int { - - astType := ast.Type{ - TypeKind: from.Types[ref].TypeKind, - OfType: -1, - } - - if astType.TypeKind == ast.TypeKindNamed { - astType.Name = to.Input.AppendInputString(renameTo) - } - - if from.Types[ref].OfType != -1 { - astType.OfType = i.ImportTypeWithRename(from.Types[ref].OfType, from, to, renameTo) - } - - to.Types = append(to.Types, astType) - return len(to.Types) - 1 -} - -func (i *Importer) ImportValue(fromValue ast.Value, from, to *ast.Document) (value ast.Value) { - value.Kind = fromValue.Kind - - switch fromValue.Kind { - case ast.ValueKindFloat: - value.Ref = to.ImportFloatValue( - from.FloatValueRaw(fromValue.Ref), - from.FloatValueIsNegative(fromValue.Ref)) - - case ast.ValueKindInteger: - value.Ref = to.ImportIntValue( - from.IntValueRaw(fromValue.Ref), - from.IntValueIsNegative(fromValue.Ref)) - - case ast.ValueKindBoolean: - value.Ref = fromValue.Ref - - case ast.ValueKindString: - value.Ref = to.ImportStringValue( - from.StringValueContentBytes(fromValue.Ref), - from.StringValueIsBlockString(fromValue.Ref)) - - case ast.ValueKindNull: - // empty case - - case ast.ValueKindEnum: - value.Ref = to.ImportEnumValue(from.EnumValueNameBytes(fromValue.Ref)) - - case ast.ValueKindVariable: - value.Ref = to.ImportVariableValue(from.VariableValueNameBytes(fromValue.Ref)) - - case ast.ValueKindList: - value.Ref = to.ImportListValue(i.ImportListValues(fromValue.Ref, from, to)) - - case ast.ValueKindObject: - value.Ref = to.ImportObjectValue(i.ImportObjectFields(fromValue.Ref, from, to)) - - default: - value.Kind = ast.ValueKindUnknown - fmt.Printf("astimport.Importer.ImportValue: not implemented for ValueKind: %s\n", fromValue.Kind) - } - return -} - -func (i *Importer) ImportObjectFields(ref int, from, to *ast.Document) (refs []int) { - objValue := from.ObjectValues[ref] - - for _, fieldRef := range objValue.Refs { - objectField := from.ObjectFields[fieldRef] - - refs = append(refs, to.ImportObjectField( - from.ObjectFieldNameBytes(fieldRef), - i.ImportValue(objectField.Value, from, to))) - } - return -} - -func (i *Importer) ImportListValues(ref int, from, to *ast.Document) (refs []int) { - listValue := from.ListValues[ref] - - for _, valueRef := range listValue.Refs { - value := i.ImportValue(from.Values[valueRef], from, to) - refs = append(refs, to.AddValue(value)) - } - return -} - -func (i *Importer) ImportArgument(ref int, from, to *ast.Document) int { - arg := ast.Argument{ - Name: to.Input.AppendInputBytes(from.ArgumentNameBytes(ref)), - Value: i.ImportValue(from.ArgumentValue(ref), from, to), - } - to.Arguments = append(to.Arguments, arg) - return len(to.Arguments) - 1 -} - -func (i *Importer) ImportArguments(refs []int, from, to *ast.Document) []int { - args := make([]int, len(refs)) - for j, k := range refs { - args[j] = i.ImportArgument(k, from, to) - } - return args -} - -func (i *Importer) ImportVariableDefinition(ref int, from, to *ast.Document) int { - - variableDefinition := ast.VariableDefinition{ - VariableValue: i.ImportValue(from.VariableDefinitions[ref].VariableValue, from, to), - Type: i.ImportType(from.VariableDefinitions[ref].Type, from, to), - DefaultValue: ast.DefaultValue{ - IsDefined: from.VariableDefinitions[ref].DefaultValue.IsDefined, - }, - // HasDirectives: false, //TODO: implement import directives - // Directives: ast.DirectiveList{}, - } - - if from.VariableDefinitions[ref].DefaultValue.IsDefined { - variableDefinition.DefaultValue.Value = i.ImportValue(from.VariableDefinitions[ref].DefaultValue.Value, from, to) - } - - to.VariableDefinitions = append(to.VariableDefinitions, variableDefinition) - return len(to.VariableDefinitions) - 1 -} - -func (i *Importer) ImportVariableDefinitionWithRename(ref int, from, to *ast.Document, renameTo string) int { - - variableDefinition := ast.VariableDefinition{ - VariableValue: i.ImportValue(from.VariableDefinitions[ref].VariableValue, from, to), - Type: i.ImportTypeWithRename(from.VariableDefinitions[ref].Type, from, to, renameTo), - DefaultValue: ast.DefaultValue{ - IsDefined: from.VariableDefinitions[ref].DefaultValue.IsDefined, - }, - // HasDirectives: false, //TODO: implement import directives - // Directives: ast.DirectiveList{}, - } - - if from.VariableDefinitions[ref].DefaultValue.IsDefined { - variableDefinition.DefaultValue.Value = i.ImportValue(from.VariableDefinitions[ref].DefaultValue.Value, from, to) - } - - to.VariableDefinitions = append(to.VariableDefinitions, variableDefinition) - return len(to.VariableDefinitions) - 1 -} - -func (i *Importer) ImportVariableDefinitions(refs []int, from, to *ast.Document) []int { - definitions := make([]int, len(refs)) - for j, k := range refs { - definitions[j] = i.ImportVariableDefinition(k, from, to) - } - return definitions -} - -func (i *Importer) ImportField(ref int, from, to *ast.Document) int { - field := ast.Field{ - Alias: ast.Alias{ - IsDefined: from.FieldAliasIsDefined(ref), - }, - Name: to.Input.AppendInputBytes(from.FieldNameBytes(ref)), - HasArguments: from.FieldHasArguments(ref), - // HasDirectives: from.FieldHasDirectives(ref), // HasDirectives: false, //TODO: implement import directives - SelectionSet: -1, - HasSelections: false, - } - if field.Alias.IsDefined { - field.Alias.Name = to.Input.AppendInputBytes(from.FieldAliasBytes(ref)) - } - if field.HasArguments { - field.Arguments.Refs = i.ImportArguments(from.FieldArguments(ref), from, to) - } - to.Fields = append(to.Fields, field) - return len(to.Fields) - 1 -} diff --git a/pkg/astimport/astimport_test.go b/pkg/astimport/astimport_test.go deleted file mode 100644 index 0f0bd2c32..000000000 --- a/pkg/astimport/astimport_test.go +++ /dev/null @@ -1,320 +0,0 @@ -package astimport - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestImporter_ImportType(t *testing.T) { - for _, typeDef := range []string{ - "ID!", - "[String]!", - "[String!]!", - "FooType", - } { - typeBytes := []byte(typeDef) - from := ast.NewDocument() - from.Input.AppendInputBytes(typeBytes) - report := &operationreport.Report{} - parser := astparser.NewParser() - parser.PrepareImport(from, report) - ref := parser.ParseType() - - if report.HasErrors() { - t.Fatal(report) - } - - out, err := from.PrintTypeBytes(ref, nil) - require.NoError(t, err) - require.Equal(t, typeBytes, out) - - to := ast.NewDocument() - importer := &Importer{} - - ref = importer.ImportType(ref, from, to) - out, err = to.PrintTypeBytes(ref, nil) - require.NoError(t, err) - require.Equal(t, typeBytes, out) - } -} - -func TestImporter_ImportValue(t *testing.T) { - for _, tc := range []struct { - value, name string - kind ast.ValueKind - }{ - {"111", "integer", ast.ValueKindInteger}, - {"-111", "negative integer", ast.ValueKindInteger}, - {"11.1", "float", ast.ValueKindFloat}, - {"-11.1", "negative float", ast.ValueKindFloat}, - {`"bobby"`, "string", ast.ValueKindString}, - {"ENUM_VALUE", "enum", ast.ValueKindEnum}, - {`{one: "one"}`, "object", ast.ValueKindObject}, - {"true", "bool", ast.ValueKindBoolean}, - {"[1,2]", "list", ast.ValueKindList}, - {"[[1,2]]", "nested list", ast.ValueKindList}, - {`[{a: "b"},{c: "d"}]`, "list with objects", ast.ValueKindList}, - {`[[{a: "b",c: [1,2]}]]`, "deep nested list", ast.ValueKindList}, - } { - t.Run(tc.name, func(t *testing.T) { - valueBytes := []byte(tc.value) - - from := ast.NewDocument() - from.Input.AppendInputBytes(valueBytes) - - report := &operationreport.Report{} - parser := astparser.NewParser() - parser.PrepareImport(from, report) - - value := parser.ParseValue() - require.Equal(t, value.Kind, tc.kind) - - if report.HasErrors() { - t.Fatal(report) - } - - out, err := from.PrintValueBytes(value, nil) - require.NoError(t, err) - require.Equal(t, valueBytes, out) - - to := ast.NewDocument() - importer := &Importer{} - - value = importer.ImportValue(value, from, to) - out, err = to.PrintValueBytes(value, nil) - require.NoError(t, err) - require.Equal(t, valueBytes, out) - }) - } -} - -func TestImporter_ImportVariableDefinitions(t *testing.T) { - run := func(source ast.Document, target ast.Document, refs []int, expectedDocument ast.Document, expectedRefs []int) func(t *testing.T) { - return func(t *testing.T) { - importer := &Importer{} - actualRefs := importer.ImportVariableDefinitions(refs, &source, &target) - - assert.Equal(t, expectedRefs, actualRefs) - assert.Equal(t, expectedDocument, target) - } - } - - t.Run("should not import variables if source does not have variables", run( - ast.Document{}, - ast.Document{}, - []int{}, - ast.Document{}, - []int{}, - )) - - t.Run("should import a single variable with value", run( - ast.Document{ - Input: ast.Input{ - RawBytes: []byte("abEUDE"), - }, - Types: []ast.Type{ - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 2, - End: 4, - }, - OfType: -1, - }, - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 4, - End: 6, - }, - OfType: -1, - }, - }, - VariableValues: []ast.VariableValue{ - { - Name: ast.ByteSliceReference{ - Start: 0, - End: 1, - }, - }, - { - Name: ast.ByteSliceReference{ - Start: 1, - End: 2, - }, - }, - }, - VariableDefinitions: []ast.VariableDefinition{ - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 0, - }, - Type: 0, - }, - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 1, - }, - Type: 1, - }, - }, - }, - ast.Document{}, - []int{1}, - ast.Document{ - Input: ast.Input{ - RawBytes: []byte("bDE"), - Length: 3, - }, - Types: []ast.Type{ - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 1, - End: 3, - }, - OfType: -1, - }, - }, - VariableValues: []ast.VariableValue{ - { - Name: ast.ByteSliceReference{ - Start: 0, - End: 1, - }, - }, - }, - VariableDefinitions: []ast.VariableDefinition{ - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 0, - }, - Type: 0, - }, - }, - }, - []int{0}, - )) - - t.Run("should import all variables with values", run( - ast.Document{ - Input: ast.Input{ - RawBytes: []byte("abEUDE"), - }, - Types: []ast.Type{ - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 2, - End: 4, - }, - OfType: -1, - }, - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 4, - End: 6, - }, - OfType: -1, - }, - }, - VariableValues: []ast.VariableValue{ - { - Name: ast.ByteSliceReference{ - Start: 0, - End: 1, - }, - }, - { - Name: ast.ByteSliceReference{ - Start: 1, - End: 2, - }, - }, - }, - VariableDefinitions: []ast.VariableDefinition{ - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 0, - }, - Type: 0, - }, - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 1, - }, - Type: 1, - }, - }, - }, - ast.Document{}, - []int{0, 1}, - ast.Document{ - Input: ast.Input{ - RawBytes: []byte("aEUbDE"), - Length: 6, - }, - Types: []ast.Type{ - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 1, - End: 3, - }, - OfType: -1, - }, - { - TypeKind: ast.TypeKindNamed, - Name: ast.ByteSliceReference{ - Start: 4, - End: 6, - }, - OfType: -1, - }, - }, - VariableValues: []ast.VariableValue{ - { - Name: ast.ByteSliceReference{ - Start: 0, - End: 1, - }, - }, - { - Name: ast.ByteSliceReference{ - Start: 3, - End: 4, - }, - }, - }, - VariableDefinitions: []ast.VariableDefinition{ - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 0, - }, - Type: 0, - }, - { - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: 1, - }, - Type: 1, - }, - }, - }, - []int{0, 1}, - )) -} diff --git a/pkg/astnormalization/astnormalization.go b/pkg/astnormalization/astnormalization.go deleted file mode 100644 index 7cb6e1852..000000000 --- a/pkg/astnormalization/astnormalization.go +++ /dev/null @@ -1,240 +0,0 @@ -/* -Package astnormalization helps to transform parsed GraphQL AST's into a easier to use structure. - -# Example - -This examples shows how the normalization package helps "simplifying" a GraphQL AST. - -Input: - - subscription sub { - ... multipleSubscriptions - ... on Subscription { - newMessage { - body - sender - } - } - } - fragment newMessageFields on Message { - body: body - sender - ... on Body { - body - } - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - newMessage { - ... newMessageFields - } - newMessage { - body - body - sender - } - ... on Subscription { - newMessage { - body - sender - } - } - disallowedSecondRootField - } - -Output: - - subscription sub { - newMessage { - body - sender - } - disallowedSecondRootField - } - fragment newMessageFields on Message { - body - sender - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - } -*/ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// NormalizeOperation creates a default Normalizer and applies all rules to a given AST -// In case you're using OperationNormalizer in a hot path you shouldn't be using this function. -// Create a new OperationNormalizer using NewNormalizer() instead and re-use it. -func NormalizeOperation(operation, definition *ast.Document, report *operationreport.Report) { - normalizer := NewNormalizer(false, false) - normalizer.NormalizeOperation(operation, definition, report) -} - -func NormalizeNamedOperation(operation, definition *ast.Document, operationName []byte, report *operationreport.Report) { - normalizer := NewNormalizer(true, true) - normalizer.NormalizeNamedOperation(operation, definition, operationName, report) -} - -// OperationNormalizer walks a given AST and applies all registered rules -type OperationNormalizer struct { - operationWalkers []*astvisitor.Walker - variablesExtraction *variablesExtractionVisitor - options options - definitionNormalizer *DefinitionNormalizer -} - -// NewNormalizer creates a new OperationNormalizer and sets up all default rules -func NewNormalizer(removeFragmentDefinitions, extractVariables bool) *OperationNormalizer { - normalizer := &OperationNormalizer{ - options: options{ - removeFragmentDefinitions: removeFragmentDefinitions, - extractVariables: extractVariables, - }, - } - normalizer.setupOperationWalkers() - return normalizer -} - -// NewWithOpts creates a new OperationNormalizer with Options -func NewWithOpts(opts ...Option) *OperationNormalizer { - var options options - for _, opt := range opts { - opt(&options) - } - normalizer := &OperationNormalizer{ - options: options, - } - normalizer.setupOperationWalkers() - - if options.normalizeDefinition { - normalizer.definitionNormalizer = NewDefinitionNormalizer() - } - - return normalizer -} - -type options struct { - removeFragmentDefinitions bool - extractVariables bool - removeUnusedVariables bool - normalizeDefinition bool -} - -type Option func(options *options) - -func WithExtractVariables() Option { - return func(options *options) { - options.extractVariables = true - } -} - -func WithRemoveFragmentDefinitions() Option { - return func(options *options) { - options.removeFragmentDefinitions = true - } -} - -func WithRemoveUnusedVariables() Option { - return func(options *options) { - options.removeUnusedVariables = true - } -} - -func WithNormalizeDefinition() Option { - return func(options *options) { - options.normalizeDefinition = true - } -} - -func (o *OperationNormalizer) setupOperationWalkers() { - o.operationWalkers = make([]*astvisitor.Walker, 0, 4) - - fragmentInline := astvisitor.NewWalker(48) - fragmentSpreadInline(&fragmentInline) - directiveIncludeSkip(&fragmentInline) - o.operationWalkers = append(o.operationWalkers, &fragmentInline) - - if o.options.extractVariables { - extractVariablesWalker := astvisitor.NewWalker(48) - o.variablesExtraction = extractVariables(&extractVariablesWalker) - o.operationWalkers = append(o.operationWalkers, &extractVariablesWalker) - } - - other := astvisitor.NewWalker(48) - removeSelfAliasing(&other) - mergeInlineFragments(&other) - mergeFieldSelections(&other) - deduplicateFields(&other) - - if o.options.removeFragmentDefinitions { - removeFragmentDefinitions(&other) - } - if o.options.removeUnusedVariables { - deleteUnusedVariables(&other) - } - o.operationWalkers = append(o.operationWalkers, &other) - - if o.options.extractVariables { - variablesProcessing := astvisitor.NewWalker(48) - inputCoercionForList(&variablesProcessing) - extractVariablesDefaultValue(&variablesProcessing) - injectInputFieldDefaults(&variablesProcessing) - - o.operationWalkers = append(o.operationWalkers, &variablesProcessing) - } -} - -func (o *OperationNormalizer) prepareDefinition(definition *ast.Document, report *operationreport.Report) { - if o.definitionNormalizer != nil { - o.definitionNormalizer.NormalizeDefinition(definition, report) - } -} - -// NormalizeOperation applies all registered rules to the AST -func (o *OperationNormalizer) NormalizeOperation(operation, definition *ast.Document, report *operationreport.Report) { - if o.options.normalizeDefinition { - o.prepareDefinition(definition, report) - if report.HasErrors() { - return - } - } - - for i := range o.operationWalkers { - o.operationWalkers[i].Walk(operation, definition, report) - if report.HasErrors() { - return - } - } -} - -// NormalizeNamedOperation applies all registered rules to one specific named operation in the AST -func (o *OperationNormalizer) NormalizeNamedOperation(operation, definition *ast.Document, operationName []byte, report *operationreport.Report) { - if o.options.normalizeDefinition { - o.prepareDefinition(definition, report) - if report.HasErrors() { - return - } - } - - if o.variablesExtraction != nil { - o.variablesExtraction.operationName = operationName - } - for i := range o.operationWalkers { - o.operationWalkers[i].Walk(operation, definition, report) - if report.HasErrors() { - return - } - } -} diff --git a/pkg/astnormalization/astnormalization_test.go b/pkg/astnormalization/astnormalization_test.go deleted file mode 100644 index 75a65abde..000000000 --- a/pkg/astnormalization/astnormalization_test.go +++ /dev/null @@ -1,778 +0,0 @@ -package astnormalization - -import ( - "fmt" - "regexp" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeprinter" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestNormalizeOperation(t *testing.T) { - - run := func(t *testing.T, definition, operation, expectedOutput, variablesInput, expectedVariables string) { - t.Helper() - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(definition) - require.NoError(t, asttransform.MergeDefinitionWithBaseSchema(&definitionDocument)) - - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedOutput) - report := operationreport.Report{} - - if variablesInput != "" { - operationDocument.Input.Variables = []byte(variablesInput) - } - - normalizer := NewWithOpts( - WithExtractVariables(), - WithRemoveFragmentDefinitions(), - WithRemoveUnusedVariables(), - WithNormalizeDefinition(), - ) - normalizer.NormalizeOperation(&operationDocument, &definitionDocument, &report) - - if report.HasErrors() { - t.Fatal(report.Error()) - } - - got := mustString(astprinter.PrintString(&operationDocument, &definitionDocument)) - want := mustString(astprinter.PrintString(&expectedOutputDocument, &definitionDocument)) - - assert.Equal(t, want, got) - assert.Equal(t, expectedVariables, string(operationDocument.Input.Variables)) - } - - t.Run("complex", func(t *testing.T) { - run(t, testDefinition, ` - subscription sub { - ... multipleSubscriptions - ... on Subscription { - newMessage { - body - sender - } - } - } - fragment newMessageFields on Message { - body: body - sender - ... on Body { - body - } - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - newMessage { - ... newMessageFields - } - newMessage { - body - body - sender - } - ... on Subscription { - newMessage { - body - sender - } - } - disallowedSecondRootField - }`, ` - subscription sub { - newMessage { - body - sender - } - disallowedSecondRootField - }`, "", "") - }) - t.Run("inject default", func(t *testing.T) { - run(t, - injectDefaultValueDefinition, ` - query{elQuery(input:{fieldB: "dupa"})}`, - `query($a: elInput){elQuery(input: $a)}`, "", - `{"a":{"fieldB":"dupa","fieldA":"VALUE_A"}}`, - ) - }) - t.Run("fragments", func(t *testing.T) { - run(t, testDefinition, ` - query conflictingBecauseAlias ($unused: String) { - dog { - extras { ...frag } - extras { ...frag2 } - } - } - fragment frag on DogExtra { string1 } - fragment frag2 on DogExtra { string1: string }`, ` - query conflictingBecauseAlias { - dog { - extras { - string1 - string1: string - } - } - }`, `{"unused":"foo"}`, `{}`) - }) - t.Run("fragments", func(t *testing.T) { - run(t, variablesExtractionDefinition, ` - mutation HttpBinPost{ - httpBinPost(input: {foo: "bar"}){ - headers { - userAgent - } - data { - foo - } - } - }`, ` - mutation HttpBinPost($a: HttpBinPostInput){ - httpBinPost(input: $a){ - headers { - userAgent - } - data { - foo - } - } - }`, ``, `{"a":{"foo":"bar"}}`) - }) - t.Run("type extensions", func(t *testing.T) { - run(t, typeExtensionsDefinition, ` - { - findUserByLocation(loc: {lat: 1.000, lon: 2.000, planet: "EARTH"}) { - id - name - age - type { - ... on TrialUser { - __typename - enabled - } - ... on SubscribedUser { - __typename - subscription - } - } - metadata - } - }`, `query($a: Location){ - findUserByLocation(loc: $a) { - id - name - age - type { - ... on TrialUser { - __typename - enabled - } - ... on SubscribedUser { - __typename - subscription - } - } - metadata - } - }`, - `{"a": {"lat": 1.000, "lon": 2.000, "planet": "EARTH"}}`, - `{"a": {"lat":1.000,"lon":2.000,"planet":"EARTH"}}`) - }) - t.Run("use extended Query without explicit schema definition", func(t *testing.T) { - run(t, extendedRootOperationTypeDefinition, ` - { - me - }`, `{ - me - }`, ``, ``) - }) - t.Run("use extended Mutation without explicit schema definition", func(t *testing.T) { - run(t, extendedRootOperationTypeDefinition, ` - mutation { - increaseTextCounter - }`, `mutation { - increaseTextCounter - }`, ``, ``) - }) - t.Run("use extended Subscription without explicit schema definition", func(t *testing.T) { - run(t, extendedRootOperationTypeDefinition, ` - subscription { - textCounter - }`, `subscription { - textCounter - }`, ``, ``) - }) - - t.Run("default values", func(t *testing.T) { - run(t, testDefinition, ` - query { - simple - }`, `query($a: String) { - simple(input: $a) - }`, ``, `{"a":"foo"}`) - }) - t.Run("input list coercion inline", func(t *testing.T) { - run(t, inputCoercionForListDefinition, ` - query Foo { - inputWithList(input: {list:{foo:"bar",list:{foo:"bar2",list:{nested:{foo:"bar3",list:{foo:"bar4"}}}}}}) { - id - name - } - }`, `query Foo($a: InputWithList) { - inputWithList(input: $a) { - id - name - } - }`, `{}`, `{"a":{"list":[{"foo":"bar","list":[{"foo":"bar2","list":[{"nested":{"foo":"bar3","list":[{"foo":"bar4"}]}}]}]}]}}`) - }) - t.Run("input list coercion with extracted variables", func(t *testing.T) { - run(t, inputCoercionForListDefinition, ` - query ($input: InputWithListNestedList) { - inputWithListNestedList(input: $input) { - id - name - } - }`, `query ($input: InputWithListNestedList) { - inputWithListNestedList(input: $input) { - id - name - } - }`, `{"input":{"doubleList":{"foo":"bar","list":{"foo":"bar2","list":{"nested":{"foo":"bar3","list":{"foo":"bar4"}}}}}}}`, - `{"input":{"doubleList":[[{"foo":"bar","list":[{"foo":"bar2","list":[{"nested":{"foo":"bar3","list":[{"foo":"bar4"}]}}]}]}]]}}`) - }) -} - -func TestOperationNormalizer_NormalizeOperation(t *testing.T) { - t.Run("should return an error once on normalization with missing field", func(t *testing.T) { - schema := ` -type Query { - country: Country! -} - -type Country { - name: String! -} - -schema { - query: Query -} -` - - query := ` -{ - country { - nam - } -} -` - definition := unsafeparser.ParseGraphqlDocumentString(schema) - operation := unsafeparser.ParseGraphqlDocumentString(query) - - report := operationreport.Report{} - normalizer := NewNormalizer(true, true) - normalizer.NormalizeOperation(&operation, &definition, &report) - - assert.True(t, report.HasErrors()) - assert.Equal(t, 1, len(report.ExternalErrors)) - assert.Equal(t, 0, len(report.InternalErrors)) - assert.Equal(t, "external: field: nam not defined on type: Country, locations: [], path: [query,country,nam]", report.Error()) - }) -} - -func TestNewNormalizer(t *testing.T) { - schema := ` -scalar String - -type Query { - country: Country! -} - -type Country { - name: String! -} - -schema { - query: Query -} -` - query := `fragment Fields on Country {name} query Q {country {...Fields}}` - - runNormalization := func(t *testing.T, removeFragmentDefinitions bool, expectedOperation string) { - t.Helper() - - definition := unsafeparser.ParseGraphqlDocumentString(schema) - operation := unsafeparser.ParseGraphqlDocumentString(query) - - report := operationreport.Report{} - normalizer := NewNormalizer(removeFragmentDefinitions, true) - normalizer.NormalizeOperation(&operation, &definition, &report) - assert.False(t, report.HasErrors()) - fmt.Println(report) - - actualOperation := unsafeprinter.Print(&operation, nil) - assert.NotEqual(t, query, actualOperation) - assert.Equal(t, expectedOperation, actualOperation) - } - - t.Run("should respect remove fragment definitions option", func(t *testing.T) { - t.Run("when remove fragments: true", func(t *testing.T) { - runNormalization(t, true, `query Q {country {name}}`) - }) - - t.Run("when remove fragments: false", func(t *testing.T) { - runNormalization(t, false, `fragment Fields on Country {name} query Q {country {name}}`) - }) - }) -} - -func TestParseMissingBaseSchema(t *testing.T) { - const ( - schema = `type Query { - hello: String! - }` - - query = `query { hello }` - ) - definition, report := astparser.ParseGraphqlDocumentString(schema) - assert.False(t, report.HasErrors(), report.Error()) - doc := ast.NewDocument() - doc.Input.ResetInputString(query) - astparser.NewParser().Parse(doc, &report) - assert.False(t, report.HasErrors(), report.Error()) - normalizer := NewNormalizer(false, false) - normalizer.NormalizeOperation(doc, &definition, &report) - assert.True(t, report.HasErrors(), "normalization should report an error") - assert.Regexp(t, regexp.MustCompile("forget.*merge.*base.*schema"), report.Error(), "error should mention the user forgot to merge the base schema") -} - -func BenchmarkAstNormalization(b *testing.B) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(testOperation) - report := operationreport.Report{} - - normalizer := NewNormalizer(false, false) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - report.Reset() - normalizer.NormalizeOperation(&operation, &definition, &report) - } -} - -var mustString = func(str string, err error) string { - if err != nil { - panic(err) - } - return str -} - -type registerNormalizeFunc func(walker *astvisitor.Walker) -type registerNormalizeVariablesFunc func(walker *astvisitor.Walker) *variablesExtractionVisitor -type registerNormalizeVariablesDefaulValueFunc func(walker *astvisitor.Walker) *variablesDefaultValueExtractionVisitor -type registerNormalizeDeleteVariablesFunc func(walker *astvisitor.Walker) *deleteUnusedVariablesVisitor - -var runWithVariablesAssert = func(t *testing.T, registerVisitor func(walker *astvisitor.Walker), definition, operation, operationName, expectedOutput, variablesInput, expectedVariables string, additionalNormalizers ...registerNormalizeFunc) { - t.Helper() - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(definition) - err := asttransform.MergeDefinitionWithBaseSchema(&definitionDocument) - if err != nil { - panic(err) - } - - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedOutput) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - if variablesInput != "" { - operationDocument.Input.Variables = []byte(variablesInput) - } - - registerVisitor(&walker) - - for _, fn := range additionalNormalizers { - fn(&walker) - } - - walker.Walk(&operationDocument, &definitionDocument, &report) - // we run this walker twice because some normalizers may depend on other normalizers - // walking twice ensures that all prerequisites are met - // additionally, walking twice also ensures that the normalizers are idempotent - walker.Walk(&operationDocument, &definitionDocument, &report) - - if report.HasErrors() { - panic(report.Error()) - } - - actualAST := mustString(astprinter.PrintString(&operationDocument, &definitionDocument)) - expectedAST := mustString(astprinter.PrintString(&expectedOutputDocument, &definitionDocument)) - assert.Equal(t, expectedAST, actualAST) - actualVariables := string(operationDocument.Input.Variables) - assert.Equal(t, expectedVariables, actualVariables) -} - -var runWithVariables = func(t *testing.T, normalizeFunc registerNormalizeVariablesFunc, definition, operation, operationName, expectedOutput, variablesInput, expectedVariables string, additionalNormalizers ...registerNormalizeFunc) { - t.Helper() - - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - visitor := normalizeFunc(walker) - visitor.operationName = []byte(operationName) - }, definition, operation, operationName, expectedOutput, variablesInput, expectedVariables, additionalNormalizers...) -} - -var runWithVariablesDefaultValues = func(t *testing.T, normalizeFunc registerNormalizeVariablesDefaulValueFunc, definition, operation, operationName, expectedOutput, variablesInput, expectedVariables string) { - t.Helper() - - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - visitor := normalizeFunc(walker) - visitor.operationName = []byte(operationName) - }, definition, operation, operationName, expectedOutput, variablesInput, expectedVariables) -} - -var runWithDeleteUnusedVariables = func(t *testing.T, normalizeFunc registerNormalizeDeleteVariablesFunc, definition, operation, operationName, expectedOutput, variablesInput, expectedVariables string) { - t.Helper() - - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - visitor := normalizeFunc(walker) - visitor.operationName = []byte(operationName) - }, definition, operation, operationName, expectedOutput, variablesInput, expectedVariables) -} - -var run = func(normalizeFunc registerNormalizeFunc, definition, operation, expectedOutput string) { - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(definition) - err := asttransform.MergeDefinitionWithBaseSchema(&definitionDocument) - if err != nil { - panic(err) - } - - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedOutput) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - normalizeFunc(&walker) - - walker.Walk(&operationDocument, &definitionDocument, &report) - - if report.HasErrors() { - panic(report.Error()) - } - - got := mustString(astprinter.PrintString(&operationDocument, &definitionDocument)) - want := mustString(astprinter.PrintString(&expectedOutputDocument, &definitionDocument)) - - if want != got { - panic(fmt.Errorf("\nwant:\n%s\ngot:\n%s", want, got)) - } -} - -var runWithExpectedErrors = func(t *testing.T, normalizeFunc registerNormalizeVariablesFunc, definition, operation, expectedError string, additionalNormalizers ...registerNormalizeFunc) { - t.Helper() - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(definition) - err := asttransform.MergeDefinitionWithBaseSchema(&definitionDocument) - if err != nil { - panic(err) - } - - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - normalizeFunc(&walker) - - for _, fn := range additionalNormalizers { - fn(&walker) - } - - walker.Walk(&operationDocument, &definitionDocument, &report) - // we run this walker twice because some normalizers may depend on other normalizers - // walking twice ensures that all prerequisites are met - // additionally, walking twice also ensures that the normalizers are idempotent - walker.Walk(&operationDocument, &definitionDocument, &report) - - assert.True(t, report.HasErrors()) - assert.Condition(t, func() bool { - for i := range report.InternalErrors { - if report.InternalErrors[i].Error() == expectedError { - return true - } - } - return false - }) -} - -func runMany(definition, operation, expectedOutput string, normalizeFuncs ...registerNormalizeFunc) { - var runManyNormalizers = func(walker *astvisitor.Walker) { - for _, normalizeFunc := range normalizeFuncs { - normalizeFunc(walker) - } - } - - run(runManyNormalizers, definition, operation, expectedOutput) -} - -func runManyOnDefinition(definition, expectedOutput string, normalizeFuncs ...registerNormalizeFunc) { - runMany("", definition, expectedOutput, normalizeFuncs...) -} - -const testOperation = ` -subscription sub { - ... multipleSubscriptions - ... on Subscription { - newMessage { - body - sender - } - } -} -fragment newMessageFields on Message { - body: body - sender - ... on Body { - body - } -} -fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - newMessage { - ... newMessageFields - } - newMessage { - body - body - sender - } - ... on Subscription { - newMessage { - body - sender - } - } - disallowedSecondRootField -}` - -const testDefinition = ` -schema { - query: Query - subscription: Subscription -} - -interface Body { - body: String -} - -type Message implements Body { - body: String - sender: String -} - -type Subscription { - newMessage: Message - disallowedSecondRootField: Boolean - frag2Field: String -} - -input ComplexInput { name: String, owner: String } -input ComplexNonOptionalInput { name: String! } - -type Field { - subfieldA: String - subfieldB: String -} - -type Query { - human: Human - pet: Pet - dog: Dog - cat: Cat - catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien - arguments: ValidArguments - findDog(complex: ComplexInput): Dog - findDogNonOptional(complex: ComplexNonOptionalInput): Dog - booleanList(booleanListArg: [Boolean!]): Boolean - extra: Extra - field: Field - simple(input: String = "foo"): String -} - -type ValidArguments { - multipleReqs(x: Int!, y: Int!): Int! - booleanArgField(booleanArg: Boolean): Boolean - floatArgField(floatArg: Float): Float - intArgField(intArg: Int): Int - nonNullBooleanArgField(nonNullBooleanArg: Boolean!): Boolean! - booleanListArgField(booleanListArg: [Boolean]!): [Boolean] - optionalNonNullBooleanArgField(optionalBooleanArg: Boolean! = false): Boolean! -} - -enum DogCommand { SIT, DOWN, HEEL } - -type Dog implements Pet { - name: String! - nickname: String - barkVolume: Int - doesKnowCommand(dogCommand: DogCommand!): Boolean! - isHousetrained(atOtherHomes: Boolean): Boolean! - owner: Human - extra: DogExtra - extras: [DogExtra] - mustExtra: DogExtra! - mustExtras: [DogExtra]! - mustMustExtras: [DogExtra!]! - doubleNested: Boolean - nestedDogName: String -} - -type DogExtra { - string: String - string1: String - strings: [String] - mustStrings: [String]! - bool: Int - noString: Boolean -} - -interface Sentient { - name: String! -} - -interface Pet { - name: String! -} - -type Alien implements Sentient { - name: String! - homePlanet: String -} - -type Human implements Sentient { - name: String! -} - -enum CatCommand { JUMP } - -type Cat implements Pet { - name: String! - nickname: String - doesKnowCommand(catCommand: CatCommand!): Boolean! - meowVolume: Int - extra: CatExtra -} - -type CatExtra { - string: String - string2: String - strings: [String] - mustStrings: [String]! - bool: Boolean -} - -union CatOrDog = Cat | Dog -union DogOrHuman = Dog | Human -union HumanOrAlien = Human | Alien -union Extra = CatExtra | DogExtra` - -const typeExtensionsDefinition = ` -schema { query: Query } - -extend scalar JSONPayload -extend union UserType = TrialUser | SubscribedUser - -extend type Query { - findUserByLocation(loc: Location): [User] -} - -extend interface Entity { - id: ID -} - -type User { - name: String -} - -type TrialUser { - enabled: Boolean -} - -type SubscribedUser { - subscription: SubscriptionType -} - -enum SubscriptionType { - BASIC - PRO - ULTIMATE -} - -extend type User implements Entity { - id: ID - age: Int - type: UserType - metadata: JSONPayload -} - -extend enum Planet { - EARTH - MARS -} - -extend input Location { - lat: Float - lon: Float - planet: Planet -} -` - -const extendedRootOperationTypeDefinition = ` -extend type Query { - me: String -} -extend type Mutation { - increaseTextCounter: String -} -extend type Subscription { - textCounter: String -} -` -const injectDefaultValueDefinition = ` -type Query { - elQuery(input: elInput): Boolean! -} - -type Mutation{ - elMutation(input: elInput!): Boolean! -} - -input elInput{ - fieldA: MyEnum! = VALUE_A - fieldB: String -} - -enum MyEnum { - VALUE_A - VALUE_B -} -` diff --git a/pkg/astnormalization/definition_normalization.go b/pkg/astnormalization/definition_normalization.go deleted file mode 100644 index fa897cf36..000000000 --- a/pkg/astnormalization/definition_normalization.go +++ /dev/null @@ -1,67 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// NormalizeDefinition creates a default DefinitionNormalizer and applies all rules to a given AST -// In case you're using DefinitionNormalizer in a hot path you shouldn't be using this function. -// Create a new DefinitionNormalizer using NewDefinitionNormalizer() instead and re-use it. -func NormalizeDefinition(definition *ast.Document, report *operationreport.Report) { - normalizer := NewDefinitionNormalizer() - normalizer.NormalizeDefinition(definition, report) -} - -// DefinitionNormalizer walks a given AST and applies all registered rules -type DefinitionNormalizer struct { - walker *astvisitor.Walker -} - -// NewDefinitionNormalizer creates a new DefinitionNormalizer and sets up all default rules -func NewDefinitionNormalizer() *DefinitionNormalizer { - normalizer := &DefinitionNormalizer{} - normalizer.setupWalkers() - return normalizer -} - -func (o *DefinitionNormalizer) setupWalkers() { - walker := astvisitor.NewWalker(48) - - extendObjectTypeDefinition(&walker) - extendInputObjectTypeDefinition(&walker) - extendEnumTypeDefinition(&walker) - extendInterfaceTypeDefinition(&walker) - extendScalarTypeDefinition(&walker) - extendUnionTypeDefinition(&walker) - removeMergedTypeExtensions(&walker) - implicitSchemaDefinition(&walker) - - o.walker = &walker -} - -func NewSubgraphDefinitionNormalizer() *DefinitionNormalizer { - normalizer := &DefinitionNormalizer{} - normalizer.setupSubgraphWalkers() - return normalizer -} - -func (o *DefinitionNormalizer) setupSubgraphWalkers() { - walker := astvisitor.NewWalker(48) - - extendObjectTypeDefinitionKeepingOrphans(&walker) - extendInputObjectTypeDefinitionKeepingOrphans(&walker) - extendEnumTypeDefinitionKeepingOrphans(&walker) - extendInterfaceTypeDefinitionKeepingOrphans(&walker) - extendScalarTypeDefinitionKeepingOrphans(&walker) - extendUnionTypeDefinitionKeepingOrphans(&walker) - removeMergedTypeExtensions(&walker) - - o.walker = &walker -} - -// NormalizeDefinition applies all registered rules to the AST -func (o *DefinitionNormalizer) NormalizeDefinition(definition *ast.Document, report *operationreport.Report) { - o.walker.Walk(definition, nil, report) -} diff --git a/pkg/astnormalization/definition_normalization_test.go b/pkg/astnormalization/definition_normalization_test.go deleted file mode 100644 index b714d6e9e..000000000 --- a/pkg/astnormalization/definition_normalization_test.go +++ /dev/null @@ -1,262 +0,0 @@ -package astnormalization - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestNormalizeDefinition(t *testing.T) { - run := func(t *testing.T, definition, expectedOutput string) { - t.Helper() - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(definition) - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedOutput) - - report := operationreport.Report{} - normalizer := NewDefinitionNormalizer() - normalizer.NormalizeDefinition(&definitionDocument, &report) - - if report.HasErrors() { - t.Fatal(report.Error()) - } - - got := mustString(astprinter.PrintString(&definitionDocument, nil)) - want := mustString(astprinter.PrintString(&expectedOutputDocument, nil)) - - assert.Equal(t, want, got) - } - - t.Run("removes extensions and creates missing types", func(t *testing.T) { - run(t, typeExtensionsDefinition, ` - schema { query: Query } - - type User implements Entity { - name: String - id: ID - age: Int - type: UserType - metadata: JSONPayload - } - - type TrialUser { - enabled: Boolean - } - - type SubscribedUser { - subscription: SubscriptionType - } - - enum SubscriptionType { - BASIC - PRO - ULTIMATE - } - - scalar JSONPayload - - union UserType = TrialUser | SubscribedUser - - type Query { - findUserByLocation(loc: Location): [User] - } - - interface Entity { - id: ID - } - - enum Planet { - EARTH - MARS - } - - input Location { - lat: Float - lon: Float - planet: Planet - } - `) - }) - - t.Run("removes type extension and includes interfaces when type already has implements interface", func(t *testing.T) { - run(t, ` - schema { query: Query } - - type User implements Named { - name: String - } - - interface Named { - name: String - } - - extend type User implements Entity { - id: ID - } - - interface Entity { - id: ID - } - `, ` - schema { query: Query } - - type User implements Named & Entity { - name: String - id: ID - } - - interface Named { - name: String - } - - interface Entity { - id: ID - } - `) - }) - - t.Run("removes extensions and creates missing schema and root operation types", func(t *testing.T) { - run(t, extendedRootOperationTypeDefinition, ` - schema { - query: Query - mutation: Mutation - subscription: Subscription - } - type Query { - me: String - } - type Mutation { - increaseTextCounter: String - } - type Subscription { - textCounter: String - } - `) - }) -} - -func TestNormalizeSubgraphDefinition(t *testing.T) { - run := func(t *testing.T, definition, expectedOutput string) { - t.Helper() - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(definition) - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedOutput) - - report := operationreport.Report{} - normalizer := NewSubgraphDefinitionNormalizer() - normalizer.NormalizeDefinition(&definitionDocument, &report) - - if report.HasErrors() { - t.Fatal(report.Error()) - } - - got := mustString(astprinter.PrintString(&definitionDocument, nil)) - want := mustString(astprinter.PrintString(&expectedOutputDocument, nil)) - - assert.Equal(t, want, got) - } - - t.Run("Extension orphans are not deleted", func(t *testing.T) { - run(t, ` - extend type Rival { - version: Version! - } - - enum Badge { - BOULDER - SOUL - } - - extend enum Version { - SILVER - } - - extend input Deposit { - quantity: Int! - } - - extend interface GymLeader { - badge: Badge! - } - - type Pokemon { - name: String! - } - - extend interface Trainer { - age: Int! - } - - union Types = Water | Fire - - extend input Move { - name: String - } - - input Deposit { - item: String! - } - - extend enum Badge { - EARTH - } - - extend union Berry = Oran - - extend type Pokemon { - types: Types! - } - - extend union Types = Grass - - interface Trainer { - name: String! - } - `, ` - extend type Rival { - version: Version! - } - - enum Badge { - BOULDER - SOUL - EARTH - } - - extend enum Version { - SILVER - } - - extend interface GymLeader { - badge: Badge! - } - - type Pokemon { - name: String! - types: Types! - } - - union Types = Water | Fire | Grass - - extend input Move { - name: String - } - - input Deposit { - item: String! - quantity: Int! - } - - extend union Berry = Oran - - interface Trainer { - name: String! - age: Int! - } - `) - }) -} diff --git a/pkg/astnormalization/directive_include_skip.go b/pkg/astnormalization/directive_include_skip.go deleted file mode 100644 index 5b969a9df..000000000 --- a/pkg/astnormalization/directive_include_skip.go +++ /dev/null @@ -1,87 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func directiveIncludeSkip(walker *astvisitor.Walker) { - visitor := directiveIncludeSkipVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterDirectiveVisitor(&visitor) -} - -type directiveIncludeSkipVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (d *directiveIncludeSkipVisitor) EnterDocument(operation, definition *ast.Document) { - d.operation = operation - d.definition = definition -} - -func (d *directiveIncludeSkipVisitor) EnterDirective(ref int) { - - name := d.operation.DirectiveNameBytes(ref) - - switch { - case bytes.Equal(name, literal.INCLUDE): - d.handleInclude(ref) - case bytes.Equal(name, literal.SKIP): - d.handleSkip(ref) - } -} - -func (d *directiveIncludeSkipVisitor) handleSkip(ref int) { - if len(d.operation.Directives[ref].Arguments.Refs) != 1 { - return - } - arg := d.operation.Directives[ref].Arguments.Refs[0] - if !bytes.Equal(d.operation.ArgumentNameBytes(arg), literal.IF) { - return - } - value := d.operation.ArgumentValue(arg) - if value.Kind != ast.ValueKindBoolean { - return - } - include := d.operation.BooleanValue(value.Ref) - switch include { - case false: - d.operation.RemoveDirectiveFromNode(d.Ancestors[len(d.Ancestors)-1], ref) - case true: - if len(d.Ancestors) < 2 { - return - } - d.operation.RemoveNodeFromNode(d.Ancestors[len(d.Ancestors)-1], d.Ancestors[len(d.Ancestors)-2]) - } -} - -func (d *directiveIncludeSkipVisitor) handleInclude(ref int) { - if len(d.operation.Directives[ref].Arguments.Refs) != 1 { - return - } - arg := d.operation.Directives[ref].Arguments.Refs[0] - if !bytes.Equal(d.operation.ArgumentNameBytes(arg), literal.IF) { - return - } - value := d.operation.ArgumentValue(arg) - if value.Kind != ast.ValueKindBoolean { - return - } - include := d.operation.BooleanValue(value.Ref) - switch include { - case true: - d.operation.RemoveDirectiveFromNode(d.Ancestors[len(d.Ancestors)-1], ref) - case false: - if len(d.Ancestors) < 2 { - return - } - d.operation.RemoveNodeFromNode(d.Ancestors[len(d.Ancestors)-1], d.Ancestors[len(d.Ancestors)-2]) - } -} diff --git a/pkg/astnormalization/directive_include_skip_test.go b/pkg/astnormalization/directive_include_skip_test.go deleted file mode 100644 index 39b6a4403..000000000 --- a/pkg/astnormalization/directive_include_skip_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package astnormalization - -import "testing" - -func TestDirectiveIncludeVisitor(t *testing.T) { - t.Run("remove static include true on inline fragment", func(t *testing.T) { - run(directiveIncludeSkip, testDefinition, ` - { - dog { - name: nickname - ... @include(if: true) { - includeName: name @include(if: true) - notIncludeName: name @include(if: false) - notSkipName: name @skip(if: false) - skipName: name @skip(if: true) - } - } - notInclude: dog @include(if: false) { - name - } - skip: dog @skip(if: true) { - name - } - }`, ` - { - dog { - name: nickname - ... { - includeName: name - notSkipName: name - } - } - }`) - }) -} diff --git a/pkg/astnormalization/enum_type_extending.go b/pkg/astnormalization/enum_type_extending.go deleted file mode 100644 index e0ca63436..000000000 --- a/pkg/astnormalization/enum_type_extending.go +++ /dev/null @@ -1,54 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func extendEnumTypeDefinition(walker *astvisitor.Walker) { - visitor := extendEnumTypeDefinitionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterEnumTypeExtensionVisitor(&visitor) -} - -func extendEnumTypeDefinitionKeepingOrphans(walker *astvisitor.Walker) { - visitor := extendEnumTypeDefinitionVisitor{ - Walker: walker, - keepExtensionOrphans: true, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterEnumTypeExtensionVisitor(&visitor) -} - -type extendEnumTypeDefinitionVisitor struct { - *astvisitor.Walker - operation *ast.Document - keepExtensionOrphans bool -} - -func (e *extendEnumTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.operation = operation -} - -func (e *extendEnumTypeDefinitionVisitor) EnterEnumTypeExtension(ref int) { - nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.EnumTypeExtensionNameBytes(ref)) - if !exists { - return - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindEnumTypeDefinition { - continue - } - e.operation.ExtendEnumTypeDefinitionByEnumTypeExtension(nodes[i].Ref, ref) - return - } - - if e.keepExtensionOrphans { - return - } - - e.operation.ImportAndExtendEnumTypeDefinitionByEnumTypeExtension(ref) -} diff --git a/pkg/astnormalization/enum_type_extending_test.go b/pkg/astnormalization/enum_type_extending_test.go deleted file mode 100644 index 742cc9122..000000000 --- a/pkg/astnormalization/enum_type_extending_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendEnumType(t *testing.T) { - t.Run("extend enum type by directive", func(t *testing.T) { - run(extendEnumTypeDefinition, testDefinition, ` - enum Countries {DE ES NL} - extend enum Countries @deprecated(reason: "some reason") - `, ` - enum Countries @deprecated(reason: "some reason") {DE ES NL} - extend enum Countries @deprecated(reason: "some reason") - `) - }) - t.Run("extend enum type by enum values", func(t *testing.T) { - run(extendEnumTypeDefinition, testDefinition, ` - enum Countries {DE ES NL} - extend enum Countries {EN} - `, ` - enum Countries {DE ES NL EN} - extend enum Countries {EN} - `) - }) - t.Run("extend enum type by multiple enum values and directives", func(t *testing.T) { - run(extendEnumTypeDefinition, testDefinition, ` - enum Countries {DE ES NL} - extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT} - `, ` - enum Countries @deprecated(reason: "some reason") @skip(if: false) {DE ES NL EN IT} - extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT} - `) - }) - t.Run("extend non existent enum type", func(t *testing.T) { - run(extendEnumTypeDefinition, "", ` - extend enum Planet { EARTH MARS } - extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT} - `, ` - extend enum Planet { EARTH MARS } - extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT} - enum Planet { EARTH MARS } - enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT} - `) - }) -} diff --git a/pkg/astnormalization/extends_directive.go b/pkg/astnormalization/extends_directive.go deleted file mode 100644 index 065b3aa70..000000000 --- a/pkg/astnormalization/extends_directive.go +++ /dev/null @@ -1,82 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -var extendsDirectiveName = "extends" - -type extendsDirectiveVisitor struct { - document *ast.Document -} - -func extendsDirective(walker *astvisitor.Walker) { - v := &extendsDirectiveVisitor{} - walker.RegisterEnterDocumentVisitor(v) - walker.RegisterEnterObjectTypeDefinitionVisitor(v) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(v) -} - -func (v *extendsDirectiveVisitor) EnterDocument(document, _ *ast.Document) { - v.document = document -} - -func (v *extendsDirectiveVisitor) EnterObjectTypeDefinition(ref int) { - if !v.document.ObjectTypeDefinitions[ref].Directives.HasDirectiveByName(v.document, extendsDirectiveName) { - return - } - for i := range v.document.RootNodes { - if v.document.RootNodes[i].Ref == ref && v.document.RootNodes[i].Kind == ast.NodeKindObjectTypeDefinition { - // give this node a new NodeKind of ObjectTypeExtension - newRef := v.document.AddObjectTypeDefinitionExtension(ast.ObjectTypeExtension{ObjectTypeDefinition: v.document.ObjectTypeDefinitions[ref]}) - // reflect changes inside the root nodes - v.document.UpdateRootNode(i, newRef, ast.NodeKindObjectTypeExtension) - // only remove @extends if the nodes was updated - v.document.ObjectTypeExtensions[newRef].Directives.RemoveDirectiveByName(v.document, extendsDirectiveName) - // update index - oldIndexNode := ast.Node{ - Kind: ast.NodeKindObjectTypeDefinition, - Ref: ref, - } - - v.document.Index.ReplaceNode(v.document.ObjectTypeExtensionNameBytes(newRef), oldIndexNode, ast.Node{ - Kind: ast.NodeKindObjectTypeExtension, - Ref: newRef, - }) - - break - } - } - -} - -func (v *extendsDirectiveVisitor) EnterInterfaceTypeDefinition(ref int) { - if !v.document.InterfaceTypeDefinitions[ref].Directives.HasDirectiveByName(v.document, extendsDirectiveName) { - return - } - for i := range v.document.RootNodes { - if v.document.RootNodes[i].Kind != ast.NodeKindInterfaceTypeDefinition || v.document.RootNodes[i].Ref != ref { - continue - } - - newRef := v.document.AddInterfaceTypeExtension(ast.InterfaceTypeExtension{ - InterfaceTypeDefinition: v.document.InterfaceTypeDefinitions[ref], - }) - - v.document.UpdateRootNode(i, newRef, ast.NodeKindInterfaceTypeExtension) - v.document.InterfaceTypeExtensions[newRef].Directives.RemoveDirectiveByName(v.document, extendsDirectiveName) - - oldIndexNode := ast.Node{ - Kind: ast.NodeKindInterfaceTypeDefinition, - Ref: ref, - } - - v.document.Index.ReplaceNode(v.document.InterfaceTypeExtensionNameBytes(newRef), oldIndexNode, ast.Node{ - Kind: ast.NodeKindInterfaceTypeExtension, - Ref: newRef, - }) - - return - } -} diff --git a/pkg/astnormalization/extends_directive_test.go b/pkg/astnormalization/extends_directive_test.go deleted file mode 100644 index cdf725ef6..000000000 --- a/pkg/astnormalization/extends_directive_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendsDirective(t *testing.T) { - t.Run("@extends on object type definition", func(t *testing.T) { - t.Run("support extends directive", func(_ *testing.T) { - runManyOnDefinition(` - type User @extends { - field: String! - } - `, ` - extend type User { field: String! } - `, extendsDirective, - ) - }) - - t.Run("delete extends directive", func(_ *testing.T) { - runManyOnDefinition(` - type User @extends @otherDirective { - field: String! - } - `, ` - extend type User @otherDirective { field: String! } - `, extendsDirective, - ) - }) - }) - - t.Run("@extends on interface type definition", func(t *testing.T) { - t.Run("support extends directive", func(_ *testing.T) { - runManyOnDefinition(` - interface Vehicle @extends { - speed: Int! - } - `, ` - extend interface Vehicle { speed: Int! } - `, extendsDirective, - ) - }) - - t.Run("delete extends directive", func(_ *testing.T) { - runManyOnDefinition(` - interface Vehicle @extends @otherDirective { - speed: Int! - } - `, ` - extend interface Vehicle @otherDirective { speed: Int! } - `, extendsDirective, - ) - }) - }) -} diff --git a/pkg/astnormalization/field_deduplication.go b/pkg/astnormalization/field_deduplication.go deleted file mode 100644 index 0b56298b5..000000000 --- a/pkg/astnormalization/field_deduplication.go +++ /dev/null @@ -1,59 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func deduplicateFields(walker *astvisitor.Walker) { - visitor := deduplicateFieldsVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterSelectionSetVisitor(&visitor) -} - -type deduplicateFieldsVisitor struct { - *astvisitor.Walker - operation *ast.Document -} - -func (d *deduplicateFieldsVisitor) EnterDocument(operation, definition *ast.Document) { - d.operation = operation -} - -func (d *deduplicateFieldsVisitor) EnterSelectionSet(ref int) { - if len(d.operation.SelectionSets[ref].SelectionRefs) < 2 { - return - } - - for a, i := range d.operation.SelectionSets[ref].SelectionRefs { - if d.operation.Selections[i].Kind != ast.SelectionKindField { - continue - } - left := d.operation.Selections[i].Ref - if d.operation.Fields[left].HasSelections { - continue - } - for b, j := range d.operation.SelectionSets[ref].SelectionRefs { - if a == b { - continue - } - if a > b { - continue - } - if d.operation.Selections[j].Kind != ast.SelectionKindField { - continue - } - right := d.operation.Selections[j].Ref - if d.operation.Fields[right].HasSelections { - continue - } - if d.operation.FieldsAreEqualFlat(left, right) { - d.operation.RemoveFromSelectionSet(ref, b) - d.RevisitNode() - return - } - } - } -} diff --git a/pkg/astnormalization/field_deduplication_test.go b/pkg/astnormalization/field_deduplication_test.go deleted file mode 100644 index 28046f918..000000000 --- a/pkg/astnormalization/field_deduplication_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package astnormalization - -import "testing" - -func TestDeDuplicateFields(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(deduplicateFields, testDefinition, ` - query conflictingBecauseAlias { - dog { - extra { - string - string: noString - string - string: noString - } - } - }`, ` - query conflictingBecauseAlias { - dog { - extra { - string - string: noString - } - } - }`) - }) - t.Run("with different args", func(t *testing.T) { - run(deduplicateFields, testDefinition, ` - fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: 1) - doesKnowCommand(dogCommand: 0) - }`, ` - fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: 1) - doesKnowCommand(dogCommand: 0) - }`) - }) -} diff --git a/pkg/astnormalization/field_selection_merging.go b/pkg/astnormalization/field_selection_merging.go deleted file mode 100644 index 9e035afe0..000000000 --- a/pkg/astnormalization/field_selection_merging.go +++ /dev/null @@ -1,93 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func mergeFieldSelections(walker *astvisitor.Walker) { - visitor := fieldSelectionMergeVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterSelectionSetVisitor(&visitor) -} - -type fieldSelectionMergeVisitor struct { - *astvisitor.Walker - operation *ast.Document -} - -func (f *fieldSelectionMergeVisitor) EnterDocument(operation, definition *ast.Document) { - f.operation = operation -} - -func (f *fieldSelectionMergeVisitor) fieldsCanMerge(left, right int) bool { - leftName := f.operation.FieldNameBytes(left) - rightName := f.operation.FieldNameBytes(right) - leftAlias := f.operation.FieldAliasBytes(left) - rightAlias := f.operation.FieldAliasBytes(right) - - if !bytes.Equal(leftName, rightName) || !bytes.Equal(leftAlias, rightAlias) { - return false - } - - leftDirectives := f.operation.FieldDirectives(left) - rightDirectives := f.operation.FieldDirectives(right) - - return f.operation.DirectiveSetsAreEqual(leftDirectives, rightDirectives) -} - -func (f *fieldSelectionMergeVisitor) isFieldSelection(ref int) bool { - return f.operation.Selections[ref].Kind == ast.SelectionKindField -} - -func (f *fieldSelectionMergeVisitor) fieldsHaveSelections(left, right int) bool { - return f.operation.Fields[left].HasSelections && f.operation.Fields[right].HasSelections -} - -func (f *fieldSelectionMergeVisitor) removeSelection(set, i int) { - f.operation.SelectionSets[set].SelectionRefs = append(f.operation.SelectionSets[set].SelectionRefs[:i], f.operation.SelectionSets[set].SelectionRefs[i+1:]...) -} - -func (f *fieldSelectionMergeVisitor) mergeFields(left, right int) { - leftSet := f.operation.Fields[left].SelectionSet - rightSet := f.operation.Fields[right].SelectionSet - f.operation.SelectionSets[leftSet].SelectionRefs = append(f.operation.SelectionSets[leftSet].SelectionRefs, f.operation.SelectionSets[rightSet].SelectionRefs...) - f.operation.Fields[left].Directives.Refs = append(f.operation.Fields[left].Directives.Refs, f.operation.Fields[right].Directives.Refs...) -} - -func (f *fieldSelectionMergeVisitor) EnterSelectionSet(ref int) { - - if len(f.operation.SelectionSets[ref].SelectionRefs) < 2 { - return - } - - for _, leftSelection := range f.operation.SelectionSets[ref].SelectionRefs { - if !f.isFieldSelection(leftSelection) { - continue - } - leftField := f.operation.Selections[leftSelection].Ref - for i, rightSelection := range f.operation.SelectionSets[ref].SelectionRefs { - if !f.isFieldSelection(rightSelection) { - continue - } - if leftSelection == rightSelection { - continue - } - rightField := f.operation.Selections[rightSelection].Ref - if !f.fieldsHaveSelections(leftField, rightField) { - continue - } - if !f.fieldsCanMerge(leftField, rightField) { - continue - } - f.removeSelection(ref, i) - f.mergeFields(leftField, rightField) - f.RevisitNode() - return - } - } -} diff --git a/pkg/astnormalization/field_selection_merging_test.go b/pkg/astnormalization/field_selection_merging_test.go deleted file mode 100644 index fb4207b06..000000000 --- a/pkg/astnormalization/field_selection_merging_test.go +++ /dev/null @@ -1,82 +0,0 @@ -package astnormalization - -import "testing" - -func TestMergeFieldSelections(t *testing.T) { - t.Run("depth 1", func(t *testing.T) { - run(mergeFieldSelections, testDefinition, ` - query conflictingBecauseAlias { - dog { - extra { string } - extra { noString: string } - } - }`, ` - query conflictingBecauseAlias { - dog { - extra { - string - noString: string - } - } - }`) - }) - t.Run("depth 2", func(t *testing.T) { - run(mergeFieldSelections, testDefinition, ` - query conflictingBecauseAlias { - dog { - extra { string } - extra { string: noString } - } - dog { - extra { string } - extra { string: noString } - } - }`, ` - query conflictingBecauseAlias { - dog { - extra { - string - string: noString - string - string: noString - } - } - }`) - }) - t.Run("aliased", func(t *testing.T) { - t.Run("aliased", func(t *testing.T) { - run(mergeFieldSelections, testDefinition, ` - query conflictingBecauseAlias { - dog { - x: extras { string } - x: mustExtras { string } - } - }`, ` - query conflictingBecauseAlias { - dog { - x: extras { string } - x: mustExtras { string } - } - }`) - }) - }) - t.Run("fields with directives", func(t *testing.T) { - run(mergeFieldSelections, testDefinition, ` - { - field @skip(if: $foo) { - subfieldA - } - field @skip(if: $bar) { - subfieldB - } - }`, ` - { - field @skip(if: $foo) { - subfieldA - } - field @skip(if: $bar) { - subfieldB - } - }`) - }) -} diff --git a/pkg/astnormalization/fragment_definition_removal.go b/pkg/astnormalization/fragment_definition_removal.go deleted file mode 100644 index 7e62d6c11..000000000 --- a/pkg/astnormalization/fragment_definition_removal.go +++ /dev/null @@ -1,25 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -type FragmentDefinitionRemoval struct { -} - -func removeFragmentDefinitions(walker *astvisitor.Walker) { - visitor := removeFragmentDefinitionsVisitor{} - walker.RegisterLeaveDocumentVisitor(visitor) -} - -type removeFragmentDefinitionsVisitor struct { -} - -func (r removeFragmentDefinitionsVisitor) LeaveDocument(operation, definition *ast.Document) { - for i := range operation.RootNodes { - if operation.RootNodes[i].Kind == ast.NodeKindFragmentDefinition { - operation.RootNodes[i].Kind = ast.NodeKindUnknown - } - } -} diff --git a/pkg/astnormalization/fragment_spread_inlining.go b/pkg/astnormalization/fragment_spread_inlining.go deleted file mode 100644 index e74a97fda..000000000 --- a/pkg/astnormalization/fragment_spread_inlining.go +++ /dev/null @@ -1,115 +0,0 @@ -package astnormalization - -import ( - "bytes" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func fragmentSpreadInline(walker *astvisitor.Walker) { - visitor := fragmentSpreadInlineVisitor{ - Walker: walker, - } - walker.RegisterDocumentVisitor(&visitor) - walker.RegisterEnterFragmentSpreadVisitor(&visitor) -} - -type fragmentSpreadInlineVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - transformer asttransform.Transformer - fragmentSpreadDepth FragmentSpreadDepth - depths Depths -} - -func (f *fragmentSpreadInlineVisitor) EnterDocument(operation, definition *ast.Document) { - f.transformer.Reset() - f.depths = f.depths[:0] - f.operation = operation - f.definition = definition - - f.fragmentSpreadDepth.Get(operation, definition, f.Report, &f.depths) - if f.Report.HasErrors() { - f.Stop() - } -} - -func (f *fragmentSpreadInlineVisitor) LeaveDocument(operation, definition *ast.Document) { - f.transformer.ApplyTransformations(operation) -} - -func (f *fragmentSpreadInlineVisitor) EnterFragmentSpread(ref int) { - parentTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition) - - fragmentDefinitionRef, exists := f.operation.FragmentDefinitionRef(f.operation.FragmentSpreadNameBytes(ref)) - if !exists { - fragmentName := f.operation.FragmentSpreadNameBytes(ref) - f.StopWithExternalErr(operationreport.ErrFragmentUndefined(fragmentName)) - return - } - - fragmentTypeName := f.operation.FragmentDefinitionTypeName(fragmentDefinitionRef) - fragmentNode, exists := f.definition.NodeByName(fragmentTypeName) - if !exists { - f.StopWithExternalErr(operationreport.ErrTypeUndefined(fragmentTypeName)) - return - } - - fragmentTypeEqualsParentType := bytes.Equal(parentTypeName, fragmentTypeName) - var enclosingTypeImplementsFragmentType bool - var enclosingTypeIsMemberOfFragmentUnion bool - var fragmentTypeImplementsEnclosingType bool - var fragmentTypeIsMemberOfEnclosingUnionType bool - var fragmentUnionIntersectsEnclosingInterface bool - var fragmentInterfaceIntersectsEnclosingUnion bool - - if fragmentNode.Kind == ast.NodeKindInterfaceTypeDefinition && f.EnclosingTypeDefinition.Kind == ast.NodeKindObjectTypeDefinition { - enclosingTypeImplementsFragmentType = f.definition.NodeImplementsInterface(f.EnclosingTypeDefinition, fragmentNode) - } - - if fragmentNode.Kind == ast.NodeKindUnionTypeDefinition { - enclosingTypeIsMemberOfFragmentUnion = f.definition.NodeIsUnionMember(f.EnclosingTypeDefinition, fragmentNode) - } - - if f.EnclosingTypeDefinition.Kind == ast.NodeKindInterfaceTypeDefinition { - fragmentTypeImplementsEnclosingType = f.definition.NodeImplementsInterface(fragmentNode, f.EnclosingTypeDefinition) - } - - if f.EnclosingTypeDefinition.Kind == ast.NodeKindInterfaceTypeDefinition && fragmentNode.Kind == ast.NodeKindUnionTypeDefinition { - fragmentUnionIntersectsEnclosingInterface = f.definition.UnionNodeIntersectsInterfaceNode(fragmentNode, f.EnclosingTypeDefinition) - } - - if f.EnclosingTypeDefinition.Kind == ast.NodeKindUnionTypeDefinition && fragmentNode.Kind == ast.NodeKindInterfaceTypeDefinition { - fragmentInterfaceIntersectsEnclosingUnion = f.definition.UnionNodeIntersectsInterfaceNode(f.EnclosingTypeDefinition, fragmentNode) - } - - if f.EnclosingTypeDefinition.Kind == ast.NodeKindUnionTypeDefinition { - fragmentTypeIsMemberOfEnclosingUnionType = f.definition.NodeIsUnionMember(fragmentNode, f.EnclosingTypeDefinition) - } - - nestedDepth, ok := f.depths.ByRef(ref) - if !ok { - f.StopWithInternalErr(fmt.Errorf("nested depth missing on depths for FragmentSpread: %s", f.operation.FragmentSpreadNameString(ref))) - return - } - - precedence := asttransform.Precedence{ - Depth: nestedDepth, - Order: 0, - } - - selectionSet := f.Ancestors[len(f.Ancestors)-1].Ref - replaceWith := f.operation.FragmentDefinitions[fragmentDefinitionRef].SelectionSet - typeCondition := f.operation.FragmentDefinitions[fragmentDefinitionRef].TypeCondition - - switch { - case fragmentTypeEqualsParentType || enclosingTypeImplementsFragmentType: - f.transformer.ReplaceFragmentSpread(precedence, selectionSet, ref, replaceWith) - case fragmentTypeImplementsEnclosingType || fragmentTypeIsMemberOfEnclosingUnionType || enclosingTypeIsMemberOfFragmentUnion || fragmentUnionIntersectsEnclosingInterface || fragmentInterfaceIntersectsEnclosingUnion: - f.transformer.ReplaceFragmentSpreadWithInlineFragment(precedence, selectionSet, ref, replaceWith, typeCondition) - } -} diff --git a/pkg/astnormalization/fragment_spread_inlining_test.go b/pkg/astnormalization/fragment_spread_inlining_test.go deleted file mode 100644 index f31b2d980..000000000 --- a/pkg/astnormalization/fragment_spread_inlining_test.go +++ /dev/null @@ -1,443 +0,0 @@ -package astnormalization - -import "testing" - -func TestInlineFragments(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - subscription sub { - ...multipleSubscriptions - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - }`, ` - subscription sub { - newMessage { - body - sender - } - disallowedSecondRootField - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - }`) - }) - t.Run("simple 2x", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - subscription sub { - ...multipleSubscriptions - ...multipleSubscriptions - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - }`, ` - subscription sub { - newMessage { - body - sender - } - disallowedSecondRootField - newMessage { - body - sender - } - disallowedSecondRootField - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - }`) - }) - t.Run("nested", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - subscription sub { - ...frag1 - } - fragment frag1 on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - ...frag2 - } - fragment frag2 on Subscription { - frag2Field - }`, ` - subscription sub { - newMessage { - body - sender - } - disallowedSecondRootField - frag2Field - } - fragment frag1 on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - frag2Field - } - fragment frag2 on Subscription { - frag2Field - }`) - }) - t.Run("2x nested", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - subscription sub { - ...frag1 - } - fragment frag1 on Subscription { - newMessage { - body - sender - ...messageFrag - sender - sender - ...nestedMessageFrag - } - disallowedSecondRootField - ...frag2 - } - fragment messageFrag on Message { - body - sender - } - fragment nestedMessageFrag on Message { - body - sender - } - fragment frag2 on Subscription { - frag2Field - }`, ` - subscription sub { - newMessage { - body - sender - body - sender - sender - sender - body - sender - } - disallowedSecondRootField - frag2Field - } - fragment frag1 on Subscription { - newMessage { - body - sender - body - sender - sender - sender - body - sender - } - disallowedSecondRootField - frag2Field - } - fragment messageFrag on Message { - body - sender - } - fragment nestedMessageFrag on Message { - body - sender - } - fragment frag2 on Subscription { - frag2Field - }`) - }) - t.Run("mergeFields interface fields into selection if type implements interface", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - { - dog { - ...definedOnImplementorsButNotInterface - } - } - fragment definedOnImplementorsButNotInterface on Pet { - name - }`, ` - { - dog { - name - } - } - fragment definedOnImplementorsButNotInterface on Pet { - name - }`) - }) - t.Run("inline fragments if fragment type definition implements enclosing type definition", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - fragment conflictingDifferingResponses on Pet { - ...dogFrag - ...catFrag - } - fragment dogFrag on Dog { - someValue: nickname - } - fragment catFrag on Cat { - someValue: meowVolume - }`, ` - fragment conflictingDifferingResponses on Pet { - ... on Dog { - someValue: nickname - } - ... on Cat { - someValue: meowVolume - } - } - fragment dogFrag on Dog { - someValue: nickname - } - fragment catFrag on Cat { - someValue: meowVolume - }`) - }) - t.Run("inline fragment if fragment type is member of enclosing union type", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - query conflictingDifferingResponses { - catOrDog { - ...catDogFrag - } - } - fragment catDogFrag on CatOrDog { - ...catFrag - ...dogFrag - } - fragment catFrag on Cat { - someValue: meowVolume - } - fragment dogFrag on Dog { - someValue: name - }`, ` - query conflictingDifferingResponses { - catOrDog { - ... on Cat { - someValue: meowVolume - } - ... on Dog { - someValue: name - } - } - } - fragment catDogFrag on CatOrDog { - ... on Cat { - someValue: meowVolume - } - ... on Dog { - someValue: name - } - } - fragment catFrag on Cat { - someValue: meowVolume - } - fragment dogFrag on Dog { - someValue: name - }`) - }) - t.Run("inline fragment of outer enclosing type inside union fragment could be inlined if enclosing type is member of union fragment", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - { - dog { - ...fragOnObject - ...fragOnInterface - ...fragOnUnion - } - } - fragment fragOnObject on Dog { - name - } - fragment fragOnInterface on Pet { - name - } - fragment fragOnUnion on CatOrDog { - ... on Dog { - name - } - }`, ` - { - dog { - name - name - ... on CatOrDog { - ... on Dog { - name - } - } - } - } - fragment fragOnObject on Dog { - name - } - fragment fragOnInterface on Pet { - name - } - fragment fragOnUnion on CatOrDog { - ... on Dog { - name - } - }`) - }) - t.Run("type inside union inside type", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - { - dog { - ...unionWithObjectFragment - } - } - fragment catOrDogNameFragment on CatOrDog { - ... on Cat { - meowVolume - } - } - fragment unionWithObjectFragment on Dog { - ...catOrDogNameFragment - }`, ` - { - dog { - ... on CatOrDog { - ... on Cat { - meowVolume - } - } - } - } - fragment catOrDogNameFragment on CatOrDog { - ... on Cat { - meowVolume - } - } - fragment unionWithObjectFragment on Dog { - ... on CatOrDog { - ... on Cat { - meowVolume - } - } - }`) - }) - t.Run("inline fragment inside union inside interface inside type", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - { - dog { - ...unionWithInterface - } - } - fragment unionWithInterface on Pet { - ...dogOrHumanFragment - } - fragment dogOrHumanFragment on DogOrHuman { - ... on Dog { - barkVolume - } - }`, ` - { - dog { - ... on DogOrHuman { - ... on Dog { - barkVolume - } - } - } - } - fragment unionWithInterface on Pet { - ... on DogOrHuman { - ... on Dog { - barkVolume - } - } - } - fragment dogOrHumanFragment on DogOrHuman { - ... on Dog { - barkVolume - } - }`) - }) - t.Run("inline fragment inside interface inside union inside type", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - { - dog { - ...interfaceWithUnion - } - } - fragment interfaceWithUnion on DogOrHuman { - ...petFragment - } - fragment petFragment on Pet { - ... on Dog { - barkVolume - } - }`, ` - { - dog { - ... on DogOrHuman { - ... on Pet { - ... on Dog { - barkVolume - } - } - } - } - } - fragment interfaceWithUnion on DogOrHuman { - ... on Pet { - ... on Dog { - barkVolume - } - } - } - fragment petFragment on Pet { - ... on Dog { - barkVolume - } - }`) - }) - t.Run("non intersecting interfaces shouldn't merge", func(t *testing.T) { - run(fragmentSpreadInline, testDefinition, ` - { - dog { - ...nonIntersectingInterfaces - } - } - fragment nonIntersectingInterfaces on Pet { - ...sentientFragment - } - fragment sentientFragment on Sentient { - name - }`, ` - { - dog { - ... on Sentient { - name - } - } - } - fragment nonIntersectingInterfaces on Pet { - ... on Sentient { - name - } - } - fragment sentientFragment on Sentient { - name - }`) - }) -} diff --git a/pkg/astnormalization/fragmentspread_depth.go b/pkg/astnormalization/fragmentspread_depth.go deleted file mode 100644 index 08d78f2df..000000000 --- a/pkg/astnormalization/fragmentspread_depth.go +++ /dev/null @@ -1,105 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// FragmentSpreadDepth is a helper for nested Fragments to calculate the actual depth of a Fragment Node -type FragmentSpreadDepth struct { - walker astvisitor.Walker - visitor fragmentSpreadDepthVisitor - calc nestedDepthCalc - visitorsRegistered bool -} - -// Depth holds all necessary information to understand the Depth of a Fragment Node -type Depth struct { - SpreadRef int - Depth int - SpreadName ast.ByteSlice - isNested bool - parentFragmentName ast.ByteSlice -} - -type Depths []Depth - -func (d Depths) ByRef(ref int) (int, bool) { - for i := range d { - if d[i].SpreadRef == ref { - return d[i].Depth, true - } - } - return -1, false -} - -// Get returns all FragmentSpread Depths for a given AST -func (r *FragmentSpreadDepth) Get(operation, definition *ast.Document, report *operationreport.Report, depths *Depths) { - - if !r.visitorsRegistered { - r.walker.RegisterEnterFragmentSpreadVisitor(&r.visitor) - r.visitorsRegistered = true - } - - r.visitor.operation = operation - r.visitor.definition = definition - r.visitor.depths = depths - r.visitor.Walker = &r.walker - - r.walker.Walk(operation, definition, report) - r.calc.calculatedNestedDepths(depths) -} - -type nestedDepthCalc struct { - depths *Depths -} - -func (n *nestedDepthCalc) calculatedNestedDepths(depths *Depths) { - n.depths = depths - - for i := range *depths { - (*depths)[i].Depth = n.calculateNestedDepth(i) - } -} - -func (n *nestedDepthCalc) calculateNestedDepth(i int) int { - if !(*n.depths)[i].isNested { - return (*n.depths)[i].Depth - } - return (*n.depths)[i].Depth + n.depthForFragment((*n.depths)[i].parentFragmentName) -} - -func (n *nestedDepthCalc) depthForFragment(name ast.ByteSlice) int { - for i := range *n.depths { - if bytes.Equal(name, (*n.depths)[i].SpreadName) { - return n.calculateNestedDepth(i) - } - } - return 0 -} - -type fragmentSpreadDepthVisitor struct { - *astvisitor.Walker - operation *ast.Document - definition *ast.Document - depths *Depths -} - -func (r *fragmentSpreadDepthVisitor) EnterFragmentSpread(ref int) { - - depth := Depth{ - SpreadRef: ref, - Depth: r.Depth, - SpreadName: r.operation.FragmentSpreadNameBytes(ref), - } - - if r.Ancestors[0].Kind == ast.NodeKindFragmentDefinition { - depth.isNested = true - depth.parentFragmentName = r.operation.FragmentDefinitionNameBytes(r.Ancestors[0].Ref) - } - - *r.depths = append(*r.depths, depth) -} diff --git a/pkg/astnormalization/fragmentspread_depth_test.go b/pkg/astnormalization/fragmentspread_depth_test.go deleted file mode 100644 index 06fdc0617..000000000 --- a/pkg/astnormalization/fragmentspread_depth_test.go +++ /dev/null @@ -1,109 +0,0 @@ -package astnormalization - -import ( - "fmt" - "testing" - - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestRealDepthCalculator_CalculateDepthForFragmentSpread(t *testing.T) { - run := func(operation, definition, spreadName string, wantDepth int) { - op := unsafeparser.ParseGraphqlDocumentString(operation) - def := unsafeparser.ParseGraphqlDocumentString(definition) - err := asttransform.MergeDefinitionWithBaseSchema(&def) - if err != nil { - panic(err) - } - - report := operationreport.Report{} - calc := FragmentSpreadDepth{} - var depths Depths - calc.Get(&op, &def, &report, &depths) - if report.HasErrors() { - panic(report.Error()) - } - - gotDepth := -1 - for _, depth := range depths { - if string(depth.SpreadName) == spreadName { - gotDepth = depth.Depth - break - } - } - - if wantDepth != gotDepth { - panic(fmt.Errorf("want: %d, got: %d", wantDepth, gotDepth)) - } - } - - t.Run("simple", func(t *testing.T) { - run(` - subscription sub { - ...frag1 - } - fragment frag1 on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - ...frag2 - } - fragment frag2 on Subscription { - frag2Field - }`, testDefinition, "frag1", 3) - }) - t.Run("nested", func(t *testing.T) { - run(` - subscription sub { - ...frag1 - } - fragment frag1 on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - ...frag2 - } - fragment frag2 on Subscription { - frag2Field - }`, testDefinition, "frag2", 6) - }) -} - -func BenchmarkFragmentSpreadDepthCalc_Get(b *testing.B) { - nested := ` - subscription sub { - ...frag1 - } - fragment frag1 on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - ...frag2 - } - fragment frag2 on Subscription { - frag2Field - }` - - op := unsafeparser.ParseGraphqlDocumentString(nested) - def := unsafeparser.ParseGraphqlDocumentString(testDefinition) - - calc := &FragmentSpreadDepth{} - depths := make(Depths, 0, 8) - report := operationreport.Report{} - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - depths = depths[:0] - calc.Get(&op, &def, &report, &depths) - } -} diff --git a/pkg/astnormalization/implicit_extend_root_operation.go b/pkg/astnormalization/implicit_extend_root_operation.go deleted file mode 100644 index 1894b0355..000000000 --- a/pkg/astnormalization/implicit_extend_root_operation.go +++ /dev/null @@ -1,54 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -/* -type Query {...} -type Mutation {...} -type Subscription {...} - -will be, - -extend type Query {...} -extend type Mutation {...} -extend type Subscription {...} - -this also works if root types are defined in schema{...} with other names. -root types are left unmodified if they have no fields, directives or implements any interface. -*/ -type implicitExtendRootOperationVisitor struct { - operation *ast.Document -} - -func implicitExtendRootOperation(walker *astvisitor.Walker) { - v := &implicitExtendRootOperationVisitor{} - walker.RegisterEnterDocumentVisitor(v) - walker.RegisterEnterObjectTypeDefinitionVisitor(v) -} - -func (v *implicitExtendRootOperationVisitor) EnterDocument(operation, _ *ast.Document) { - v.operation = operation -} - -func (v *implicitExtendRootOperationVisitor) EnterObjectTypeDefinition(ref int) { - node := v.operation.ObjectTypeDefinitions[ref] - if !(node.HasFieldDefinitions || node.HasDirectives) { - return - } - switch v.operation.ObjectTypeDefinitionNameString(ref) { - case implicitQueryTypeName, implicitMutationTypeName, implicitSubscriptionTypeName, - v.operation.Index.QueryTypeName.String(), v.operation.Index.MutationTypeName.String(), v.operation.Index.SubscriptionTypeName.String(): - for i := range v.operation.RootNodes { - if v.operation.RootNodes[i].Ref == ref && v.operation.RootNodes[i].Kind == ast.NodeKindObjectTypeDefinition { - // give this node a new NodeKind of ObjectTypeExtension - newRef := v.operation.AddObjectTypeDefinitionExtension(ast.ObjectTypeExtension{ObjectTypeDefinition: node}) - // reflect changes inside the root nodes - v.operation.UpdateRootNode(i, newRef, ast.NodeKindObjectTypeExtension) - break - } - } - } -} diff --git a/pkg/astnormalization/implicit_extend_root_operation_test.go b/pkg/astnormalization/implicit_extend_root_operation_test.go deleted file mode 100644 index c8e60af25..000000000 --- a/pkg/astnormalization/implicit_extend_root_operation_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package astnormalization - -import "testing" - -func TestImplicitExtendRootOperation(t *testing.T) { - t.Run("implicit extend root operation from schema", func(_ *testing.T) { - runManyOnDefinition(` - schema { - query: QueryName - mutation: MutationName - } - type QueryName @hello { - } - type MutationName { - field: String! - } - scalar String - `, ` - schema { query: QueryName mutation: MutationName } - extend type QueryName @hello{} - extend type MutationName { field: String! } - scalar String - `, registerNormalizeFunc(implicitExtendRootOperation)) - }) - t.Run("don't implicitly extend empty schema root operation", func(_ *testing.T) { - runManyOnDefinition(` - schema { - query: QueryName - } - type QueryName { - } - `, ` - schema { query: QueryName } - type QueryName {} - `, registerNormalizeFunc(implicitExtendRootOperation)) - }) - t.Run("don't implicitly extend empty object root operation", func(_ *testing.T) { - runManyOnDefinition(` - type Query {} - type Mutation { - field: String! - } - type Subscription @directive { - } - `, ` - type Query {} - extend type Mutation { field: String! } - extend type Subscription @directive {} - `, registerNormalizeFunc(implicitExtendRootOperation)) - }) - t.Run("implicitly extend object root operation with definitions and directives", func(_ *testing.T) { - runManyOnDefinition(` - type Query {} - type Mutation { - field: String! - } - type Subscription @directive { - newUser: ID! - } - `, ` - type Query {} - extend type Mutation { field: String! } - extend type Subscription @directive { newUser: ID! } - `, registerNormalizeFunc(implicitExtendRootOperation)) - }) - -} diff --git a/pkg/astnormalization/implicit_schema_definition.go b/pkg/astnormalization/implicit_schema_definition.go deleted file mode 100644 index 72a185cd2..000000000 --- a/pkg/astnormalization/implicit_schema_definition.go +++ /dev/null @@ -1,58 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -const ( - implicitQueryTypeName = "Query" - implicitMutationTypeName = "Mutation" - implicitSubscriptionTypeName = "Subscription" -) - -func implicitSchemaDefinition(walker *astvisitor.Walker) { - visitor := implicitSchemaDefinitionVisitor{ - Walker: walker, - } - walker.RegisterLeaveDocumentVisitor(&visitor) -} - -type implicitSchemaDefinitionVisitor struct { - *astvisitor.Walker -} - -func (i *implicitSchemaDefinitionVisitor) LeaveDocument(operation, definition *ast.Document) { - queryNodeName := i.nodeName(implicitQueryTypeName, operation) - mutationNodeName := i.nodeName(implicitMutationTypeName, operation) - subscriptionNodeName := i.nodeName(implicitSubscriptionTypeName, operation) - - schemaDefinitionRef := operation.SchemaDefinitionRef() - if schemaDefinitionRef == ast.InvalidRef { - operation.ImportSchemaDefinition(queryNodeName, mutationNodeName, subscriptionNodeName) - return - } - - if len(operation.SchemaDefinitions[schemaDefinitionRef].RootOperationTypeDefinitions.Refs) > 0 { - return - } - - operation.ReplaceRootOperationTypesOfSchemaDefinition(schemaDefinitionRef, queryNodeName, mutationNodeName, subscriptionNodeName) -} - -func (i *implicitSchemaDefinitionVisitor) nodeName(operationTypeName string, operation *ast.Document) string { - nodes, ok := operation.Index.NodesByNameStr(operationTypeName) - if !ok { - return "" - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindObjectTypeDefinition { - continue - } - - return operationTypeName - } - - return "" -} diff --git a/pkg/astnormalization/implicit_schema_definition_test.go b/pkg/astnormalization/implicit_schema_definition_test.go deleted file mode 100644 index 725efebe9..000000000 --- a/pkg/astnormalization/implicit_schema_definition_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package astnormalization - -import ( - "testing" -) - -func TestImplicitSchemaDefinition(t *testing.T) { - t.Run("should create schema definition implicitly", func(t *testing.T) { - run(implicitSchemaDefinition, "", ` - extend type Query { me: String } - extend type Mutation { increaseTextCounter: String } - extend type Subscription { textCounter: String } - type Query { me: String } - type Mutation { increaseTextCounter: String } - type Subscription { textCounter: String } - `, ` - schema { query: Query mutation: Mutation subscription: Subscription } - extend type Query { me: String } - extend type Mutation { increaseTextCounter: String } - extend type Subscription { textCounter: String } - type Query { me: String } - type Mutation { increaseTextCounter: String } - type Subscription { textCounter: String } - `) - }) - - t.Run("should replace empty schema definition with implicit one", func(t *testing.T) { - run(implicitSchemaDefinition, "", ` - schema {} - extend type Query { me: String } - extend type Mutation { increaseTextCounter: String } - extend type Subscription { textCounter: String } - type Query { me: String } - type Mutation { increaseTextCounter: String } - type Subscription { textCounter: String } - `, ` - schema { query: Query mutation: Mutation subscription: Subscription } - extend type Query { me: String } - extend type Mutation { increaseTextCounter: String } - extend type Subscription { textCounter: String } - type Query { me: String } - type Mutation { increaseTextCounter: String } - type Subscription { textCounter: String } - `) - }) - - t.Run("should ignore schema definition if there is already one explicitly defined", func(t *testing.T) { - run(implicitSchemaDefinition, "", ` - schema { query: Query } - extend type Query { me: String } - extend type Mutation { increaseTextCounter: String } - extend type Subscription { textCounter: String } - type Query { me: String } - type Mutation { increaseTextCounter: String } - type Subscription { textCounter: String } - `, ` - schema { query: Query } - extend type Query { me: String } - extend type Mutation { increaseTextCounter: String } - extend type Subscription { textCounter: String } - type Query { me: String } - type Mutation { increaseTextCounter: String } - type Subscription { textCounter: String } - `) - }) -} diff --git a/pkg/astnormalization/inject_input_default_values.go b/pkg/astnormalization/inject_input_default_values.go deleted file mode 100644 index 3ddb81fb7..000000000 --- a/pkg/astnormalization/inject_input_default_values.go +++ /dev/null @@ -1,235 +0,0 @@ -package astnormalization - -import ( - "errors" - "fmt" - - "github.com/buger/jsonparser" - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func injectInputFieldDefaults(walker *astvisitor.Walker) *inputFieldDefaultInjectionVisitor { - visitor := &inputFieldDefaultInjectionVisitor{ - Walker: walker, - jsonPath: make([]string, 0), - } - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterVariableDefinitionVisitor(visitor) - return visitor -} - -type inputFieldDefaultInjectionVisitor struct { - *astvisitor.Walker - - operation *ast.Document - definition *ast.Document - - variableName string - jsonPath []string -} - -func (v *inputFieldDefaultInjectionVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation, v.definition = operation, definition -} - -func (v *inputFieldDefaultInjectionVisitor) EnterVariableDefinition(ref int) { - v.variableName = v.operation.VariableDefinitionNameString(ref) - - variableVal, _, _, err := jsonparser.Get(v.operation.Input.Variables, v.variableName) - if err == jsonparser.KeyPathNotFoundError { - return - } - if err != nil { - v.StopWithInternalErr(err) - return - } - - typeRef := v.operation.VariableDefinitions[ref].Type - if v.isScalarTypeOrExtension(typeRef, v.operation) { - return - } - newVal, replaced, err := v.processObjectOrListInput(typeRef, variableVal, v.operation) - if err != nil { - v.StopWithInternalErr(err) - return - } - if replaced { - newVariables, err := jsonparser.Set(v.operation.Input.Variables, newVal, v.variableName) - if err != nil { - v.StopWithInternalErr(err) - return - } - v.operation.Input.Variables = newVariables - } -} - -// recursiveInjectInputFields injects default values in input types starting from -// inputObjectRef and walking to its descendants. If no replacements are done it -// returns (varValue, false). If injecting a default value caused varValue to change -// it returns (newValue, true). -func (v *inputFieldDefaultInjectionVisitor) recursiveInjectInputFields(inputObjectRef int, varValue []byte) ([]byte, bool, error) { - objectDef := v.definition.InputObjectTypeDefinitions[inputObjectRef] - if !objectDef.HasInputFieldsDefinition { - return varValue, false, nil - } - finalVal := varValue - hasDoneAnyReplacements := false - for _, ref := range objectDef.InputFieldsDefinition.Refs { - valDef := v.definition.InputValueDefinitions[ref] - fieldName := v.definition.InputValueDefinitionNameString(ref) - isTypeScalarOrEnum := v.isScalarTypeOrExtension(valDef.Type, v.definition) - hasDefault := valDef.DefaultValue.IsDefined - - varVal, _, _, err := jsonparser.Get(varValue, fieldName) - if err != nil && err != jsonparser.KeyPathNotFoundError { - v.StopWithInternalErr(err) - return nil, false, err - } - existsInVal := err != jsonparser.KeyPathNotFoundError - - if !isTypeScalarOrEnum { - var valToUse []byte - if existsInVal { - valToUse = varVal - } else if hasDefault { - defVal, err := v.definition.ValueToJSON(valDef.DefaultValue.Value) - if err != nil { - return nil, false, err - } - valToUse = defVal - } else { - continue - } - fieldValue, replaced, err := v.processObjectOrListInput(valDef.Type, valToUse, v.definition) - if err != nil { - return nil, false, err - } - if (!existsInVal && hasDefault) || replaced { - finalVal, err = jsonparser.Set(finalVal, fieldValue, fieldName) - if err != nil { - return nil, false, err - } - hasDoneAnyReplacements = true - } - continue - } - - if !hasDefault && isTypeScalarOrEnum { - continue - } - if existsInVal { - continue - } - defVal, err := v.definition.ValueToJSON(valDef.DefaultValue.Value) - if err != nil { - return nil, false, err - } - - finalVal, err = jsonparser.Set(finalVal, defVal, fieldName) - if err != nil { - return nil, false, err - } - hasDoneAnyReplacements = true - } - return finalVal, hasDoneAnyReplacements, nil -} - -func (v *inputFieldDefaultInjectionVisitor) isScalarTypeOrExtension(typeRef int, typeDoc *ast.Document) bool { - if typeDoc.TypeIsScalar(typeRef, v.definition) || typeDoc.TypeIsEnum(typeRef, v.definition) { - return true - } - typeName := typeDoc.TypeNameBytes(typeRef) - node, found := v.definition.Index.FirstNonExtensionNodeByNameBytes(typeName) - if !found { - return false - } - switch node.Kind { - case ast.NodeKindScalarTypeDefinition, ast.NodeKindEnumTypeDefinition: - return true - } - return false -} - -// processObjectOrListInput walks over an input object or list, assigning default values -// from the schema if necessary. If there are no changes to be made it (defaultValue, false), -// and if any value is replaced by its default in the schema it returns (newValue, true). -func (v *inputFieldDefaultInjectionVisitor) processObjectOrListInput(fieldType int, defaultValue []byte, typeDoc *ast.Document) ([]byte, bool, error) { - fieldIsList := typeDoc.TypeIsList(fieldType) - varVal, valType, _, err := jsonparser.Get(defaultValue) - if err != nil { - return nil, false, err - - } - node, found := v.definition.Index.FirstNodeByNameBytes(typeDoc.ResolveTypeNameBytes(fieldType)) - if !found { - return defaultValue, false, nil - } - if node.Kind == ast.NodeKindScalarTypeDefinition { - return defaultValue, false, nil - } - finalVal := defaultValue - replaced := false - valIsList := valType == jsonparser.Array - if fieldIsList && valIsList { - _, err := jsonparser.ArrayEach(varVal, v.jsonWalker(typeDoc.ResolveListOrNameType(fieldType), defaultValue, &node, typeDoc, &finalVal, &replaced)) - if err != nil { - return nil, false, err - - } - } else if !fieldIsList && !valIsList { - finalVal, replaced, err = v.recursiveInjectInputFields(node.Ref, defaultValue) - if err != nil { - return nil, false, err - } - } else { - return nil, false, errors.New("mismatched input value") - } - return finalVal, replaced, nil -} - -// jsonWalker returns a function for visiting an array using jsonparser.ArrayEach that recursively applies -// default values from the schema if necessary, using v.processObjectOrListInput() and v.recursiveInjectInputFields(). -// If any changes are made, it returns (newValue, true), otherwise it returns (defaultValue, false). -func (v *inputFieldDefaultInjectionVisitor) jsonWalker(fieldType int, defaultValue []byte, node *ast.Node, typeDoc *ast.Document, finalVal *[]byte, finalValueReplaced *bool) func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - i := 0 - listOfList := typeDoc.TypeIsList(typeDoc.Types[fieldType].OfType) - return func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - if err != nil { - return - } - if listOfList && dataType == jsonparser.Array { - newVal, replaced, err := v.processObjectOrListInput(typeDoc.Types[fieldType].OfType, value, typeDoc) - if err != nil { - return - } - if replaced { - *finalVal, err = jsonparser.Set(defaultValue, newVal, fmt.Sprintf("[%d]", i)) - if err != nil { - return - } - *finalValueReplaced = true - } - } else if !listOfList && dataType == jsonparser.Object { - newVal, replaced, err := v.recursiveInjectInputFields(node.Ref, value) - if err != nil { - return - } - if replaced { - *finalVal, err = jsonparser.Set(defaultValue, newVal, fmt.Sprintf("[%d]", i)) - if err != nil { - return - } - *finalValueReplaced = true - } - } else { - return - } - i++ - } - -} -func (v *inputFieldDefaultInjectionVisitor) LeaveVariableDefinition(ref int) { - v.variableName = "" - v.jsonPath = make([]string, 0) -} diff --git a/pkg/astnormalization/inject_input_default_values_test.go b/pkg/astnormalization/inject_input_default_values_test.go deleted file mode 100644 index 82e24cfc4..000000000 --- a/pkg/astnormalization/inject_input_default_values_test.go +++ /dev/null @@ -1,266 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "testing" -) - -const testInputDefaultSchema = ` -scalar CustomScalar - -enum TestEnum { - ValueOne - ValueTwo -} - -schema { - mutation: Mutation -} - -type Mutation { - testDefaultValueSimple(data: SimpleTestInput!): String! - testDefaultValueSimpleNull(data: LowerLevelInput): String! - testNestedInputField(data: InputWithNestedField!): String! - mutationExtractDefaultVariable( - in: PassedWithDefault = { firstField: "test" } - ): String - mutationNestedMissing(in: InputWithDefaultFieldsNested): String - mutationWithListInput(in: InputHasList): String - mutationWithMultiNestedInput(in: MultiNestedInput): String - mutationComplexNestedListInput(in: ComplexNestedListInput): String - mutationSimpleInputList(in: [SimpleTestInput]): String - mutationUseCustomScalar(in: CustomScalar!): String - mutationUseCustomScalarList(in: [CustomScalar!]): String -} - -input MultiNestedInput { - nested: [[LowerLevelInput]] = [[{ firstField: 1 }]] -} - -input ComplexNestedListInput { - nested: [[[LowerLevelInput]]] -} - -input InputHasList { - firstList: [LowerLevelInput!]! = [ - { firstField: 1, secondField: ValueOne } - { firstField: 1 } - ] -} - -input InputWithDefaultFieldsNested { - first: String! - nested: LowerLevelInput = { firstField: 0 } -} - -input SimpleTestInput { - firstField: String! = "firstField" - secondField: Int! = 1 - thirdField: Int! - fourthField: String -} - -input PassedWithDefault { - firstField: String! - second: Int! = 0 -} - -input InputWithNestedField { - nested: LowerLevelInput! -} - -input LowerLevelInput { - firstField: Int! - secondField: TestEnum! = ValueOne -} -` - -func TestInputDefaultValueExtraction(t *testing.T) { - t.Run("should not change", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation testDefaultValueSimple($a: SimpleTestInput!) { - testDefaultValueSimple(data: $a) - }`, "", ` - mutation testDefaultValueSimple($a: SimpleTestInput!) { - testDefaultValueSimple(data: $a) - }`, `{"a":{"firstField":"test","secondField":2}}`, `{"a":{"firstField":"test","secondField":2}}`) - }) - t.Run("simple default value extract", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation testDefaultValueSimple($a: SimpleTestInput!) { - testDefaultValueSimple(data: $a) - }`, "", ` - mutation testDefaultValueSimple($a: SimpleTestInput!) { - testDefaultValueSimple(data: $a) - }`, `{"a":{"firstField":"test"}}`, `{"a":{"firstField":"test","secondField":1}}`) - }) - - t.Run("simple default value nullable extract", func(t *testing.T) { - runWithVariables(t, extractVariables, testInputDefaultSchema, ` - mutation{ - testDefaultValueSimpleNull(data: {firstField: "test"}) - }`, "", ` - mutation($a: LowerLevelInput) { - testDefaultValueSimpleNull(data: $a) - }`, "", `{"a":{"firstField":"test","secondField":"ValueOne"}}`, - func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }) - }) - - t.Run("nested input field with default values", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation testNestedInputField($a: InputWithNestedField) { - testNestedInputField(data: $a) - }`, "", ` - mutation testNestedInputField($a: InputWithNestedField) { - testNestedInputField(data: $a) - }`, `{"a":{"nested":{}}}`, `{"a":{"nested":{"secondField":"ValueOne"}}}`) - }) - - t.Run("multiple variables for operation", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation combinedMutation($a: SimpleTestInput, $b: InputWithNestedField) { - testDefaultValueSimple(data: $a) - testNestedInputField(data: $b) - }`, "", ` - mutation combinedMutation($a: SimpleTestInput, $b: InputWithNestedField) { - testDefaultValueSimple(data: $a) - testNestedInputField(data: $b) - }`, `{"b":{"nested":{}},"a":{"firstField":"test"}}`, - `{"b":{"nested":{"secondField":"ValueOne"}},"a":{"firstField":"test","secondField":1}}`, - ) - }) - - t.Run("default field object is partial", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation($a: InputWithDefaultFieldsNested){ - mutationNestedMissing(in: $a) - }`, "", ` - mutation($a: InputWithDefaultFieldsNested){ - mutationNestedMissing(in: $a) - }`, `{"a":{"first":"test"}}`, `{"a":{"first":"test","nested":{"firstField":0,"secondField":"ValueOne"}}}`) - }) - - t.Run("variable for input field as object is partial", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation($a: InputWithDefaultFieldsNested){ - mutationNestedMissing(in: $a) - }`, "", ` - mutation($a: InputWithDefaultFieldsNested){ - mutationNestedMissing(in: $a) - }`, `{"a":{"first":"test","nested":{"firstField":1}}}`, `{"a":{"first":"test","nested":{"firstField":1,"secondField":"ValueOne"}}}`) - }) - - t.Run("run with extract variables", func(t *testing.T) { - runWithVariables(t, extractVariables, testInputDefaultSchema, ` - mutation { - testNestedInputField(data: { nested: { firstField: 1 } }) - }`, "", ` - mutation($a: InputWithNestedField!) { - testNestedInputField(data: $a) - }`, "", `{"a":{"nested":{"firstField":1,"secondField":"ValueOne"}}}`, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }) - }) - - t.Run("list default value", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationWithListInput($a: InputHasList) { - mutationWithListInput(data: $a) - }`, "", ` - mutation mutationWithListInput($a: InputHasList) { - mutationWithListInput(data: $a) - } -`, `{"a":{}}`, `{"a":{"firstList":[{"firstField":1,"secondField":"ValueOne"},{"firstField":1,"secondField":"ValueOne"}]}}`) - }) - - t.Run("list object partial value", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationWithListInput($a: InputHasList) { - mutationWithListInput(data: $a) - }`, "", ` - mutation mutationWithListInput($a: InputHasList) { - mutationWithListInput(data: $a) - } -`, `{"a":{"firstList":[{"firstField":10}]}}`, `{"a":{"firstList":[{"firstField":10,"secondField":"ValueOne"}]}}`) - }) - - t.Run("nested list default value", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationWithMultiNestedInput($a: MultiNestedInput) { - mutationWithMultiNestedInput(data: $a) - }`, "", ` - mutation mutationWithMultiNestedInput($a: MultiNestedInput) { - mutationWithMultiNestedInput(data: $a) - } -`, `{"a":{}}`, `{"a":{"nested":[[{"firstField":1,"secondField":"ValueOne"}]]}}`) - }) - - t.Run("complex nested list partial in variable", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationComplexNestedListInput($a: ComplexNestedListInput) { - mutationComplexNestedListInput(data: $a) - }`, "", ` - mutation mutationComplexNestedListInput($a: ComplexNestedListInput) { - mutationComplexNestedListInput(data: $a) - } -`, `{"a":{"nested":[[[{"firstField":2}]]]}}`, `{"a":{"nested":[[[{"firstField":2,"secondField":"ValueOne"}]]]}}`) - }) - - t.Run("simple list nested input", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationSimpleInputList($a: [SimpleTestInput]) { - mutationSimpleInputList(data: $a) - }`, "", ` - mutation mutationSimpleInputList($a: [SimpleTestInput]) { - mutationSimpleInputList(data: $a) - }`, `{"a":[{"thirdField":1}]}`, `{"a":[{"thirdField":1,"firstField":"firstField","secondField":1}]}`) - }) - - t.Run("use custom scalar variable", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationUseCustomScalar($a: CustomScalar) { - mutationUseCustomScalar(in: $a) - }`, "", ` - mutation mutationUseCustomScalar($a: CustomScalar) { - mutationUseCustomScalar(in: $a) - }`, `{"a":{}}`, `{"a":{}}`) - }) - - t.Run("custom scalar variable list", func(t *testing.T) { - runWithVariablesAssert(t, func(walker *astvisitor.Walker) { - injectInputFieldDefaults(walker) - }, testInputDefaultSchema, ` - mutation mutationUseCustomScalarList($a: [CustomScalar!]) { - mutationUseCustomScalarList(in: $a) - }`, "", ` - mutation mutationUseCustomScalarList($a: [CustomScalar!]) { - mutationUseCustomScalarList(in: $a) - }`, `{"a":[{"test": "testval"}]}`, `{"a":[{"test": "testval"}]}`) - }) -} diff --git a/pkg/astnormalization/inline_fragment_merging.go b/pkg/astnormalization/inline_fragment_merging.go deleted file mode 100644 index ca7f0dfeb..000000000 --- a/pkg/astnormalization/inline_fragment_merging.go +++ /dev/null @@ -1,63 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func mergeInlineFragments(walker *astvisitor.Walker) { - visitor := mergeInlineFragmentsVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterSelectionSetVisitor(&visitor) -} - -type mergeInlineFragmentsVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (m *mergeInlineFragmentsVisitor) EnterDocument(operation, definition *ast.Document) { - m.operation = operation - m.definition = definition -} - -func (m *mergeInlineFragmentsVisitor) couldInline(set, inlineFragment int) bool { - if m.operation.InlineFragmentHasDirectives(inlineFragment) { - return false - } - if !m.operation.InlineFragmentHasTypeCondition(inlineFragment) { - return true - } - if bytes.Equal(m.operation.InlineFragmentTypeConditionName(inlineFragment), m.definition.NodeNameBytes(m.EnclosingTypeDefinition)) { - return true - } - - inlineFragmentTypeName := m.operation.InlineFragmentTypeConditionName(inlineFragment) - enclosingTypeName := m.definition.NodeNameBytes(m.EnclosingTypeDefinition) - - return m.definition.TypeDefinitionContainsImplementsInterface(enclosingTypeName, inlineFragmentTypeName) -} - -func (m *mergeInlineFragmentsVisitor) resolveInlineFragment(set, index, inlineFragment int) { - m.operation.ReplaceSelectionOnSelectionSet(set, index, m.operation.InlineFragments[inlineFragment].SelectionSet) -} - -func (m *mergeInlineFragmentsVisitor) EnterSelectionSet(ref int) { - - for index, selection := range m.operation.SelectionSets[ref].SelectionRefs { - if m.operation.Selections[selection].Kind != ast.SelectionKindInlineFragment { - continue - } - inlineFragment := m.operation.Selections[selection].Ref - if !m.couldInline(ref, inlineFragment) { - continue - } - m.resolveInlineFragment(ref, index, inlineFragment) - m.RevisitNode() - return - } -} diff --git a/pkg/astnormalization/inline_fragment_merging_test.go b/pkg/astnormalization/inline_fragment_merging_test.go deleted file mode 100644 index f292dd20f..000000000 --- a/pkg/astnormalization/inline_fragment_merging_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package astnormalization - -import "testing" - -func TestResolveInlineFragments(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(mergeInlineFragments, testDefinition, ` - query conflictingBecauseAlias { - dog { - ... { - name - } - ... on Dog { - nickname - } - ... { - ... { - doubleNested - ... on Dog { - nestedDogName - } - } - } - extra { string } - extra { string: noString } - } - }`, - ` - query conflictingBecauseAlias { - dog { - name - nickname - doubleNested - nestedDogName - extra { string } - extra { string: noString } - } - }`) - }) - t.Run("with interface type", func(t *testing.T) { - run(mergeInlineFragments, testDefinition, ` - query conflictingBecauseAlias { - dog { - ... on Pet { - name - } - } - }`, - ` - query conflictingBecauseAlias { - dog { - name - } - }`) - }) -} diff --git a/pkg/astnormalization/input_coercion_for_list.go b/pkg/astnormalization/input_coercion_for_list.go deleted file mode 100644 index a94057626..000000000 --- a/pkg/astnormalization/input_coercion_for_list.go +++ /dev/null @@ -1,299 +0,0 @@ -package astnormalization - -import ( - "fmt" - "strconv" - "strings" - - "github.com/buger/jsonparser" - "github.com/tidwall/sjson" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/pool" -) - -func inputCoercionForList(walker *astvisitor.Walker) { - visitor := inputCoercionForListVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterVariableDefinitionVisitor(&visitor) -} - -type inputCoercionForListVisitor struct { - *astvisitor.Walker - operation *ast.Document - definition *ast.Document - operationDefinitionRef int - - query []string -} - -func (i *inputCoercionForListVisitor) EnterDocument(operation, definition *ast.Document) { - i.operation, i.definition = operation, definition -} - -func (i *inputCoercionForListVisitor) EnterOperationDefinition(ref int) { - i.operationDefinitionRef = ref -} - -func (i *inputCoercionForListVisitor) EnterVariableDefinition(ref int) { - variableNameString := i.operation.VariableDefinitionNameString(ref) - variableValueNameBytes := i.operation.VariableValueNameBytes(i.operation.VariableDefinitions[ref].VariableValue.Ref) - variableDefinition, exists := i.operation.VariableDefinitionByNameAndOperation(i.operationDefinitionRef, variableValueNameBytes) - if !exists { - return - } - variableTypeRef := i.operation.VariableDefinitions[variableDefinition].Type - variableTypeRef = i.operation.ResolveListOrNameType(variableTypeRef) - - value, dataType, _, err := jsonparser.Get(i.operation.Input.Variables, variableNameString) - if err == jsonparser.KeyPathNotFoundError { - // If the user doesn't provide any variable with that name, - // there is no need for coercion. Stop the operation - return - } - if err != nil { - i.StopWithInternalErr(err) - return - } - - i.query = append(i.query, variableNameString) - - switch i.operation.Types[variableTypeRef].TypeKind { - case ast.TypeKindList: - i.processTypeKindList(i.operation, variableTypeRef, value, dataType) - case ast.TypeKindNamed: - // We build a query to insert changes to the original variable - // Sample query: inputs.list.1.list.nested.list.1 - i.processTypeKindNamed(i.operation, i.operation.VariableDefinitions[ref].Type, value, dataType) - } -} - -func (i *inputCoercionForListVisitor) LeaveVariableDefinition(ref int) { - i.query = i.query[:0] -} - -func (i *inputCoercionForListVisitor) makeJSONArray(nestingDepth int, value []byte, dataType jsonparser.ValueType) ([]byte, error) { - wrapValueInQuotes := dataType == jsonparser.String - - out := pool.BytesBuffer.Get() - defer pool.BytesBuffer.Put(out) - - // value type is a non-array. Let's build an array from it. - for idx := 0; idx < nestingDepth; idx++ { - _, err := out.Write(literal.LBRACK) - if err != nil { - return nil, err - } - } - - if wrapValueInQuotes { - _, err := out.Write(literal.QUOTE) - if err != nil { - return nil, err - } - } - - _, err := out.Write(value) - if err != nil { - return nil, err - } - - if wrapValueInQuotes { - _, err := out.Write(literal.QUOTE) - if err != nil { - return nil, err - } - } - - for idx := 0; idx < nestingDepth; idx++ { - _, err = out.Write(literal.RBRACK) - if err != nil { - return nil, err - } - } - - // We built a JSON array from the given variable here. - - // Use a new slice before putting it into the variables. - // If we use the `out` buffer here, another pool user could re-use - // it and manipulate the variables. - data := make([]byte, out.Len()) - copy(data, out.Bytes()) - return data, nil -} - -func (i *inputCoercionForListVisitor) updateQuery(path string) { - i.query = append(i.query, path) -} - -func (i *inputCoercionForListVisitor) queryPath() (path string) { - return strings.Join(i.query, ".") -} - -func (i *inputCoercionForListVisitor) popQuery() { - if len(i.query)-1 > 0 { - i.query = i.query[:len(i.query)-1] - } -} - -func (i *inputCoercionForListVisitor) calculateNestingDepth(document *ast.Document, typeRef int) int { - var nestingDepth int - for typeRef != ast.InvalidRef { - first := document.Types[typeRef] - - typeRef = first.OfType - - switch first.TypeKind { - case ast.TypeKindList: - nestingDepth++ - default: - continue - } - } - return nestingDepth -} - -/* -we analyzing json: - -variants: - -- array - find corresponding type and go to an each object -- object - find corresponding type and do deep field analysis -- plain: - do nothing - -Object in depth: - -Object is an InputDefinition - -we iterate over objects field and trying to find corresponding field type - -when we found field type: - -it could be: -- NamedType - -- List -when it is a list - -we could have data as: -- json array - proceed recursively -- json plain - wrap into array -- json object - wrap into array and proceed recursively - - -*/ - -func (i *inputCoercionForListVisitor) walkJsonObject(inputObjDefTypeRef int, data []byte) { - err := jsonparser.ObjectEach(data, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { - i.updateQuery(string(key)) - defer i.popQuery() - - inputValueDefRef := i.definition.InputObjectTypeDefinitionInputValueDefinitionByName(inputObjDefTypeRef, key) - if inputValueDefRef == ast.InvalidRef { - return fmt.Errorf("nested field %s is not defined in any subfield of type %s", string(key), i.definition.InputObjectTypeDefinitionNameBytes(inputObjDefTypeRef)) - } - - typeRef := i.definition.ResolveListOrNameType(i.definition.InputValueDefinitionType(inputValueDefRef)) - - switch i.definition.Types[typeRef].TypeKind { - case ast.TypeKindList: - i.processTypeKindList(i.definition, typeRef, value, dataType) - case ast.TypeKindNamed: - // We build a query to insert changes to the original variable - // Sample query: inputs.list.1.list.nested.list.1 - i.processTypeKindNamed(i.definition, typeRef, value, dataType) - } - - return nil - - }) - if err != nil { - i.StopWithInternalErr(err) - } -} - -func (i *inputCoercionForListVisitor) walkJsonArray(document *ast.Document, listItemTypeRef int, data []byte) { - index := -1 - _, err := jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, cbErr error) { - if cbErr != nil { - i.StopWithInternalErr(cbErr) - return - } - index++ - - i.updateQuery(strconv.Itoa(index)) - defer i.popQuery() - - itemTypeRef := document.ResolveListOrNameType(listItemTypeRef) - - switch document.Types[itemTypeRef].TypeKind { - case ast.TypeKindList: - i.processTypeKindList(document, itemTypeRef, value, dataType) - case ast.TypeKindNamed: - // We build a query to insert changes to the original variable - // Sample query: inputs.list.1.list.nested.list.1 - i.processTypeKindNamed(document, itemTypeRef, value, dataType) - } - }) - - if err != nil { - i.StopWithInternalErr(err) - } - -} - -func (i *inputCoercionForListVisitor) processTypeKindNamed(document *ast.Document, typeRef int, value []byte, dataType jsonparser.ValueType) { - if dataType != jsonparser.Object { - return - } - - typeName := document.ResolveTypeNameBytes(typeRef) - - node, exist := i.definition.Index.FirstNodeByNameBytes(typeName) - if !exist { - return - } - - switch node.Kind { - case ast.NodeKindInputObjectTypeDefinition: - i.walkJsonObject(node.Ref, value) - case ast.NodeKindScalarTypeDefinition: - return - } -} - -func (i *inputCoercionForListVisitor) processTypeKindList(document *ast.Document, typeRef int, value []byte, dataType jsonparser.ValueType) { - // Build arrays from scalar/object types. If the variable type is an array or null, - // stop the operation. - // Take a look at that table: https://spec.graphql.org/October2021/#sec-List.Input-Coercion - switch dataType { - case jsonparser.Array: - i.walkJsonArray(document, document.Types[typeRef].OfType, value) - return - case jsonparser.Null: - return - default: - } - - // Calculate the nesting depth of variable definition - // For example: [[Int]], nestingDepth = 2 - nestingDepth := i.calculateNestingDepth(document, typeRef) - - data, err := i.makeJSONArray(nestingDepth, value, dataType) - if err != nil { - i.StopWithInternalErr(err) - return - } - i.operation.Input.Variables, err = sjson.SetRawBytes(i.operation.Input.Variables, i.queryPath(), data) - if err != nil { - i.StopWithInternalErr(err) - return - } - - i.walkJsonArray(document, document.Types[typeRef].OfType, data) -} diff --git a/pkg/astnormalization/input_coercion_for_list_test.go b/pkg/astnormalization/input_coercion_for_list_test.go deleted file mode 100644 index 06d93a7c2..000000000 --- a/pkg/astnormalization/input_coercion_for_list_test.go +++ /dev/null @@ -1,792 +0,0 @@ -package astnormalization - -import ( - "testing" -) - -const inputCoercionForListDefinition = ` -schema { - query: Query - mutation: Mutation -} - -type Character { - id: Int - name: String -} - -input Input { - foo: String -} - -input InputWithList { - foo: String - list: [InputWithList] - nested: InputWithList -} - -input InputWithListNonNull { - foo: String - list: [InputWithList!]! - nested: InputWithList! -} - -input InputWithListNestedList { - foo: String - doubleList: [[InputWithList]] - nested: InputWithList -} - -type Query { - characterById(id: Int): Character - nestedList(ids: [[Int]]): [Character] - charactersByIds(ids: [Int]): [Character] - charactersByStringIds(ids: [String]): [Character] - charactersByIdScalarIds(ids: [ID]): [Character] - characterByInput(input: Input): Character - charactersByInputs(inputs: [Input]): [Character] - charactersByIdsNonNull(ids: [Int]!): [Character] - charactersByIdsNonNullInteger(ids: [Int!]!): [Character] - nestedListNonNull(ids: [[Int!]!]!): [Character] - innerListNonNull(ids: [[Int]!]): [Character] - characterByIdNonNullInteger(id: Int!): Character - inputWithList(input: InputWithList): Character - inputWithListNonNull(input: InputWithListNonNull): Character - inputWithListNestedList(input: InputWithListNestedList): Character - inputWithNestedScalar(input: InputWithNestedScalarList): String -} - -type Mutation { - mutate(input: InputWithNestedScalarList): String - mutateNested(input: Nested): String - mutateDeepNested(input: DeepNested): String - mutateWithList(input: [InputWithNestedScalarList]): String - mutateNestedExtremeList(input: ExtremeNesting): String - mutateMultiArg(arg1: InputWithNestedScalarList, arg2: InputWithNestedScalarList): String -} - -input DeepNested { - deepNested: Nested -} - -input Nested { - nested: InputWithNestedScalarList -} - -input ExtremeNesting { - nested: [[[[[InputWithNestedScalarList]]]]] -} - -input InputWithNestedScalarList { - stringList: [String!] - intList: [Int!] -}` - -func TestInputCoercionForList(t *testing.T) { - t.Run("convert integer to list of integer", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIds(ids: 1) { - id - name - } - }`, ``, - ` - query ($a: [Int]){ - charactersByIds(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1]}`, inputCoercionForList) - }) - - t.Run("strings list variants", func(t *testing.T) { - t.Run("convert string to list of strings", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByStringIds(ids: "id") { - id - name - } - }`, ``, - ` - query ($a: [String]){ - charactersByStringIds(ids: $a) { - id - name - } - }`, `{}`, `{"a":["id"]}`, inputCoercionForList) - }) - - t.Run("convert string id to list of ID", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdScalarIds(ids: "id") { - id - name - } - }`, ``, - ` - query ($a: [ID]){ - charactersByIdScalarIds(ids: $a) { - id - name - } - }`, `{}`, `{"a":["id"]}`, inputCoercionForList) - }) - - t.Run("convert int id to list of ID", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query Q { - charactersByIdScalarIds(ids: 1) { - id - name - } - }`, `Q`, - ` - query Q ($a: [ID]){ - charactersByIdScalarIds(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1]}`, inputCoercionForList) - }) - - }) - - t.Run("input with nested scalar list", func(t *testing.T) { - t.Run("query", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query Q { - inputWithNestedScalar(input: { - stringList: "str", - intList: 1 - }) - }`, `Q`, - ` - query Q($a: InputWithNestedScalarList) { - inputWithNestedScalar(input: $a) - }`, `{}`, `{"a":{"stringList":["str"],"intList":[1]}}`, inputCoercionForList) - }) - - t.Run("query with null values", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query Q { - inputWithNestedScalar(input: { - stringList: null, - intList: null - }) - }`, `Q`, - ` - query Q($a: InputWithNestedScalarList) { - inputWithNestedScalar(input: $a) - }`, `{}`, `{"a":{"stringList":null,"intList":null}}`, inputCoercionForList) - }) - - t.Run("mutation", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutate(input: { - stringList: "str" - }) - }`, `Mutate`, - ` - mutation Mutate($a: InputWithNestedScalarList) { - mutate(input: $a) - }`, `{}`, `{"a":{"stringList":["str"]}}`, inputCoercionForList) - }) - - t.Run("mutation with list of inputs with nested list fields", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutateWithList(input: { - stringList: "str" - }) - }`, `Mutate`, - ` - mutation Mutate($a: [InputWithNestedScalarList]) { - mutateWithList(input: $a) - }`, `{}`, `{"a":[{"stringList":["str"]}]}`, inputCoercionForList) - }) - - t.Run("mutation: should coerse each nested field of element of a list", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutateWithList(input: [ - {stringList: "str"}, - {intList: 1} - ]) - }`, `Mutate`, - ` - mutation Mutate($a: [InputWithNestedScalarList]) { - mutateWithList(input: $a) - }`, `{}`, `{"a":[{"stringList":["str"]},{"intList":[1]}]}`, inputCoercionForList) - }) - - t.Run("mutation list items as variables", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate($a: InputWithNestedScalarList, $b: InputWithNestedScalarList) { - mutateWithList(input: [ - $a, - $b - ]) - }`, `Mutate`, - ` - mutation Mutate($a: InputWithNestedScalarList, $b: InputWithNestedScalarList) { - mutateWithList(input: [ - $a, - $b - ]) - }`, - `{"a":{"stringList":"str"},"b":{"intList":1}}`, - `{"a":{"stringList":["str"]},"b":{"intList":[1]}}`, inputCoercionForList) - }) - - t.Run("mutation list items as variables with additional variables", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate($a: InputWithNestedScalarList, $b: InputWithNestedScalarList) { - mutateWithList(input: [ - $a, - $b, - {stringList: "str2"}, - {intList: 1} - ]) - }`, `Mutate`, - ` - mutation Mutate($a: InputWithNestedScalarList, $b: InputWithNestedScalarList, $c: [String!], $d: [Int!]) { - mutateWithList(input: [ - $a, - $b, - {stringList: $c}, - {intList: $d} - ]) - }`, - `{"a":{"stringList":"str"},"b":{"intList":1}}`, - `{"d":[1],"c":["str2"],"a":{"stringList":["str"]},"b":{"intList":[1]}}`, inputCoercionForList) - }) - - t.Run("mutation nested", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutateNested(input: { - nested: { - stringList: "str" - } - }) - }`, `Mutate`, - ` - mutation Mutate($a: Nested) { - mutateNested(input: $a) - }`, `{}`, `{"a":{"nested":{"stringList":["str"]}}}`, inputCoercionForList) - }) - - t.Run("mutation deep nested", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutateDeepNested(input: { - deepNested: { - nested: { - stringList: "str" - } - } - }) - }`, `Mutate`, - ` - mutation Mutate($a: DeepNested) { - mutateDeepNested(input: $a) - }`, `{}`, `{"a":{"deepNested":{"nested":{"stringList":["str"]}}}}`, inputCoercionForList) - }) - - t.Run("mutation deep nested in extreme list", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutateNestedExtremeList(input: { - nested: { - stringList: "str" - } - }) - }`, `Mutate`, - ` - mutation Mutate($a: ExtremeNesting) { - mutateNestedExtremeList(input: $a) - }`, `{}`, `{"a":{"nested":[[[[[{"stringList":["str"]}]]]]]}}`, inputCoercionForList) - }) - - t.Run("mutation multi arg", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - mutation Mutate { - mutateMultiArg(arg1: {stringList: "str"}, arg2: {intList: 1}) - }`, `Mutate`, - ` - mutation Mutate($a: InputWithNestedScalarList, $b: InputWithNestedScalarList) { - mutateMultiArg(arg1: $a, arg2: $b) - }`, `{}`, `{"b":{"intList":[1]},"a":{"stringList":["str"]}}`, inputCoercionForList) - }) - - }) - - t.Run("list of integers", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIds(ids: [1, 2, 3]) { - id - name - } - }`, ``, - ` - query ($a: [Int]){ - charactersByIds(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1,2,3]}`, inputCoercionForList) - }) - - t.Run("nested list of integers", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - nestedList(ids: [[1], [2, 3]]) { - id - name - } - }`, ``, - ` - query ($a: [[Int]]) { - nestedList(ids: $a) { - id - name - } - }`, `{}`, `{"a":[[1],[2,3]]}`, inputCoercionForList) - }) - - t.Run("list of integers with null value", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIds(ids: null) { - id - name - } - }`, ``, - ` - query ($a: [Int]){ - charactersByIds(ids: $a) { - id - name - } - }`, `{}`, `{"a":null}`, inputCoercionForList) - }) - - t.Run("nested list with null value", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - nestedList(ids: null) { - id - name - } - }`, ``, - ` - query ($a: [[Int]]){ - nestedList(ids: $a) { - id - name - } - }`, `{}`, `{"a":null}`, inputCoercionForList) - }) - - t.Run("convert integer to nested list of integer", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - nestedList(ids: 1) { - id - name - } - }`, ``, - ` - query ($a: [[Int]]){ - nestedList(ids: $a) { - id - name - } - }`, `{}`, `{"a":[[1]]}`, inputCoercionForList) - }) - - t.Run("integer argument without modification", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - characterById(id: 1) { - id - name - } - }`, ``, - ` - query ($a: Int) { - characterById(id: $a) { - id - name - } - }`, `{}`, `{"a":1}`) - }) - - t.Run("non-null integer argument without modification", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - characterByIdNonNullInteger(id: 1) { - id - name - } - }`, ``, - ` - query ($a: Int!){ - characterByIdNonNullInteger(id: $a) { - id - name - } - }`, `{}`, `{"a":1}`, inputCoercionForList) - }) - - t.Run("do not modify null as argument", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - characterByIdNonNullInteger(id: null) { - id - name - } - }`, ``, - ` - query ($a: Int!){ - characterByIdNonNullInteger(id: $a) { - id - name - } - }`, `{}`, `{"a":null}`, inputCoercionForList) - }) - - t.Run("convert object type to list of object type", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByInputs(inputs: { foo: "bar" }) { - id - name - } - }`, ``, - ` - query ($a: [Input]){ - charactersByInputs(inputs: $a) { - id - name - } - }`, `{}`, `{"a":[{"foo":"bar"}]}`, inputCoercionForList) - }) - - t.Run("list of object type to list of object type remains unchanged", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByInputs(inputs: [{ foo: "bar" },{ foo: "bazz" }]) { - id - name - } - }`, ``, - ` - query ($a: [Input]){ - charactersByInputs(inputs: $a) { - id - name - } - }`, `{}`, `{"a":[{"foo":"bar"},{"foo":"bazz"}]}`, inputCoercionForList) - }) - - t.Run("object type definition", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - characterByInput(input: { foo: "bar" }) { - id - name - } - }`, ``, - ` - query ($a: Input){ - characterByInput(input: $a) { - id - name - } - }`, `{}`, `{"a":{"foo":"bar"}}`, inputCoercionForList) - }) - - t.Run("handle non-existent variable", func(t *testing.T) { - runWithVariablesAssert(t, inputCoercionForList, inputCoercionForListDefinition, ` - query ($ids: [[Int]]) { - nestedList(ids: $ids) { - id - name - } - }`, ``, - ` - query ($ids: [[Int]]) { - nestedList(ids: $ids) { - id - name - } - }`, `{"foo": "bar"}`, `{"foo": "bar"}`) - }) - - t.Run("convert integer to list of integer, non-null list", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdsNonNull(ids: 1) { - id - name - } - }`, ``, - ` - query ($a: [Int]!){ - charactersByIdsNonNull(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1]}`, inputCoercionForList) - }) - - t.Run("convert integer to list of integer, non-null integer", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdsNonNullInteger(ids: 1) { - id - name - } - }`, ``, - ` - query ($a: [Int!]!){ - charactersByIdsNonNullInteger(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1]}`, inputCoercionForList) - }) - - t.Run("send list of integers as argument, non-null integer", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdsNonNullInteger(ids: [1]) { - id - name - } - }`, ``, - ` - query ($a: [Int!]!) { - charactersByIdsNonNullInteger(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1]}`, inputCoercionForList) - }) - - t.Run("send list of integers as argument, non-null list", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdsNonNull(ids: [1]) { - id - name - } - }`, - ``, - ` - query ($a: [Int]!) { - charactersByIdsNonNull(ids: $a) { - id - name - } - }`, `{}`, `{"a":[1]}`, inputCoercionForList) - }) - - t.Run("convert integer to nested list of integer, non-null nested list", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - nestedListNonNull(ids: 1) { - id - name - } - }`, ``, - ` - query ($a: [[Int!]!]!){ - nestedListNonNull(ids: $a) { - id - name - } - }`, `{}`, `{"a":[[1]]}`, inputCoercionForList) - }) - - t.Run("convert integer to nested list of integer, non-null inner list", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - innerListNonNull(ids: 1) { - id - name - } - }`, ``, - ` - query ($a: [[Int]!]){ - innerListNonNull(ids: $a) { - id - name - } - }`, `{}`, `{"a":[[1]]}`, inputCoercionForList) - }) - - t.Run("send list of integers as variable input", func(t *testing.T) { - runWithVariablesAssert(t, inputCoercionForList, inputCoercionForListDefinition, ` - query ($ids: [[Int]]) { - nestedList(ids: $ids) { - id - name - } - }`, ``, - ` - query ($ids: [[Int]]) { - nestedList(ids: $ids) { - id - name - } - }`, `{"ids":[1]}`, `{"ids":[[1]]}`) - }) - - t.Run("send inline null to charactersByIdsNonNull", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdsNonNull(ids: null) { - id - name - } - }`, ``, - ` - query ($a: [Int]!){ - charactersByIdsNonNull(ids: $a) { - id - name - } - }`, `{}`, `{"a":null}`, inputCoercionForList) - }) - - t.Run("send inline null to nestedListNonNull", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - nestedListNonNull(ids: null) { - id - name - } - }`, ``, - ` - query ($a: [[Int!]!]!){ - nestedListNonNull(ids: $a) { - id - name - } - }`, `{}`, `{"a":null}`, inputCoercionForList) - }) - - t.Run("send inline null to charactersByIdsNonNullInteger", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query { - charactersByIdsNonNullInteger(ids: null) { - id - name - } - }`, ``, - ` - query ($a: [Int!]!){ - charactersByIdsNonNullInteger(ids: $a) { - id - name - } - }`, `{}`, `{"a":null}`, inputCoercionForList) - }) - - t.Run("nested variants", func(t *testing.T) { - t.Run("nested variables", func(t *testing.T) { - runWithVariablesAssert(t, inputCoercionForList, inputCoercionForListDefinition, ` - query ($input: InputWithList) { - inputWithList(input: $input) { - id - name - } - }`, - ``, ` - query ($input: InputWithList) { - inputWithList(input: $input) { - id - name - } - }`, - `{"input":{"list":{"foo":"bar","list":{"foo":"bar2","list":{"nested":{"foo":"bar3","list":{"foo":"bar4"}}}}}}}`, - `{"input":{"list":[{"foo":"bar","list":[{"foo":"bar2","list":[{"nested":{"foo":"bar3","list":[{"foo":"bar4"}]}}]}]}]}}`) - }) - - t.Run("nested variables, non-null", func(t *testing.T) { - runWithVariablesAssert(t, inputCoercionForList, inputCoercionForListDefinition, ` - query ($input: InputWithListNonNull) { - inputWithListNonNull(input: $input) { - id - name - } - }`, - ``, ` - query ($input: InputWithListNonNull) { - inputWithListNonNull(input: $input) { - id - name - } - }`, - `{"input":{"list":{"foo":"bar","list":{"foo":"bar2","list":{"nested":{"foo":"bar3","list":{"foo":"bar4"}}}}}}}`, - `{"input":{"list":[{"foo":"bar","list":[{"foo":"bar2","list":[{"nested":{"foo":"bar3","list":[{"foo":"bar4"}]}}]}]}]}}`) - }) - - t.Run("nested variables, list", func(t *testing.T) { - runWithVariablesAssert(t, inputCoercionForList, inputCoercionForListDefinition, ` - query ($input: InputWithListNestedList) { - inputWithListNestedList(input: $input) { - id - name - } - }`, - ``, ` - query ($input: InputWithListNestedList) { - inputWithListNestedList(input: $input) { - id - name - } - }`, - `{"input":{"doubleList":{"foo":"bar","list":{"foo":"bar2","list":{"nested":{"foo":"bar3","list":{"foo":"bar4"}}}}}}}`, - `{"input":{"doubleList":[[{"foo":"bar","list":[{"foo":"bar2","list":[{"nested":{"foo":"bar3","list":[{"foo":"bar4"}]}}]}]}]]}}`) - }) - - t.Run("nested test with inline values", func(t *testing.T) { - runWithVariables(t, extractVariables, inputCoercionForListDefinition, ` - query Foo { - inputWithList(input: {list:{foo:"bar",list:{foo:"bar2",list:{nested:{foo:"bar3",list:{foo:"bar4"}}}}}}) { - id - name - } - }`, `Foo`, - ` - query Foo($a: InputWithList) { - inputWithList(input: $a) { - id - name - } - }`, - `{}`, - `{"a":{"list":[{"foo":"bar","list":[{"foo":"bar2","list":[{"nested":{"foo":"bar3","list":[{"foo":"bar4"}]}}]}]}]}}`, inputCoercionForList) - }) - t.Run("walk into nested non existing object", func(t *testing.T) { - runWithExpectedErrors(t, extractVariables, inputCoercionForListDefinition, ` - query { - inputWithListNestedList(input: { - nested: {non_existing_field: true}, - }) { - id - name - } - } -`, "nested field non_existing_field is not defined in any subfield of type InputWithList", inputCoercionForList) - }) - }) -} diff --git a/pkg/astnormalization/input_object_type_extending.go b/pkg/astnormalization/input_object_type_extending.go deleted file mode 100644 index ea44430fa..000000000 --- a/pkg/astnormalization/input_object_type_extending.go +++ /dev/null @@ -1,54 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func extendInputObjectTypeDefinition(walker *astvisitor.Walker) { - visitor := extendInputObjectTypeDefinitionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterInputObjectTypeExtensionVisitor(&visitor) -} - -func extendInputObjectTypeDefinitionKeepingOrphans(walker *astvisitor.Walker) { - visitor := extendInputObjectTypeDefinitionVisitor{ - Walker: walker, - keepExtensionOrphans: true, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterInputObjectTypeExtensionVisitor(&visitor) -} - -type extendInputObjectTypeDefinitionVisitor struct { - *astvisitor.Walker - operation *ast.Document - keepExtensionOrphans bool -} - -func (e *extendInputObjectTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.operation = operation -} - -func (e *extendInputObjectTypeDefinitionVisitor) EnterInputObjectTypeExtension(ref int) { - nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.InputObjectTypeExtensionNameBytes(ref)) - if !exists { - return - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindInputObjectTypeDefinition { - continue - } - e.operation.ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(nodes[i].Ref, ref) - return - } - - if e.keepExtensionOrphans { - return - } - - e.operation.ImportAndExtendInputObjectTypeDefinitionByInputObjectTypeExtension(ref) -} diff --git a/pkg/astnormalization/input_object_type_extending_test.go b/pkg/astnormalization/input_object_type_extending_test.go deleted file mode 100644 index c64eff2e2..000000000 --- a/pkg/astnormalization/input_object_type_extending_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendInputObjectType(t *testing.T) { - t.Run("extend input object type by directive", func(t *testing.T) { - run(extendInputObjectTypeDefinition, testDefinition, ` - input DogSize {width: Float height: Float} - extend input DogSize @deprecated(reason: "some reason") - `, ` - input DogSize @deprecated(reason: "some reason") {width: Float height: Float} - extend input DogSize @deprecated(reason: "some reason") - `) - }) - t.Run("extend input object type by input fields definition", func(t *testing.T) { - run(extendInputObjectTypeDefinition, testDefinition, ` - input DogSize {width: Float height: Float} - extend input DogSize {breadth: Float} - `, ` - input DogSize {width: Float height: Float, breadth: Float} - extend input DogSize {breadth: Float} - `) - }) - t.Run("extend input object type by multiple input fields definition and directives", func(t *testing.T) { - run(extendInputObjectTypeDefinition, testDefinition, ` - input DogSize {width: Float height: Float} - extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float} - `, ` - input DogSize @deprecated(reason: "some reason") @skip(if: false) {width: Float height: Float breadth: Float weight: Float} - extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float} - `) - }) - t.Run("extend non existent input object type", func(t *testing.T) { - run(extendInputObjectTypeDefinition, "", ` - extend input Location { lat: Float lon: Float } - extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float} - `, ` - extend input Location { lat: Float lon: Float } - extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float} - input Location { lat: Float lon: Float } - input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float} - `) - }) -} diff --git a/pkg/astnormalization/interface_type_extending.go b/pkg/astnormalization/interface_type_extending.go deleted file mode 100644 index c80d3b28d..000000000 --- a/pkg/astnormalization/interface_type_extending.go +++ /dev/null @@ -1,54 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func extendInterfaceTypeDefinition(walker *astvisitor.Walker) { - visitor := extendInterfaceTypeDefinitionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterInterfaceTypeExtensionVisitor(&visitor) -} - -func extendInterfaceTypeDefinitionKeepingOrphans(walker *astvisitor.Walker) { - visitor := extendInterfaceTypeDefinitionVisitor{ - Walker: walker, - keepExtensionOrphans: true, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterInterfaceTypeExtensionVisitor(&visitor) -} - -type extendInterfaceTypeDefinitionVisitor struct { - *astvisitor.Walker - operation *ast.Document - keepExtensionOrphans bool -} - -func (e *extendInterfaceTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.operation = operation -} - -func (e *extendInterfaceTypeDefinitionVisitor) EnterInterfaceTypeExtension(ref int) { - nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.InterfaceTypeExtensionNameBytes(ref)) - if !exists { - return - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindInterfaceTypeDefinition { - continue - } - e.operation.ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(nodes[i].Ref, ref) - return - } - - if e.keepExtensionOrphans { - return - } - - e.operation.ImportAndExtendInterfaceTypeDefinitionByInterfaceTypeExtension(ref) -} diff --git a/pkg/astnormalization/interface_type_extending_test.go b/pkg/astnormalization/interface_type_extending_test.go deleted file mode 100644 index 1294b4410..000000000 --- a/pkg/astnormalization/interface_type_extending_test.go +++ /dev/null @@ -1,176 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendInterfaceType(t *testing.T) { - t.Run("extend simple interface type by field", func(t *testing.T) { - run(extendInterfaceTypeDefinition, testDefinition, ` - interface Mammal { - name: String - } - extend interface Mammal { - furType: String - } - `, ` - interface Mammal { - name: String - furType: String - } - extend interface Mammal { - furType: String - } - `) - }) - t.Run("extend interface by implements interface", func(t *testing.T) { - run(extendInterfaceTypeDefinition, testDefinition, ` - interface A { - name: String - } - extend interface A implements B { - age: Int - } - interface B { - age: Int - } - `, ` - interface A implements B { - name: String - age: Int - } - extend interface A implements B { - age: Int - } - interface B { - age: Int - } - `) - }) - t.Run("extend interface by implements interface and field", func(t *testing.T) { - run(extendInterfaceTypeDefinition, testDefinition, ` - interface A { - name: String - } - extend interface A implements B { - field: String - age: Int - } - interface B { - age: Int - } - `, ` - interface A implements B { - name: String - field: String - age: Int - } - extend interface A implements B { - field: String - age: Int - } - interface B { - age: Int - } - `) - }) - t.Run("extend simple interface type by directive", func(t *testing.T) { - run(extendInterfaceTypeDefinition, testDefinition, ` - interface Mammal { - name: String - } - extend interface Mammal @deprecated(reason: "some reason") - `, ` - interface Mammal @deprecated(reason: "some reason") { - name: String - } - extend interface Mammal @deprecated(reason: "some reason") - `) - }) - t.Run("extend interface type by complex extends", func(t *testing.T) { - run(extendInterfaceTypeDefinition, testDefinition, ` - interface Mammal { - name: String - } - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, ` - interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - name: String - furType: String - age: Int - } - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `) - }) - - t.Run("extend non existent interface", func(t *testing.T) { - run(extendInterfaceTypeDefinition, "", ` - extend interface Entity { id: ID } - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { name: String } - `, ` - extend interface Entity { id: ID } - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { name: String } - interface Entity { id: ID } - interface Mammal @deprecated(reason: "some reason") @skip(if: false) { name: String } - `) - }) - - t.Run("interface extensions implementing other interface implemented by object type", func(t *testing.T) { - run(extendInterfaceTypeDefinition, "", ` - interface Entity { - name: String - } - - interface Tall{ - height: String - } - - extend interface Tall implements Entity{ - name: String - } - - type People implements Entity & Tall{ - name: String - height: String - mass: String - birth_year: String - gender: String - homeworld: String - homeplanet: Planet - url: String - skin_color: String - hair_color: String - eye_color: String - }`, ` - interface Entity { - name: String - } - - interface Tall implements Entity{ - height: String - name: String - } - - extend interface Tall implements Entity{ - name: String - } - - type People implements Entity & Tall{ - name: String - height: String - mass: String - birth_year: String - gender: String - homeworld: String - homeplanet: Planet - url: String - skin_color: String - hair_color: String - eye_color: String - }`) - }) -} diff --git a/pkg/astnormalization/object_type_extending.go b/pkg/astnormalization/object_type_extending.go deleted file mode 100644 index ffa2e7cdc..000000000 --- a/pkg/astnormalization/object_type_extending.go +++ /dev/null @@ -1,55 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func extendObjectTypeDefinition(walker *astvisitor.Walker) { - visitor := extendObjectTypeDefinitionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(&visitor) -} - -func extendObjectTypeDefinitionKeepingOrphans(walker *astvisitor.Walker) { - visitor := extendObjectTypeDefinitionVisitor{ - Walker: walker, - keepExtensionOrphans: true, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(&visitor) -} - -type extendObjectTypeDefinitionVisitor struct { - *astvisitor.Walker - operation *ast.Document - keepExtensionOrphans bool -} - -func (e *extendObjectTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.operation = operation -} - -func (e *extendObjectTypeDefinitionVisitor) EnterObjectTypeExtension(ref int) { - - nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.ObjectTypeExtensionNameBytes(ref)) - if !exists { - return - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindObjectTypeDefinition { - continue - } - e.operation.ExtendObjectTypeDefinitionByObjectTypeExtension(nodes[i].Ref, ref) - return - } - - if e.keepExtensionOrphans { - return - } - - e.operation.ImportAndExtendObjectTypeDefinitionByObjectTypeExtension(ref) -} diff --git a/pkg/astnormalization/object_type_extending_test.go b/pkg/astnormalization/object_type_extending_test.go deleted file mode 100644 index 360e7dc2e..000000000 --- a/pkg/astnormalization/object_type_extending_test.go +++ /dev/null @@ -1,159 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendObjectType(t *testing.T) { - t.Run("extend object type by field", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Dog { - name: String - } - extend type Dog { - favoriteToy: String - } - `, ` - type Dog { - name: String - favoriteToy: String - } - extend type Dog { - favoriteToy: String - } - `) - }) - t.Run("extend object type by directive", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") - `, ` - type Cat @deprecated(reason: "not as cool as dogs") { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") - `) - }) - t.Run("extend object type by multiple field", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Dog { - name: String - } - extend type Dog { - favoriteToy: String - breed: String - } - `, ` - type Dog { - name: String - favoriteToy: String - breed: String - } - extend type Dog { - favoriteToy: String - breed: String - } - `) - }) - t.Run("extend object type by multiple directives", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) - `, ` - type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) - `) - }) - t.Run("extend object type by complex extends", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - age: Int - breed: String - } - `, ` - type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - name: String - age: Int - breed: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - age: Int - breed: String - } - `) - }) - t.Run("extend missing object type definition", func(t *testing.T) { - run(extendObjectTypeDefinition, `schema { query: Query }`, ` - extend type Query { me: String } - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { age: Int breed: String } - `, ` - extend type Query { me: String } - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { age: Int breed: String } - type Query { me: String } - type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { age: Int breed: String } - `) - }) - t.Run("extend object type by interface", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Dog { - name: String - } - extend type Dog implements ToyLover { - favoriteToy: String - } - interface ToyLover { - favoriteToy: String - } - `, ` - type Dog implements ToyLover { - name: String - favoriteToy: String - } - extend type Dog implements ToyLover { - favoriteToy: String - } - interface ToyLover { - favoriteToy: String - } - `) - }) - t.Run("extend object type which implements interface by interface", func(t *testing.T) { - run(extendObjectTypeDefinition, testDefinition, ` - type Dog implements ToyHater { - name: String - hatedToy: String - } - extend type Dog implements ToyLover { - favoriteToy: String - } - interface ToyLover { - favoriteToy: String - } - interface ToyHater { - hatedToy: String - } - `, ` - type Dog implements ToyHater & ToyLover { - name: String - hatedToy: String - favoriteToy: String - } - extend type Dog implements ToyLover { - favoriteToy: String - } - interface ToyLover { - favoriteToy: String - } - interface ToyHater { - hatedToy: String - } - `) - }) -} diff --git a/pkg/astnormalization/remove_self_aliasing.go b/pkg/astnormalization/remove_self_aliasing.go deleted file mode 100644 index cc68d28a7..000000000 --- a/pkg/astnormalization/remove_self_aliasing.go +++ /dev/null @@ -1,32 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func removeSelfAliasing(walker *astvisitor.Walker) { - visitor := removeSelfAliasingVisitor{} - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterFieldVisitor(&visitor) -} - -type removeSelfAliasingVisitor struct { - operation *ast.Document -} - -func (r *removeSelfAliasingVisitor) EnterDocument(operation, definition *ast.Document) { - r.operation = operation -} - -func (r *removeSelfAliasingVisitor) EnterField(ref int) { - if !r.operation.Fields[ref].Alias.IsDefined { - return - } - if !bytes.Equal(r.operation.FieldNameBytes(ref), r.operation.FieldAliasBytes(ref)) { - return - } - r.operation.RemoveFieldAlias(ref) -} diff --git a/pkg/astnormalization/remove_self_aliasing_test.go b/pkg/astnormalization/remove_self_aliasing_test.go deleted file mode 100644 index b444da3fa..000000000 --- a/pkg/astnormalization/remove_self_aliasing_test.go +++ /dev/null @@ -1,12 +0,0 @@ -package astnormalization - -import "testing" - -func TestRemoveSelfAliasing(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(removeSelfAliasing, testDefinition, ` - {dog: dog}`, - ` - {dog}`) - }) -} diff --git a/pkg/astnormalization/remove_type_extensions.go b/pkg/astnormalization/remove_type_extensions.go deleted file mode 100644 index 591bd038d..000000000 --- a/pkg/astnormalization/remove_type_extensions.go +++ /dev/null @@ -1,21 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func removeMergedTypeExtensions(walker *astvisitor.Walker) { - visitor := removeMergedTypeExtensionsVisitor{ - Walker: walker, - } - walker.RegisterLeaveDocumentVisitor(&visitor) -} - -type removeMergedTypeExtensionsVisitor struct { - *astvisitor.Walker -} - -func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) { - operation.RemoveMergedTypeExtensions() -} diff --git a/pkg/astnormalization/remove_type_extensions_test.go b/pkg/astnormalization/remove_type_extensions_test.go deleted file mode 100644 index 98bf224c9..000000000 --- a/pkg/astnormalization/remove_type_extensions_test.go +++ /dev/null @@ -1,214 +0,0 @@ -package astnormalization - -import "testing" - -func TestRemoveTypeExtensions(t *testing.T) { - t.Run("remove single type extension of fieldDefinition", func(t *testing.T) { - runManyOnDefinition(` - type Dog { - name: String - } - extend type Dog { - favoriteToy: String - } - `, ` - type Dog { - name: String - favoriteToy: String - } - `, - extendObjectTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove single type extension of directive", func(t *testing.T) { - runManyOnDefinition(` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") - `, ` - type Cat @deprecated(reason: "not as cool as dogs") { - name: String - } - `, - extendObjectTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove multiple type extensions at once", func(t *testing.T) { - runManyOnDefinition(` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") - extend type Cat { - age: Int - } - `, ` - type Cat @deprecated(reason: "not as cool as dogs") { - name: String - age: Int - } - `, - extendObjectTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove scalar type extensions", func(t *testing.T) { - runManyOnDefinition(` - scalar Coordinates - extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - `, ` - scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - `, - extendScalarTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove enum type extensions", func(t *testing.T) { - runManyOnDefinition(` - enum Countries {DE ES NL} - extend enum Countries @deprecated(reason: "some reason") @skip(if: false) {EN IT} - `, ` - enum Countries @deprecated(reason: "some reason") @skip(if: false) {DE ES NL EN IT} - `, - extendEnumTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove union type extensions", func(t *testing.T) { - runManyOnDefinition(` - union Mammal - extend union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog - `, ` - union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog - `, - extendUnionTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove input object type extensions", func(t *testing.T) { - runManyOnDefinition(` - input DogSize {width: Float height: Float} - extend input DogSize @deprecated(reason: "some reason") @skip(if: false) {breadth: Float weight: Float} - `, ` - input DogSize @deprecated(reason: "some reason") @skip(if: false) {width: Float height: Float breadth: Float weight: Float} - `, - extendInputObjectTypeDefinition, - removeMergedTypeExtensions) - }) - t.Run("remove interface type extensions", func(t *testing.T) { - runManyOnDefinition(` - interface Mammal { - name: String - } - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, ` - interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - name: String - furType: String - age: Int - } - `, - extendInterfaceTypeDefinition, - removeMergedTypeExtensions) - }) - - t.Run("remove object type extensions when object type definition does not exist", func(t *testing.T) { - runManyOnDefinition(` - extend type Query { - _entities(representations: [_Any!]!): [_Entity]! - _service: _Service! - } - - extend type Query { - me: User - } - `, ` - type Query { - _entities(representations: [_Any!]!): [_Entity]! - _service: _Service! - me: User - } - `, - extendObjectTypeDefinition, - removeMergedTypeExtensions) - }) - - t.Run("remove input object type extensions when input object type definition does not exist", func(t *testing.T) { - runManyOnDefinition(` - extend input Location { - lat: Float - } - - extend input Location { - lon: Float - } - `, ` - input Location { - lat: Float - lon: Float - } - `, - extendInputObjectTypeDefinition, - removeMergedTypeExtensions) - }) - - t.Run("remove enum type extensions when enum type does not exist", func(t *testing.T) { - runManyOnDefinition(` - extend enum Planet { - EARTH - } - - extend enum Planet { - MARS - } - `, ` - enum Planet { - EARTH - MARS - } - `, - extendEnumTypeDefinition, - removeMergedTypeExtensions) - }) - - t.Run("remove interface type extensions when interface type does not exist", func(t *testing.T) { - runManyOnDefinition(` - extend interface Entity { - id: ID - } - - extend interface Entity { - createdAt: String - } - `, ` - interface Entity { - id: ID - createdAt: String - } - `, - extendInterfaceTypeDefinition, - removeMergedTypeExtensions) - }) - - t.Run("remove scalar type extensions when scalar type does not exist", func(t *testing.T) { - runManyOnDefinition(` - extend scalar IPv4 - extend scalar IPv4 @deprecated(reason: "use IPv6") - `, ` - scalar IPv4 @deprecated(reason: "use IPv6") - `, - extendScalarTypeDefinition, - removeMergedTypeExtensions) - }) - - t.Run("remove union type extensions when union type does not exist", func(t *testing.T) { - runManyOnDefinition(` - extend union Response = SuccessResponse - extend union Response = ErrorResponse - `, ` - union Response = SuccessResponse | ErrorResponse - `, - extendUnionTypeDefinition, - removeMergedTypeExtensions) - }) -} diff --git a/pkg/astnormalization/scalar_type_extending.go b/pkg/astnormalization/scalar_type_extending.go deleted file mode 100644 index de4086adf..000000000 --- a/pkg/astnormalization/scalar_type_extending.go +++ /dev/null @@ -1,55 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func extendScalarTypeDefinition(walker *astvisitor.Walker) { - visitor := extendScalarTypeDefinitionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterScalarTypeExtensionVisitor(&visitor) -} - -func extendScalarTypeDefinitionKeepingOrphans(walker *astvisitor.Walker) { - visitor := extendScalarTypeDefinitionVisitor{ - Walker: walker, - keepExtensionOrphans: true, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterScalarTypeExtensionVisitor(&visitor) -} - -type extendScalarTypeDefinitionVisitor struct { - *astvisitor.Walker - operation *ast.Document - keepExtensionOrphans bool -} - -func (e *extendScalarTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.operation = operation -} - -func (e *extendScalarTypeDefinitionVisitor) EnterScalarTypeExtension(ref int) { - - nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.ScalarTypeExtensionNameBytes(ref)) - if !exists { - return - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindScalarTypeDefinition { - continue - } - e.operation.ExtendScalarTypeDefinitionByScalarTypeExtension(nodes[i].Ref, ref) - return - } - - if e.keepExtensionOrphans { - return - } - - e.operation.ImportAndExtendScalarTypeDefinitionByScalarTypeExtension(ref) -} diff --git a/pkg/astnormalization/scalar_type_extending_test.go b/pkg/astnormalization/scalar_type_extending_test.go deleted file mode 100644 index 796b9e445..000000000 --- a/pkg/astnormalization/scalar_type_extending_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendScalarType(t *testing.T) { - t.Run("extend simple scalar type", func(t *testing.T) { - run(extendScalarTypeDefinition, testDefinition, ` - scalar Coordinates - extend scalar Coordinates @deprecated(reason: "some reason") - `, ` - scalar Coordinates @deprecated(reason: "some reason") - extend scalar Coordinates @deprecated(reason: "some reason") - `) - }) - t.Run("extend scalar type by multiple directives", func(t *testing.T) { - run(extendScalarTypeDefinition, testDefinition, ` - scalar Coordinates - extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - `, ` - scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - `) - }) - t.Run("extend non-existent scalar", func(t *testing.T) { - run(extendScalarTypeDefinition, testDefinition, ` - extend scalar Mood - extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - `, ` - extend scalar Mood - extend scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - scalar Mood - scalar Coordinates @deprecated(reason: "some reason") @skip(if: false) - `) - }) -} diff --git a/pkg/astnormalization/subgraph_sdl_normalization.go b/pkg/astnormalization/subgraph_sdl_normalization.go deleted file mode 100644 index a49510397..000000000 --- a/pkg/astnormalization/subgraph_sdl_normalization.go +++ /dev/null @@ -1,33 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func NormalizeSubgraphSDL(definition *ast.Document, report *operationreport.Report) { - normalizer := NewSubgraphSDLNormalizer() - normalizer.NormalizeSubgraphSDL(definition, report) -} - -type SubgraphSDLNormalizer struct { - walker *astvisitor.Walker -} - -func NewSubgraphSDLNormalizer() *SubgraphSDLNormalizer { - normalizer := &SubgraphSDLNormalizer{} - normalizer.setupWalkers() - return normalizer -} - -func (s *SubgraphSDLNormalizer) setupWalkers() { - walker := astvisitor.NewWalker(48) - implicitExtendRootOperation(&walker) - extendsDirective(&walker) - s.walker = &walker -} - -func (s *SubgraphSDLNormalizer) NormalizeSubgraphSDL(definition *ast.Document, report *operationreport.Report) { - s.walker.Walk(definition, nil, report) -} diff --git a/pkg/astnormalization/subgraph_sdl_normalization_test.go b/pkg/astnormalization/subgraph_sdl_normalization_test.go deleted file mode 100644 index 15d1d9ac0..000000000 --- a/pkg/astnormalization/subgraph_sdl_normalization_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package astnormalization - -import ( - "testing" -) - -func TestNormalizeSubgraphSDL(t *testing.T) { - t.Run("support both extends directive and implicit extend keyword", func(_ *testing.T) { - runManyOnDefinition(` - type User @extends { - field: String! - } - type Query @extends {} - `, ` - extend type User { field: String! } extend type Query @extends {} - `, registerNormalizeFunc(implicitExtendRootOperation), registerNormalizeFunc(extendsDirective)) - }) - t.Run("support both extends directive and implicit extend keyword in schema", func(_ *testing.T) { - runManyOnDefinition(` - schema { - query: AQuery - } - type User @extends @directiv2 { - field: String! - } - type AQuery @key { - field: String - } - `, ` - schema { - query: AQuery - } - extend type User @directiv2 { field: String! } - extend type AQuery @key { - field: String - } - `, registerNormalizeFunc(implicitExtendRootOperation), registerNormalizeFunc(extendsDirective)) - }) -} diff --git a/pkg/astnormalization/union_type_extending.go b/pkg/astnormalization/union_type_extending.go deleted file mode 100644 index ac5ba6e29..000000000 --- a/pkg/astnormalization/union_type_extending.go +++ /dev/null @@ -1,54 +0,0 @@ -package astnormalization - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func extendUnionTypeDefinition(walker *astvisitor.Walker) { - visitor := extendUnionTypeDefinitionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterUnionTypeExtensionVisitor(&visitor) -} - -func extendUnionTypeDefinitionKeepingOrphans(walker *astvisitor.Walker) { - visitor := extendUnionTypeDefinitionVisitor{ - Walker: walker, - keepExtensionOrphans: true, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterUnionTypeExtensionVisitor(&visitor) -} - -type extendUnionTypeDefinitionVisitor struct { - *astvisitor.Walker - operation *ast.Document - keepExtensionOrphans bool -} - -func (e *extendUnionTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.operation = operation -} - -func (e *extendUnionTypeDefinitionVisitor) EnterUnionTypeExtension(ref int) { - nodes, exists := e.operation.Index.NodesByNameBytes(e.operation.UnionTypeExtensionNameBytes(ref)) - if !exists { - return - } - - for i := range nodes { - if nodes[i].Kind != ast.NodeKindUnionTypeDefinition { - continue - } - e.operation.ExtendUnionTypeDefinitionByUnionTypeExtension(nodes[i].Ref, ref) - return - } - - if e.keepExtensionOrphans { - return - } - - e.operation.ImportAndExtendUnionTypeDefinitionByUnionTypeExtension(ref) -} diff --git a/pkg/astnormalization/union_type_extending_test.go b/pkg/astnormalization/union_type_extending_test.go deleted file mode 100644 index 5cad231db..000000000 --- a/pkg/astnormalization/union_type_extending_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package astnormalization - -import "testing" - -func TestExtendUnionType(t *testing.T) { - t.Run("extend union type by directive", func(t *testing.T) { - run(extendUnionTypeDefinition, testDefinition, ` - union Mammal - extend union Mammal @deprecated(reason: "some reason") - `, ` - union Mammal @deprecated(reason: "some reason") - extend union Mammal @deprecated(reason: "some reason") - `) - }) - t.Run("extend union type by UnionMemberType", func(t *testing.T) { - run(extendUnionTypeDefinition, testDefinition, ` - union Mammal - extend union Mammal = Cat - `, ` - union Mammal = Cat - extend union Mammal = Cat - `) - }) - t.Run("extend union type by multiple UnionMemberTypes", func(t *testing.T) { - run(extendUnionTypeDefinition, testDefinition, ` - union Mammal - extend union Mammal = Cat | Dog - `, ` - union Mammal = Cat | Dog - extend union Mammal = Cat | Dog - `) - }) - t.Run("extend union by multiple directives and union members", func(t *testing.T) { - run(extendUnionTypeDefinition, testDefinition, ` - union Mammal - extend union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog - `, ` - union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog - extend union Mammal @deprecated(reason: "some reason") @skip(if: false) = Cat | Dog - `) - }) - t.Run("extend union type which already has union member", func(t *testing.T) { - run(extendUnionTypeDefinition, testDefinition, ` - union Mammal = Cat - extend union Mammal @deprecated(reason: "some reason") = Dog - `, ` - union Mammal @deprecated(reason: "some reason") = Cat | Dog - extend union Mammal @deprecated(reason: "some reason") = Dog - `) - }) - t.Run("extend non-existent union", func(t *testing.T) { - run(extendUnionTypeDefinition, testDefinition, ` - extend union Response = SuccessResponse | ErrorResponse - extend union Mammal @deprecated(reason: "some reason") = Dog - `, ` - extend union Response = SuccessResponse | ErrorResponse - extend union Mammal @deprecated(reason: "some reason") = Dog - union Response = SuccessResponse | ErrorResponse - union Mammal @deprecated(reason: "some reason") = Dog - `) - }) -} diff --git a/pkg/astnormalization/variables_default_value_extraction.go b/pkg/astnormalization/variables_default_value_extraction.go deleted file mode 100644 index 1a24b7cfd..000000000 --- a/pkg/astnormalization/variables_default_value_extraction.go +++ /dev/null @@ -1,218 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/buger/jsonparser" - "github.com/tidwall/sjson" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astimport" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -func extractVariablesDefaultValue(walker *astvisitor.Walker) *variablesDefaultValueExtractionVisitor { - visitor := &variablesDefaultValueExtractionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterOperationDefinitionVisitor(visitor) - walker.RegisterEnterVariableDefinitionVisitor(visitor) - walker.RegisterEnterFieldVisitor(visitor) - return visitor -} - -type variablesDefaultValueExtractionVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - importer astimport.Importer - operationName []byte - operationRef int - skip bool - nonNullableVariablesNames [][]byte - extractedVariablesRefs []int -} - -func (v *variablesDefaultValueExtractionVisitor) EnterField(ref int) { - if v.skip { - return - } - - // find field definition from document - fieldName := v.operation.FieldNameBytes(ref) - fieldDefRef, ok := v.definition.NodeFieldDefinitionByName(v.EnclosingTypeDefinition, fieldName) - if !ok { - return - } - - // skip when field has no args in the document - if !v.definition.FieldDefinitions[fieldDefRef].HasArgumentsDefinitions { - return - } - - for _, definitionInputValueDefRef := range v.definition.FieldDefinitions[fieldDefRef].ArgumentsDefinition.Refs { - operationArgRef, exists := v.operation.FieldArgument(ref, v.definition.InputValueDefinitionNameBytes(definitionInputValueDefRef)) - - if exists { - operationArgValue := v.operation.ArgumentValue(operationArgRef) - if v.operation.ValueContainsVariable(operationArgValue) { - defTypeRef := v.definition.InputValueDefinitions[definitionInputValueDefRef].Type - v.traverseValue(operationArgValue, defTypeRef) - } - } else { - v.processDefaultFieldArguments(ref, definitionInputValueDefRef) - } - } -} - -func (v *variablesDefaultValueExtractionVisitor) EnterVariableDefinition(ref int) { - if v.skip { - return - } - - // skip when we have no default value for variable - if !v.operation.VariableDefinitionHasDefaultValue(ref) { - return - } - - variableName := v.operation.VariableDefinitionNameString(ref) - - // remove variable DefaultValue from operation - v.operation.VariableDefinitions[ref].DefaultValue.IsDefined = false - - // skip when variable was provided - _, _, _, err := jsonparser.Get(v.operation.Input.Variables, variableName) - if err == nil { - return - } - - // store extracted variable ref - v.extractedVariablesRefs = append(v.extractedVariablesRefs, ref) - - valueBytes, err := v.operation.ValueToJSON(v.operation.VariableDefinitionDefaultValue(ref)) - if err != nil { - return - } - - v.operation.Input.Variables, err = sjson.SetRawBytes(v.operation.Input.Variables, variableName, valueBytes) - if err != nil { - v.StopWithInternalErr(err) - return - } -} - -func (v *variablesDefaultValueExtractionVisitor) EnterOperationDefinition(ref int) { - if len(v.operationName) == 0 { - v.skip = false - return - } - operationName := v.operation.OperationDefinitionNameBytes(ref) - v.operationRef = ref - v.skip = !bytes.Equal(operationName, v.operationName) - - v.nonNullableVariablesNames = make([][]byte, 0, len(v.operation.VariableDefinitions)) - v.extractedVariablesRefs = make([]int, 0, len(v.operation.VariableDefinitions)) -} - -func (v *variablesDefaultValueExtractionVisitor) LeaveOperationDefinition(_ int) { - if v.skip { - return - } - - // find and make variable not null - for j := 0; j < len(v.extractedVariablesRefs); j++ { - variableDefRef := v.extractedVariablesRefs[j] - - if v.operation.Types[v.operation.VariableDefinitions[variableDefRef].Type].TypeKind == ast.TypeKindNonNull { - // when variable is already not null, skip - continue - } - - for i := 0; i < len(v.nonNullableVariablesNames); i++ { - if bytes.Equal(v.operation.VariableDefinitionNameBytes(variableDefRef), v.nonNullableVariablesNames[i]) { - // if variable is nullable, make it not null as it satisfies both not null and nullable types - // it is required to keep operation valid after variable extraction - v.operation.VariableDefinitions[variableDefRef].Type = v.operation.AddNonNullType(v.operation.VariableDefinitions[variableDefRef].Type) - } - } - } -} - -func (v *variablesDefaultValueExtractionVisitor) traverseValue(value ast.Value, defTypeRef int) { - switch value.Kind { - case ast.ValueKindVariable: - v.saveArgumentsWithTypeNotNull(value.Ref, defTypeRef) - case ast.ValueKindList: - for _, ref := range v.operation.ListValues[value.Ref].Refs { - listValue := v.operation.Value(ref) - if !v.operation.ValueContainsVariable(listValue) { - continue - } - - listTypeRef := defTypeRef - // omit not null to get to list itself - if v.definition.Types[listTypeRef].TypeKind == ast.TypeKindNonNull { - listTypeRef = v.definition.Types[listTypeRef].OfType - } - - listItemType := v.definition.Types[listTypeRef].OfType - v.traverseValue(listValue, listItemType) - } - case ast.ValueKindObject: - for _, ref := range v.operation.ObjectValues[value.Ref].Refs { - fieldName := v.operation.Input.ByteSlice(v.operation.ObjectFields[ref].Name) - fieldValue := v.operation.ObjectFields[ref].Value - - typeName := v.definition.ResolveTypeNameString(defTypeRef) - typeDefinitionNode, ok := v.definition.Index.FirstNodeByNameStr(typeName) - if !ok { - continue - } - objectFieldDefinitionRef, ok := v.definition.NodeInputFieldDefinitionByName(typeDefinitionNode, fieldName) - if !ok { - continue - } - - if v.operation.ValueContainsVariable(fieldValue) { - v.traverseValue(fieldValue, v.definition.InputValueDefinitions[objectFieldDefinitionRef].Type) - } - } - } -} - -func (v *variablesDefaultValueExtractionVisitor) saveArgumentsWithTypeNotNull(operationVariableValueRef, defTypeRef int) { - if v.definition.Types[defTypeRef].TypeKind != ast.TypeKindNonNull { - return - } - - v.nonNullableVariablesNames = append(v.nonNullableVariablesNames, v.operation.VariableValueNameBytes(operationVariableValueRef)) -} - -func (v *variablesDefaultValueExtractionVisitor) processDefaultFieldArguments(operationFieldRef, definitionInputValueDefRef int) { - if !v.definition.InputValueDefinitionHasDefaultValue(definitionInputValueDefRef) { - return - } - - variableNameBytes := v.operation.GenerateUnusedVariableDefinitionName(v.Ancestors[0].Ref) - valueBytes, err := v.definition.ValueToJSON(v.definition.InputValueDefinitionDefaultValue(definitionInputValueDefRef)) - if err != nil { - return - } - v.operation.Input.Variables, err = sjson.SetRawBytes(v.operation.Input.Variables, unsafebytes.BytesToString(variableNameBytes), valueBytes) - if err != nil { - v.StopWithInternalErr(err) - return - } - - variableValueRef, argRef := v.operation.ImportVariableValueArgument(v.definition.InputValueDefinitionNameBytes(definitionInputValueDefRef), variableNameBytes) - defType := v.definition.InputValueDefinitions[definitionInputValueDefRef].Type - importedDefType := v.importer.ImportType(defType, v.definition, v.operation) - - v.operation.AddArgumentToField(operationFieldRef, argRef) - v.operation.AddVariableDefinitionToOperationDefinition(v.operationRef, variableValueRef, importedDefType) -} - -func (v *variablesDefaultValueExtractionVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation, v.definition = operation, definition -} diff --git a/pkg/astnormalization/variables_default_value_extraction_test.go b/pkg/astnormalization/variables_default_value_extraction_test.go deleted file mode 100644 index 3dc9aa91c..000000000 --- a/pkg/astnormalization/variables_default_value_extraction_test.go +++ /dev/null @@ -1,269 +0,0 @@ -package astnormalization - -import ( - "testing" -) - -const ( - variablesDefaultValueExtractionDefinition = ` - schema { mutation: Mutation } - type Query { - complex(input: ComplexInput): String - mixedArgs(a: String, b: String!): String - objectInList(input: [Nested]): String - objectInNestedList(input: [[Nested]]): String - stringInNestedList(input: [[String!]]): String - nullableStringInNestedList(input: [[String]]): String - } - input Nested { - NotNullable: String! - Nullable: String - } - input ComplexInput { - NotNullable: String! - Nullable: String - list: [String] - listOfNonNull: [String!] - listNonNullItemNullable: [String]! - listNonNullItemNotNull: [String!]! - } - type Mutation { - simple(input: String = "foo"): String - mixed(a: String, b: String, input: String = "foo", nonNullInput: String! = "bar"): String - } - scalar String - input ComplexInput { - NotNullable: String! - Nullable: String - list: [String] - listNonNull: [String]! - listNonNullItemNonNull: [String!]! - listNonNull: [String!] - } - ` -) - -func TestVariablesDefaultValueExtraction(t *testing.T) { - t.Run("field argument default value", func(t *testing.T) { - t.Run("no value provided", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - mutation simple { - simple - }`, "", ` - mutation simple($a: String) { - simple(input: $a) - }`, ``, `{"a":"foo"}`) - }) - - t.Run("value provided", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - mutation simple { - simple(input: "bazz") - }`, "", ` - mutation simple { - simple(input: "bazz") - }`, ``, ``) - }) - - t.Run("mixed", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - mutation simple($a: String) { - mixed(a: $a, b: "bar") - }`, "", ` - mutation simple($a: String, $b: String, $c: String!) { - mixed(a: $a, b: "bar", input: $b, nonNullInput: $c) - }`, `{"a":"aaa"}`, `{"c":"bar","b":"foo","a":"aaa"}`) - }) - }) - - t.Run("variable with default value", func(t *testing.T) { - t.Run("no value provided", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - mutation simple($in: String = "bar" ) { - simple(input: $in) - }`, "", ` - mutation simple($in: String) { - simple(input: $in) - }`, ``, `{"in":"bar"}`) - }) - t.Run("value provided", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - mutation simple($in: String = "bar" ) { - simple(input: $in) - }`, "", ` - mutation simple($in: String) { - simple(input: $in) - }`, `{"in":"foo"}`, `{"in":"foo"}`) - }) - - t.Run("multiple variables with default values", func(t *testing.T) { - t.Run("vars inside object and lists", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $nullable: String = "a", - $notNullable: String = "b", - $strIntolist: String = "1", - $strIntolistOfNonNull: String = "2" - $strIntolistNonNullItemNullable: String = "3", - $strIntolistNonNullItemNotNull: String = "4" - ) { - complex(input: { - NotNullable: $notNullable, - Nullable: $nullable, - list: [$strIntolist], - listOfNonNull: [$strIntolistOfNonNull], - listNonNullItemNullable: [$strIntolistNonNullItemNullable], - listNonNullItemNotNull: [$strIntolistNonNullItemNotNull], - }) - }`, "", ` - query q( - $nullable: String, - $notNullable: String!, - $strIntolist: String, - $strIntolistOfNonNull: String! - $strIntolistNonNullItemNullable: String, - $strIntolistNonNullItemNotNull: String! - ) { - complex(input: { - NotNullable: $notNullable, - Nullable: $nullable, - list: [$strIntolist], - listOfNonNull: [$strIntolistOfNonNull], - listNonNullItemNullable: [$strIntolistNonNullItemNullable], - listNonNullItemNotNull: [$strIntolistNonNullItemNotNull], - }) - }`, - ``, - `{"strIntolistNonNullItemNotNull":"4","strIntolistNonNullItemNullable":"3","strIntolistOfNonNull":"2","strIntolist":"1","notNullable":"b","nullable":"a"}`) - }) - t.Run("vars as lists", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $nullable: String = "a", - $notNullable: String = "b", - $list: [String] = ["1"], - $listOfNonNull: [String!] = ["2"] - $listNonNullItemNullable: [String] = ["3"], - $listNonNullItemNotNull: [String!] = ["4"] - ) { - complex(input: { - NotNullable: $notNullable, - Nullable: $nullable, - list: $list, - listOfNonNull: $listOfNonNull - listNonNullItemNullable: $listNonNullItemNullable, - listNonNullItemNotNull: $listNonNullItemNotNull, - }) - }`, ``, ` - query q( - $nullable: String, - $notNullable: String!, - $list: [String], - $listOfNonNull: [String!] - $listNonNullItemNullable: [String]!, - $listNonNullItemNotNull: [String!]! - ) { - complex(input: { - NotNullable: $notNullable, - Nullable: $nullable, - list: $list, - listOfNonNull: $listOfNonNull - listNonNullItemNullable: $listNonNullItemNullable, - listNonNullItemNotNull: $listNonNullItemNotNull, - }) - }`, - ``, - `{"listNonNullItemNotNull":["4"],"listNonNullItemNullable":["3"],"listOfNonNull":["2"],"list":["1"],"notNullable":"b","nullable":"a"}`) - }) - }) - - t.Run("variables in lists", func(t *testing.T) { - t.Run("object in list", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $nullable: String = "a", - $notNullable: String = "b", - ) { - objectInList(input: [{NotNullable: $notNullable, Nullable: $nullable}]) - }`, "", ` - query q( - $nullable: String, - $notNullable: String!, - ) { - objectInList(input: [{NotNullable: $notNullable, Nullable: $nullable}]) - }`, ``, `{"notNullable":"b","nullable":"a"}`) - }) - - t.Run("object in nested list", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $nullable: String = "a", - $notNullable: String = "b", - ) { - objectInNestedList(input: [[{NotNullable: $notNullable, Nullable: $nullable}]]) - }`, "", ` - query q( - $nullable: String, - $notNullable: String!, - ) { - objectInNestedList(input: [[{NotNullable: $notNullable, Nullable: $nullable}]]) - }`, ``, `{"notNullable":"b","nullable":"a"}`) - }) - - t.Run("not nullable string in nested list", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $notNullable: String = "foo", - ) { - stringInNestedList(input: [["a", $notNullable]]) - }`, "", ` - query q( - $notNullable: String!, - ) { - stringInNestedList(input: [["a", $notNullable]]) - }`, ``, `{"notNullable":"foo"}`) - }) - - t.Run("nullable string in nested list", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $nullable: String = "foo", - ) { - nullableStringInNestedList(input: [["a", null, $nullable]]) - }`, "", ` - query q( - $nullable: String, - ) { - nullableStringInNestedList(input: [["a", null, $nullable]]) - }`, ``, `{"nullable":"foo"}`) - }) - }) - }) - - t.Run("mixed nullable and not nullable variables", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - query q( - $nullable: String = "a", - $notNullable: String = "b", - ) { - mixedArgs(a: $nullable, b: $notNullable) - }`, "", ` - query q( - $nullable: String, - $notNullable: String!, - ) { - mixedArgs(a: $nullable, b: $notNullable) - }`, ``, `{"notNullable":"b","nullable":"a"}`) - }) - - t.Run("mixed default values of field args and variables", func(t *testing.T) { - runWithVariablesDefaultValues(t, extractVariablesDefaultValue, variablesDefaultValueExtractionDefinition, ` - mutation simple($a: String = "bar", $b: String = "bazz") { - mixed(a: $a, b: $b) - }`, "", ` - mutation simple($a: String, $b: String, $c: String, $d: String!) { - mixed(a: $a, b: $b, input: $c, nonNullInput: $d) - }`, `{"a":"aaa"}`, `{"d":"bar","c":"foo","b":"bazz","a":"aaa"}`) - - }) -} diff --git a/pkg/astnormalization/variables_extraction.go b/pkg/astnormalization/variables_extraction.go deleted file mode 100644 index 643d9c890..000000000 --- a/pkg/astnormalization/variables_extraction.go +++ /dev/null @@ -1,198 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/tidwall/sjson" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astimport" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" -) - -func extractVariables(walker *astvisitor.Walker) *variablesExtractionVisitor { - visitor := &variablesExtractionVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterArgumentVisitor(visitor) - walker.RegisterEnterOperationVisitor(visitor) - return visitor -} - -type variablesExtractionVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - importer astimport.Importer - operationName []byte - skip bool -} - -func (v *variablesExtractionVisitor) EnterOperationDefinition(ref int) { - if len(v.operationName) == 0 { - v.skip = false - return - } - operationName := v.operation.OperationDefinitionNameBytes(ref) - v.skip = !bytes.Equal(operationName, v.operationName) -} - -func (v *variablesExtractionVisitor) EnterArgument(ref int) { - if v.skip { - return - } - if v.operation.Arguments[ref].Value.Kind == ast.ValueKindVariable { - return - } - if len(v.Ancestors) == 0 || v.Ancestors[0].Kind != ast.NodeKindOperationDefinition { - return - } - - for i := range v.Ancestors { - if v.Ancestors[i].Kind == ast.NodeKindDirective { - return // skip all directives in any case - } - } - - inputValueDefinition, ok := v.Walker.ArgumentInputValueDefinition(ref) - if !ok { - return - } - - containsVariable := v.operation.ValueContainsVariable(v.operation.Arguments[ref].Value) - if containsVariable { - v.traverseValue(v.operation.Arguments[ref].Value, ref, inputValueDefinition) - return - } - - variableNameBytes := v.operation.GenerateUnusedVariableDefinitionName(v.Ancestors[0].Ref) - valueBytes, err := v.operation.ValueToJSON(v.operation.Arguments[ref].Value) - if err != nil { - return - } - v.operation.Input.Variables, err = sjson.SetRawBytes(v.operation.Input.Variables, unsafebytes.BytesToString(variableNameBytes), valueBytes) - if err != nil { - v.StopWithInternalErr(err) - return - } - - variable := ast.VariableValue{ - Name: v.operation.Input.AppendInputBytes(variableNameBytes), - } - - v.operation.VariableValues = append(v.operation.VariableValues, variable) - - varRef := len(v.operation.VariableValues) - 1 - - v.operation.Arguments[ref].Value.Ref = varRef - v.operation.Arguments[ref].Value.Kind = ast.ValueKindVariable - - defRef, ok := v.ArgumentInputValueDefinition(ref) - if !ok { - return - } - - defType := v.definition.InputValueDefinitions[defRef].Type - - importedDefType := v.importer.ImportType(defType, v.definition, v.operation) - - v.operation.VariableDefinitions = append(v.operation.VariableDefinitions, ast.VariableDefinition{ - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: varRef, - }, - Type: importedDefType, - }) - - newVariableRef := len(v.operation.VariableDefinitions) - 1 - - v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs = - append(v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs, newVariableRef) - v.operation.OperationDefinitions[v.Ancestors[0].Ref].HasVariableDefinitions = true -} - -func (v *variablesExtractionVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation, v.definition = operation, definition -} - -func (v *variablesExtractionVisitor) traverseValue(value ast.Value, argRef, inputValueDefinition int) { - switch value.Kind { - case ast.ValueKindList: - for _, ref := range v.operation.ListValues[value.Ref].Refs { - listValue := v.operation.Value(ref) - v.traverseValue(listValue, argRef, inputValueDefinition) - } - case ast.ValueKindObject: - objectValueRefs := make([]int, len(v.operation.ObjectValues[value.Ref].Refs)) - copy(objectValueRefs, v.operation.ObjectValues[value.Ref].Refs) - for _, ref := range objectValueRefs { - fieldName := v.operation.Input.ByteSlice(v.operation.ObjectFields[ref].Name) - fieldValue := v.operation.ObjectFields[ref].Value - switch fieldValue.Kind { - case ast.ValueKindVariable: - continue - default: - - typeName := v.definition.ResolveTypeNameString(v.definition.InputValueDefinitions[inputValueDefinition].Type) - typeDefinitionNode, ok := v.definition.Index.FirstNodeByNameStr(typeName) - if !ok { - continue - } - objectFieldDefinition, ok := v.definition.NodeInputFieldDefinitionByName(typeDefinitionNode, fieldName) - if !ok { - continue - } - - if v.operation.ValueContainsVariable(fieldValue) { - v.traverseValue(fieldValue, argRef, objectFieldDefinition) - continue - } - v.extractObjectValue(ref, fieldValue, objectFieldDefinition) - } - } - } -} - -func (v *variablesExtractionVisitor) extractObjectValue(objectField int, fieldValue ast.Value, inputValueDefinition int) { - - variableNameBytes := v.operation.GenerateUnusedVariableDefinitionName(v.Ancestors[0].Ref) - valueBytes, err := v.operation.ValueToJSON(fieldValue) - if err != nil { - return - } - v.operation.Input.Variables, err = sjson.SetRawBytes(v.operation.Input.Variables, unsafebytes.BytesToString(variableNameBytes), valueBytes) - if err != nil { - v.StopWithInternalErr(err) - return - } - - variable := ast.VariableValue{ - Name: v.operation.Input.AppendInputBytes(variableNameBytes), - } - - v.operation.VariableValues = append(v.operation.VariableValues, variable) - - varRef := len(v.operation.VariableValues) - 1 - - v.operation.ObjectFields[objectField].Value.Kind = ast.ValueKindVariable - v.operation.ObjectFields[objectField].Value.Ref = varRef - - defType := v.definition.InputValueDefinitions[inputValueDefinition].Type - - importedDefType := v.importer.ImportType(defType, v.definition, v.operation) - - v.operation.VariableDefinitions = append(v.operation.VariableDefinitions, ast.VariableDefinition{ - VariableValue: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: varRef, - }, - Type: importedDefType, - }) - - newVariableRef := len(v.operation.VariableDefinitions) - 1 - - v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs = - append(v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs, newVariableRef) - v.operation.OperationDefinitions[v.Ancestors[0].Ref].HasVariableDefinitions = true -} diff --git a/pkg/astnormalization/variables_extraction_test.go b/pkg/astnormalization/variables_extraction_test.go deleted file mode 100644 index 0dd77d36f..000000000 --- a/pkg/astnormalization/variables_extraction_test.go +++ /dev/null @@ -1,1337 +0,0 @@ -package astnormalization - -import ( - "testing" -) - -const ( - variablesExtractionDefinition = ` - schema { mutation: Mutation } - type Mutation { - httpBinPost(input: HttpBinPostInput): HttpBinPostResponse - } - input HttpBinPostInput { - foo: String! - } - type HttpBinPostResponse { - headers: Headers - data: HttpBinPostResponseData - } - type HttpBinPostResponseData { - foo: String - } - type Headers { - userAgent: String! - host: String! - acceptEncoding: String - Authorization: String - } - scalar String - ` -) - -func TestVariablesExtraction(t *testing.T) { - t.Run("simple http bin example", func(t *testing.T) { - runWithVariables(t, extractVariables, variablesExtractionDefinition, ` - mutation HttpBinPost { - httpBinPost(input: {foo: "bar"}){ - headers { - userAgent - } - data { - foo - } - } - }`, "", ` - mutation HttpBinPost($a: HttpBinPostInput){ - httpBinPost(input: $a){ - headers { - userAgent - } - data { - foo - } - } - }`, ``, `{"a":{"foo":"bar"}}`) - }) - t.Run("enum", func(t *testing.T) { - runWithVariables(t, extractVariables, forumExampleSchema, ` - mutation EnumOperation { - useEnum(simpleEnum: Foo) - }`, - "EnumOperation", ` - mutation EnumOperation($a: SimpleEnum) { - useEnum(simpleEnum: $a) - }`, - ``, - `{"a":"Foo"}`) - }) - t.Run("variables in argument", func(t *testing.T) { - runWithVariables(t, extractVariables, variablesExtractionDefinition, ` - mutation HttpBinPost($foo: String! = "bar") { - httpBinPost(input: {foo: $foo}){ - headers { - userAgent - } - data { - foo - } - } - }`, "", ` - mutation HttpBinPost($foo: String! = "bar") { - httpBinPost(input: {foo: $foo}){ - headers { - userAgent - } - data { - foo - } - } - }`, ``, ``) - }) - t.Run("multiple queries", func(t *testing.T) { - runWithVariables(t, extractVariables, forumExampleSchema, ` - mutation Register { - createUser(input: {user: {id: "jens" username: "jens"}}){ - user { - id - username - } - } - } - mutation CreatePost { - createPost(input: {post: {authorId: "jens" title: "my post" body: "my body"}}){ - post { - id - title - body - userByAuthorId { - username - } - } - } - }`, "Register", ` - mutation Register($a: CreateUserInput) { - createUser(input: $a){ - user { - id - username - } - } - } - mutation CreatePost { - createPost(input: {post: {authorId: "jens" title: "my post" body: "my body"}}){ - post { - id - title - body - userByAuthorId { - username - } - } - } - }`, ``, `{"a":{"user":{"id":"jens","username":"jens"}}}`) - }) - t.Run("values on directives should be ignored", func(t *testing.T) { - runWithVariables(t, extractVariables, forumExampleSchema, ` - mutation Register($a: CreateUserInput @foo(name: "bar")) { - createUser(input: $a){ - user { - id - username - } - } - }`, "Register", ` - mutation Register($a: CreateUserInput @foo(name: "bar")) { - createUser(input: $a){ - user { - id - username - } - } - }`, ``, ``) - }) - t.Run("complex nesting", func(t *testing.T) { - runWithVariables(t, extractVariables, authSchema, ` - mutation Login ($phoneNumber: String!) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - applicationId: "123" - loginId: $phoneNumber - } - ) { - code - } - }`, "Login", ` - mutation Login ($phoneNumber: String! $a: String) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - applicationId: $a - loginId: $phoneNumber - } - ) { - code - } - }`, ``, `{"a":"123"}`) - }) - t.Run("complex nesting with existing variable", func(t *testing.T) { - runWithVariables(t, extractVariables, authSchema, ` - mutation Login ($phoneNumber: String!) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - applicationId: "123" - loginId: $phoneNumber - } - ) { - code - } - }`, "Login", ` - mutation Login ($phoneNumber: String! $a: String) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - applicationId: $a - loginId: $phoneNumber - } - ) { - code - } - }`, `{"phoneNumber":"456"}`, `{"a":"123","phoneNumber":"456"}`) - }) - t.Run("complex nesting with deep nesting", func(t *testing.T) { - runWithVariables(t, extractVariables, authSchema, ` - mutation Login ($phoneNumber: String!) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - nested: { - applicationId: "123" - loginId: $phoneNumber - } - } - ) { - code - } - }`, "Login", ` - mutation Login ($phoneNumber: String! $a: String) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - nested: { - applicationId: $a - loginId: $phoneNumber - } - } - ) { - code - } - }`, `{"phoneNumber":"456"}`, `{"a":"123","phoneNumber":"456"}`) - }) - t.Run("complex nesting with deep nesting and lists", func(t *testing.T) { - runWithVariables(t, extractVariables, authSchema, ` - mutation Login ($phoneNumber: String!) { - Login: postPasswordlessStartList( - postPasswordlessStartInput: [{ - nested: { - applicationId: "123" - loginId: $phoneNumber - } - }] - ) { - code - } - }`, "Login", ` - mutation Login ($phoneNumber: String! $a: String) { - Login: postPasswordlessStartList( - postPasswordlessStartInput: [{ - nested: { - applicationId: $a - loginId: $phoneNumber - } - }] - ) { - code - } - }`, `{"phoneNumber":"456"}`, `{"a":"123","phoneNumber":"456"}`) - }) - t.Run("complex nesting with variable in list", func(t *testing.T) { - runWithVariables(t, extractVariables, authSchema, ` - mutation Login ($input: postPasswordlessStartInput!) { - Login: postPasswordlessStartList( - postPasswordlessStartInput: [$input] - ) { - code - } - }`, "Login", ` - mutation Login ($input: postPasswordlessStartInput!) { - Login: postPasswordlessStartList( - postPasswordlessStartInput: [$input] - ) { - code - } - }`, ``, ``) - }) - t.Run("nested inline string", func(t *testing.T) { - runWithVariables(t, extractVariables, nexusSchema, ` - mutation Draw ($drawDate: AWSDate!, $play: PlayInput!) { - AddTicket: addCartItem( - item: { - drawDate: $drawDate - fractional: false - play: $play - quantity: 1 - regionGameId: "lucky7|UAE" - } - ) { - id - } - }`, "Draw", ` - mutation Draw ($drawDate: AWSDate!, $play: PlayInput! $a: Boolean! $b: Int! $c: String!) { - AddTicket: addCartItem( - item: { - drawDate: $drawDate - fractional: $a - play: $play - quantity: $b - regionGameId: $c - } - ) { - id - } - }`, `{}`, `{"c":"lucky7|UAE","b":1,"a":false}`) - }) -} - -const forumExampleSchema = ` -schema { - mutation: Mutation -} -scalar String -enum SimpleEnum { - Foo - Bar -} -type Mutation { - createUser(input: CreateUserInput): CreateUser - createPost(input: CreatePostInput): CreatePost - useEnum(simpleEnum: SimpleEnum): String -} -input CreateUserInput { - user: UserInput -} -input UserInput { - id: String! - username: String! -} -input CreatePostInput { - post: PostInput -} -input PostInput { - authorId: String! - title: String! - body: String! -} -type CreateUser { - user: User -} -type CreatePost { - post: Post -} -type User { - id: String! - username: String! -} -type Post { - id: String! - title: String! - body: String! - userByAuthorId: User -} -` - -const authSchema = ` -type Mutation { - postPasswordlessStart(postPasswordlessStartInput: postPasswordlessStartInput): PostPasswordlessStart - postPasswordlessStartList(postPasswordlessStartInput: [postPasswordlessStartInput]): PostPasswordlessStart - postPasswordlessLogin(postPasswordlessLoginInput: postPasswordlessLoginInput): PostPasswordlessLogin -} - -type PostPasswordlessStart { - code: String -} - -input postPasswordlessStartInput { - applicationId: String - loginId: String - nested: postPasswordlessStartInput -} - -type PostPasswordlessLogin { - refreshToken: String - token: String - user: User -} - -type User { - username: String - verified: Boolean - firstName: String - lastName: String - email: String - mobilePhone: String - timezone: String -} - -input postPasswordlessLoginInput { - code: String - ipAddress: String - metaData: MetaDataInput -} - -input MetaDataInput { - device: DeviceInput -} - -input DeviceInput { - name: String -} -` - -const nexusSchema = ` -type Mutation { - postPasswordlessStart(postPasswordlessStartInput: postPasswordlessStartInput): PostPasswordlessStartResponse - postPasswordlessLogin(postPasswordlessLoginInput: postPasswordlessLoginInput): PostPasswordlessLoginResponse - postJwtRefresh(postJwtRefreshInput: postJwtRefreshInput): PostJwtRefreshResponse - acceptPoolInvite(poolId: String!): Boolean! - addCartItem(item: AddCartItemInput!): Cart! - addTicketToPool(poolId: String!, ticketId: String!): Boolean! - archiveAggTicket(archived: Boolean!, id: ID!): AggTicket! - cancelOrder(input: CancelOrderInput!): Order! - createCancelOrderTask(input: CreateCancelOrderTaskInput!): CancelOrderTask! - createLocationGame(locationGame: CreateLocationGameInput!): LocationGame! - createPool(pool: CreatePoolInput!): Pool! - createRecurringOrder(recurringOrder: CreateRecurringOrderInput!): RecurringOrder! - createRegionGame(regionGame: CreateRegionGameInput!): RegionGame! - createRegionGameDraw(regionGameDraw: CreateRegionGameDrawInput!): RegionGameDraw! - deleteLocationGame(id: ID!): Boolean! - deletePool(id: ID!): Boolean! - deleteRecurringOrder(id: ID!): Boolean! - deleteRegionGame(id: ID!): Boolean! - emptyCart: Cart! - expressCheckout: Order! - generateFreeTicket(freeTicket: GenerateFreeTicketInput!): [Ticket]! - inviteToPool(poolId: String!, userId: String!): PoolInvite! - leavePool(poolId: String!): Boolean! - ledgerTransfer(options: TransferOptions, requests: [TransferRequest!]!): [LedgerTransferResponse!]! - markTaskComplete(input: MarkTaskCompleteInput!): Task! - markTaskFailed(input: MarkTaskFailedInput!): Task! - registerDevice(device: RegisterDeviceInput!): Device! - rejectPoolInvite(poolId: String!): Boolean! - removeCartItem(index: Int!): Cart! - removeTicketFromPool(ticketId: String!): Boolean! - sendReceiptDuplicate(orderId: String!): Boolean! - startWinningsProcess(input: StartWinningsProcessInput!): StepFunctionsExecution! - unregisterDevice(device: UnregisterDeviceInput!): Boolean! - updateBigWinningTask(bigWinningTask: UpdateBigWinningTaskInput!): BigWinningTask! - updateCancelOrderTask(input: UpdateCancelOrderTaskInput!): CancelOrderTask! - updateLocationGame(locationGame: UpdateLocationGameInput!): LocationGame! - updatePool(pool: UpdatePoolInput!): Pool! - updatePricingRule(pricingRule: UpdatePricingRuleInput!): PricingRule! - updateProfile(profile: UpdateProfileInput): User! - updateRecurringOrder(recurringOrder: UpdateRecurringOrderInput!): RecurringOrder! - updateRegionGame(regionGame: UpdateRegionGameInput!): RegionGame! - updateRegionGameDraw(regionGameDraw: UpdateRegionGameDrawInput!): RegionGameDraw! - validateBigWinningNotificationTask(id: ID!): BigWinningNotificationTask! -} - -union PostPasswordlessStartResponse = UnspecifiedHttpResponse | PostPasswordlessStartOK | PostPasswordlessStartBadRequest | PostPasswordlessStartNoAuthProvided | PostPasswordlessStartUserNotFound | PostPasswordlessStartInternalError - -type UnspecifiedHttpResponse { - statusCode: Int! -} - -type PostPasswordlessStartOK { - code: String -} - -type PostPasswordlessStartBadRequest { - message: String -} - -type PostPasswordlessStartNoAuthProvided { - message: String -} - -type PostPasswordlessStartUserNotFound { - message: String -} - -type PostPasswordlessStartInternalError { - message: String -} - -input postPasswordlessStartInput { - applicationId: String! - loginId: String! -} - -union PostPasswordlessLoginResponse = UnspecifiedHttpResponse | PostPasswordlessLoginOK | PostPasswordlessLoginNotRegisteredForApp | PostPasswordlessLoginPasswordChangeRequested | PostPasswordlessLoginEmailNotVerified | PostPasswordlessLoginRegistrationNotVerified | PostPasswordlessLoginTwoFactorEnabled | PostPasswordlessLoginBadRequest | PostPasswordlessLoginInternalError - -type PostPasswordlessLoginOK { - refreshToken: String - token: String - user: User -} - -type NexusUser { - username: String - verified: Boolean - firstName: String - lastName: String - email: String - mobilePhone: String - timezone: String -} - -type PostPasswordlessLoginNotRegisteredForApp { - message: String -} - -type PostPasswordlessLoginPasswordChangeRequested { - changePasswordReason: String -} - -type PostPasswordlessLoginEmailNotVerified { - message: String -} - -type PostPasswordlessLoginRegistrationNotVerified { - message: String -} - -type PostPasswordlessLoginTwoFactorEnabled { - twoFactorId: String -} - -type PostPasswordlessLoginBadRequest { - message: String -} - -type PostPasswordlessLoginInternalError { - message: String -} - -input postPasswordlessLoginInput { - code: String! - ipAddress: String - metaData: MetaDataInput -} - -input MetaDataInput { - device: DeviceInput -} - -input DeviceInput { - name: String -} - -union PostJwtRefreshResponse = UnspecifiedHttpResponse | PostJwtRefreshOK | PostJwtRefreshBadRequest | PostJwtRefreshNoAuthProvided | PostJwtRefreshTokenNotFound | PostJwtRefreshInternalError - -type PostJwtRefreshOK { - refreshToken: String - token: String -} - -type PostJwtRefreshBadRequest { - message: String -} - -type PostJwtRefreshNoAuthProvided { - message: String -} - -type PostJwtRefreshTokenNotFound { - message: String -} - -type PostJwtRefreshInternalError { - message: String -} - -input postJwtRefreshInput { - refreshToken: String - token: String -} - -scalar AWSDate - -scalar AWSDateTime - -scalar AWSJSON - -scalar AWSTime - -scalar AWSEmail - -type AggTicket { - archived: Boolean! - draw: RegionGameDraw! - drawDate: AWSDate! - game: RegionGame! - id: ID! - regionGameId: String! - tickets: [Ticket!]! - userId: String! -} - -type AggTicketsResult { - items: [AggTicket!]! - nextToken: String -} - -type BigWinningNotificationTask { - drawDate: AWSDate! - id: ID! - regionGameId: String! - status: BigWinningTaskStatus! -} - -type BigWinningNotificationTasksResult { - items: [BigWinningNotificationTask!] - nextToken: String -} - -type BigWinningTask { - drawDate: AWSDate! - id: ID! - regionGameId: String! - status: BigWinningTaskStatus! -} - -type BigWinningTasksResult { - items: [BigWinningTask!] - nextToken: String -} - -type CancelOrderTask { - createdAt: AWSDateTime! - id: ID! - orderId: String! - status: CancelOrderTaskStatus! - userId: String! -} - -type CancelOrderTasksResult { - items: [CancelOrderTask!] - nextToken: String -} - -type Cart { - id: ID! - items: [CartItem!]! - serviceFee: Price! - total: Price! - userId: String! -} - -type CartItem { - drawDate: AWSDate! - fractional: Boolean! - play: Play! - price: Price! - quantity: Int! - regionGameId: String! -} - -type Currency { - code: String! -} - -type Device { - deviceId: ID! - provider: PushNotificationProvider! - token: String! -} - -type DrawResults { - prizes: AWSJSON - result: AWSJSON -} - -type FreeTicket { - drawDate: AWSDate! - generatedTicketId: String - id: ID! - regionGameId: String! - status: String! -} - -type FreeTicketsResult { - items: [FreeTicket!]! - nextToken: String -} - -type GameSchemas { - play: AWSJSON - prizes: AWSJSON - result: AWSJSON -} - -type Ledger { - balance: Price - id: ID! - transactions: [LedgerTransaction!]! - type: LedgerType -} - -type LedgerTransaction { - amount: Price! - createdAt: AWSDateTime! - description: String - id: ID! - ledgerId: String! - reference: String! - relatedTransactionId: String! -} - -type LedgerTransactionsResult { - items: [LedgerTransaction!]! - nextToken: String -} - -type LedgerTransferResponse { - amount: Price! - description: String - destinationLedgerId: String! - destinationTransactionId: String! - reference: String! - sourceLedgerId: String! - sourceTransactionId: String! -} - -type LedgersResult { - items: [Ledger!]! - nextToken: String -} - -type LocationGame { - enabled: Boolean! - fractions: Int - game: RegionGame! - id: ID! -} - -type LocationGamesResult { - items: [LocationGame!]! - nextToken: String -} - -type Order { - createdAt: AWSDateTime - fulfilledAt: AWSDateTime - id: ID! - isCanceled: Boolean! - items: [OrderItem!]! - locationId: String - refundAmount: Price - refundDestination: RefundDestinationEnum - serviceFee: Price! - status: OrderStatus! - submittedAt: AWSDateTime - total: Price! -} - -type OrderItem { - cancelAction: ActionEnum - fractional: Boolean! - id: ID! - play: Play! - price: Price! - quantity: Int! - regionGameId: String! - ticketId: String -} - -type OrdersResult { - items: [Order!]! - nextToken: String -} - -type Play { - options: AWSJSON - pick: [String!]! -} - -type Pool { - id: ID! - name: String! - userCount: Int! -} - -type PoolInvite { - status: PoolInviteStatus! - user: User! - userId: String! -} - -type PoolInvitesResult { - items: [PoolInvite!]! - nextToken: String -} - -type PoolUser { - joinedAt: AWSDateTime! - user: User! -} - -type PoolUsersResult { - items: [PoolUser!]! - nextToken: String -} - -type PoolsResult { - items: [Pool!]! - nextToken: String -} - -type PreNotifications { - email: Boolean - push: Boolean -} - -type Price { - amount: Float! - currency: Currency! -} - -type PricingRule { - actor: String - id: String! - latest: Int - rules: AWSJSON! - type: PricingRuleType! - version: Int! -} - -type PricingRulesResult { - items: [PricingRule!]! - nextToken: String -} - -type Query { - aggTicket(id: ID!): AggTicket! - aggTickets(filters: AggTicketsFilters, pagination: Pagination): AggTicketsResult! - bigWinningNotificationTask(id: ID!): BigWinningNotificationTask! - bigWinningNotificationTasks(filters: BigWinningNotificationTasksFilters!, pagination: Pagination): BigWinningNotificationTasksResult! - bigWinningTask(id: ID): BigWinningTask! - bigWinningTasks(filters: BigWinningsTaskFilters!, pagination: Pagination): BigWinningTasksResult! - cancelOrderTask(id: ID!): CancelOrderTask! - cancelOrderTasks(filters: CancelOrderTasksFilters!, pagination: Pagination): CancelOrderTasksResult! - cart(userId: ID): Cart! - freeTicket(id: ID!): FreeTicket! - freeTickets(filters: FreeTicketsFilters!, pagination: Pagination): FreeTicketsResult! - ledger(id: ID!): Ledger! - ledgerTransaction(ledgerId: ID!, transactionId: String!): LedgerTransaction - ledgerTransactions(filters: LedgerTransactionsFilters, ledgerId: ID!, pagination: Pagination): LedgerTransactionsResult! - ledgers: LedgersResult! - locationGame(id: ID!): LocationGame! - locationGames(filters: LocationGamesFilters!, pagination: Pagination): LocationGamesResult! - order(id: ID!): Order! - orders(filters: OrderFilters, pagination: Pagination): OrdersResult! - pool(id: ID!): Pool - poolInvites(id: ID!, pagination: Pagination): PoolInvitesResult! - poolUsers(id: ID!, pagination: Pagination): PoolUsersResult! - pools(pagination: Pagination): PoolsResult! - pricingRule(id: ID!): PricingRule - pricingRules(pagination: Pagination, type: ID!): PricingRulesResult! - profile: User! - quoteRegionGame(fractional: Boolean!, play: AWSJSON!, regionGameId: ID!): Price! - recurringOrder(id: ID!): RecurringOrder! - recurringOrders(pagination: Pagination): RecurringOrdersResult! - regionGame(id: ID!): RegionGame! - regionGameDraw(id: ID!): RegionGameDraw! - regionGameDraws(filters: RegionGameDrawsFilters!, pagination: Pagination): RegionGameDrawsResult! - regionGames(filters: RegionGamesFilters!, pagination: Pagination): RegionGamesResult! - task(id: ID): Task! - tasks(filters: TaskFilters): TasksResult! - ticket(id: ID!): Ticket! - tickets(filters: TicketsFilters, pagination: Pagination): TicketsResult! -} - -type RecurringOrder { - enabled: Boolean! - expectedPrice: Price! - fractional: Boolean! - id: ID! - locationId: String! - play: Play! - regionGameId: String! -} - -type RecurringOrdersResult { - items: [RecurringOrder!]! - nextToken: String -} - -type RegionGame { - autoPayoutLimit: Price - closingTime: Int! - currency: String! - drawTime: AWSTime! - draws: [RegionGameDraw!] - gameId: String! - id: ID! - lastDrawDate: AWSDate - lastDrawResult: String - name: String! - nextDrawDate: AWSDate - nextDrawPrize: Float - regionId: String! - regionName: String! - resultUpdatedAt: AWSDateTime - schemas: GameSchemas - timeZone: String! -} - -type RegionGameDraw { - closingDateTime: AWSDateTime - date: AWSDate! - id: ID! - parsedResult: DrawResults - prize: Float - regionGameId: String! - result: String - resultUpdatedAt: AWSDateTime - verifiedResult: DrawResults -} - -type RegionGameDrawsResult { - items: [RegionGameDraw!] - nextToken: String -} - -type RegionGamesResult { - items: [RegionGame!] - nextToken: String -} - -type StepFunctionsExecution { - executionArn: String! - startDate: Float! -} - -type Task { - execution: String - id: String! - input: AWSJSON - output: AWSJSON - process: TaskProcess! - state: TaskState! - status: TaskStatus! - statusReason: String - statusUpdatedAt: AWSDateTime - token: String -} - -type TasksResult { - items: [Task!] - nextToken: String -} - -type Ticket { - drawDate: AWSDate! - fraction: Int - id: ID! - locationId: String - options: AWSJSON - pick: AWSJSON! - poolId: String - regionGameId: String! - totalFractions: Int - totalWinnings: Price - type: String! - winnings: Price -} - -type TicketsResult { - items: [Ticket!]! - nextToken: String -} - -type User { - email: AWSEmail! - id: ID! - name: String! - preferences: UserPreferences! - updatedAt: AWSDateTime! -} - -type UserPreferences { - notifications: PreNotifications! -} - -enum ActionEnum { - Keep - Void -} - -enum BigWinningNotificationTaskStatus { - Complete - Pending -} - -enum BigWinningTaskStatus { - Complete - Pending -} - -enum CancelOrderTaskStatus { - Complete - Pending -} - -enum FreeTicketStatus { - Complete - Pending -} - -enum LedgerType { - Balance - Cash - Credits - Winnings -} - -enum OrderStatus { - Canceled - Draft - Fulfilled - Paid - PaymentFailed - PendingPayment -} - -enum PoolInviteStatus { - Accepted - Pending - Rejected -} - -enum PricingRuleType { - CART - GAME -} - -enum PushNotificationProvider { - FCM -} - -enum RefundDestinationEnum { - Balance - Credits - Exact - PaymentMethod -} - -enum TaskProcess { - Winnings -} - -enum TaskState { - AddPaymentMethod - BigWinner - CalculateWinnings - FulfillOrder - IssueWinnings - PreCalculateWinnings - PreIssueWinnings - PreVerifyResults - ProcessPayment - SendReceipt - SendResults - VerifyResults -} - -enum TaskStatus { - Complete - Failed - Pending -} - -input AddCartItemInput { - drawDate: AWSDate! - fractional: Boolean! - play: PlayInput - quantity: Int! - regionGameId: String! -} - -input AggTicketsFilters { - archived: Boolean - fromDate: AWSDate - regionGameId: String - toDate: AWSDate -} - -input BigWinningNotificationTasksFilters { - regionGameDrawId: String! - status: BigWinningNotificationTaskStatus -} - -input BigWinningsTaskFilters { - regionGameDrawId: String! - status: BigWinningTaskStatus -} - -input CancelItemsInput { - action: ActionEnum! - id: ID! -} - -input CancelOrderInput { - action: ActionEnum! - items: [CancelItemsInput!] - orderId: ID! - refundAmount: PriceInput - refundDestination: RefundDestinationEnum -} - -input CancelOrderTasksFilters { - fromDate: AWSDateTime - status: CancelOrderTaskStatus! - toDate: AWSDateTime - userId: String -} - -input CreateCancelOrderTaskInput { - orderId: String! -} - -input CreateLocationGameInput { - enabled: Boolean! - fractions: Int - gameId: String! - locationId: String! - regionId: String! -} - -input CreatePoolInput { - name: String! -} - -input CreateRecurringOrderInput { - fractional: Boolean! - play: PlayInput! - regionGameId: String! -} - -input CreateRegionGameDrawInput { - closingDateTime: AWSDateTime - date: AWSDate! - regionGameId: String! - result: String - verifiedResult: RegionGameDrawResultInput -} - -input CreateRegionGameInput { - autoPayoutLimit: PriceInput - closingTime: Int! - currency: String! - drawTime: AWSTime! - gameId: ID! - lastDrawDate: AWSDate - lastDrawResult: String - name: String! - nextDrawDate: AWSDate - nextDrawPrize: Float - prizes: AWSJSON - regionId: ID! - regionName: String! - resultUpdatedAt: AWSDateTime - timeZone: String! -} - -input CurrencyInput { - code: String! -} - -input FreeTicketsFilters { - regionGameDrawId: String! - status: FreeTicketStatus -} - -input FulfilledItem { - id: ID! - ticketId: String -} - -input GenerateFreeTicketInput { - drawDate: AWSDate! - id: String! - play: PlayInput! -} - -input LedgerTransactionsFilters { - fromDate: AWSDateTime - toDate: AWSDateTime -} - -input LocationGamesFilters { - locationId: String! -} - -input MarkTaskCompleteInput { - id: ID! -} - -input MarkTaskFailedInput { - id: ID! - reason: String -} - -input OrderFilters { - fromDate: AWSDateTime - status: OrderStatus - toDate: AWSDateTime - userId: String -} - -input Pagination { - limit: Int - nextToken: String -} - -input PlayInput { - options: AWSJSON - pick: [String!]! -} - -input PreNotificationsInput { - email: Boolean - push: Boolean -} - -input PriceInput { - amount: Float! - currency: CurrencyInput! -} - -input RegionGameDrawResultInput { - prizes: AWSJSON! - result: AWSJSON! -} - -input RegionGameDrawsFilters { - regionGameId: String! -} - -input RegionGamesFilters { - regionId: String! -} - -input RegisterDeviceInput { - deviceId: ID! - provider: PushNotificationProvider! - token: String! -} - -input StartWinningsProcessInput { - date: String! - regionGameId: String! -} - -input TaskFilters { - process: TaskProcess - state: TaskState - status: TaskStatus -} - -input TicketsFilters { - fromDate: AWSDate - regionGameId: String - toDate: AWSDate -} - -input TransferOptions { - idempotencyKey: String -} - -input TransferRequest { - amount: PriceInput! - description: String - destinationLedgerId: String! - reference: String! - sourceLedgerId: String! -} - -input UnregisterDeviceInput { - deviceId: ID! - provider: PushNotificationProvider! -} - -input UpdateBigWinningTaskInput { - id: ID! - status: BigWinningTaskStatus! -} - -input UpdateCancelOrderTaskInput { - id: ID! - status: CancelOrderTaskStatus! -} - -input UpdateLocationGameInput { - enabled: Boolean! - fractions: Int - id: ID! - regionId: String! -} - -input UpdatePoolInput { - id: ID! - name: String -} - -input UpdatePricingRuleInput { - latest: Int! - rules: AWSJSON! - type: PricingRuleType! -} - -input UpdateProfileInput { - email: AWSEmail - name: String - preferences: UserPreferencesInput -} - -input UpdateRecurringOrderInput { - enabled: Boolean! - fractional: Boolean! - id: ID! - play: PlayInput! - regionGameId: String! -} - -input UpdateRegionGameDrawInput { - closingDateTime: AWSDateTime - id: ID! - result: String - verifiedResult: RegionGameDrawResultInput -} - -input UpdateRegionGameInput { - autoPayoutLimit: PriceInput - closingTime: Int - currency: String - drawTime: AWSTime - id: ID! - lastDrawDate: AWSDate - lastDrawResult: String - name: String - nextDrawDate: AWSDate - nextDrawPrize: Float - prizes: AWSJSON - regionName: String - resultUpdatedAt: AWSDateTime - timeZone: String -} - -input UserPreferencesInput { - notifications: PreNotificationsInput! -}` diff --git a/pkg/astnormalization/variables_unused_deletion.go b/pkg/astnormalization/variables_unused_deletion.go deleted file mode 100644 index 872b8f68a..000000000 --- a/pkg/astnormalization/variables_unused_deletion.go +++ /dev/null @@ -1,93 +0,0 @@ -package astnormalization - -import ( - "bytes" - - "github.com/buger/jsonparser" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func deleteUnusedVariables(walker *astvisitor.Walker) *deleteUnusedVariablesVisitor { - visitor := &deleteUnusedVariablesVisitor{ - Walker: walker, - } - visitor.Walker.RegisterEnterDocumentVisitor(visitor) - visitor.Walker.RegisterOperationDefinitionVisitor(visitor) - visitor.Walker.RegisterEnterVariableDefinitionVisitor(visitor) - visitor.Walker.RegisterEnterArgumentVisitor(visitor) - return visitor -} - -type deleteUnusedVariablesVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - definedVariables []int - operationName []byte - skip bool -} - -func (d *deleteUnusedVariablesVisitor) LeaveOperationDefinition(ref int) { - for _, variable := range d.definedVariables { - variableName := d.operation.VariableDefinitionNameString(variable) - for i, variableDefinitionRef := range d.operation.OperationDefinitions[ref].VariableDefinitions.Refs { - if variable == variableDefinitionRef { - d.operation.OperationDefinitions[ref].VariableDefinitions.Refs = append(d.operation.OperationDefinitions[ref].VariableDefinitions.Refs[:i], d.operation.OperationDefinitions[ref].VariableDefinitions.Refs[i+1:]...) - d.operation.Input.Variables = jsonparser.Delete(d.operation.Input.Variables, variableName) - d.operation.OperationDefinitions[ref].HasVariableDefinitions = len(d.operation.OperationDefinitions[ref].VariableDefinitions.Refs) != 0 - } - } - - } - d.skip = true -} - -func (d *deleteUnusedVariablesVisitor) removeDefinedVariableWithName(name []byte) { - for i, variable := range d.definedVariables { - definedVariableNameBytes := d.operation.VariableDefinitionNameBytes(variable) - if bytes.Equal(name, definedVariableNameBytes) { - d.definedVariables = append(d.definedVariables[:i], d.definedVariables[i+1:]...) - d.removeDefinedVariableWithName(name) - return - } - } -} - -func (d *deleteUnusedVariablesVisitor) traverseValue(value ast.Value) { - switch value.Kind { - case ast.ValueKindVariable: - d.removeDefinedVariableWithName(d.operation.VariableValueNameBytes(value.Ref)) - case ast.ValueKindList: - for _, ref := range d.operation.ListValues[value.Ref].Refs { - d.traverseValue(d.operation.Value(ref)) - } - case ast.ValueKindObject: - for _, ref := range d.operation.ObjectValues[value.Ref].Refs { - d.traverseValue(d.operation.ObjectField(ref).Value) - } - } -} - -func (d *deleteUnusedVariablesVisitor) EnterArgument(ref int) { - if d.skip { - return - } - d.traverseValue(d.operation.Arguments[ref].Value) -} - -func (d *deleteUnusedVariablesVisitor) EnterVariableDefinition(ref int) { - if d.skip { - return - } - d.definedVariables = append(d.definedVariables, ref) -} - -func (d *deleteUnusedVariablesVisitor) EnterOperationDefinition(ref int) { - d.definedVariables = d.definedVariables[:0] - d.skip = false -} - -func (d *deleteUnusedVariablesVisitor) EnterDocument(operation, definition *ast.Document) { - d.operation, d.definition = operation, definition -} diff --git a/pkg/astnormalization/variables_unused_deletion_test.go b/pkg/astnormalization/variables_unused_deletion_test.go deleted file mode 100644 index 11c775d47..000000000 --- a/pkg/astnormalization/variables_unused_deletion_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package astnormalization - -import ( - "testing" -) - -func TestUnusedVariableDeletion(t *testing.T) { - t.Run("delete unused variables", func(t *testing.T) { - runWithDeleteUnusedVariables(t, deleteUnusedVariables, variablesExtractionDefinition, ` - mutation HttpBinPost($a: HttpBinPostInput $b: String){ - httpBinPost(input: $a){ - headers { - userAgent - } - data { - foo - } - } - }`, "HttpBinPost", ` - mutation HttpBinPost($a: HttpBinPostInput){ - httpBinPost(input: $a){ - headers { - userAgent - } - data { - foo - } - } - }`, `{"a":{"foo":"bar"},"b":"bat"}`, `{"a":{"foo":"bar"}}`) - }) -} diff --git a/pkg/astparser/errors.go b/pkg/astparser/errors.go deleted file mode 100644 index f4d9b0469..000000000 --- a/pkg/astparser/errors.go +++ /dev/null @@ -1,53 +0,0 @@ -package astparser - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/identkeyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type origin struct { - file string - line int - funcName string -} - -// ErrUnexpectedToken is a custom error object containing all necessary information to properly render an unexpected token error -type ErrUnexpectedToken struct { - keyword keyword.Keyword - expected []keyword.Keyword - position position.Position - literal string - origins []origin -} - -func (e ErrUnexpectedToken) Error() string { - - origins := "" - for _, origin := range e.origins { - origins = origins + fmt.Sprintf("\n\t\t%s:%d\n\t\t%s", origin.file, origin.line, origin.funcName) - } - - return fmt.Sprintf("unexpected token - keyword: '%s' literal: '%s' - expected: '%s' position: '%s'%s", e.keyword, e.literal, e.expected, e.position, origins) -} - -// ErrUnexpectedIdentKey is a custom error object to properly render an unexpected ident key error -type ErrUnexpectedIdentKey struct { - keyword identkeyword.IdentKeyword - expected []identkeyword.IdentKeyword - position position.Position - literal string - origins []origin -} - -func (e ErrUnexpectedIdentKey) Error() string { - - origins := "" - for _, origin := range e.origins { - origins = origins + fmt.Sprintf("\n\t\t%s:%d\n\t\t%s", origin.file, origin.line, origin.funcName) - } - - return fmt.Sprintf("unexpected ident - keyword: '%s' literal: '%s' - expected: '%s' position: '%s'%s", e.keyword, e.literal, e.expected, e.position, origins) -} diff --git a/pkg/astparser/parser.go b/pkg/astparser/parser.go deleted file mode 100644 index 0847a97fa..000000000 --- a/pkg/astparser/parser.go +++ /dev/null @@ -1,1781 +0,0 @@ -// Package astparser is used to turn raw GraphQL documents into an AST. -package astparser - -import ( - "fmt" - "runtime" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphqlerrors" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/identkeyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/token" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// ParseGraphqlDocumentString takes a raw GraphQL document in string format and parses it into an AST. -// This function creates a new parser as well as a new AST for every call. -// Therefore you shouldn't use this function in a hot path. -// Instead create a parser as well as AST objects and re-use them. -func ParseGraphqlDocumentString(input string) (ast.Document, operationreport.Report) { - return ParseGraphqlDocumentBytes([]byte(input)) -} - -// ParseGraphqlDocumentBytes takes a raw GraphQL document in byte slice format and parses it into an AST. -// This function creates a new parser as well as a new AST for every call. -// Therefore you shouldn't use this function in a hot path. -// Instead create a parser as well as AST objects and re-use them. -func ParseGraphqlDocumentBytes(input []byte) (ast.Document, operationreport.Report) { - parser := NewParser() - doc := *ast.NewDocument() - doc.Input.ResetInputBytes(input) - report := operationreport.Report{} - parser.Parse(&doc, &report) - return doc, report -} - -// Parser takes a raw input and turns it into an AST -// use NewParser() to create a parser -// Don't create new parsers in the hot path, re-use them. -type Parser struct { - document *ast.Document - report *operationreport.Report - tokenizer *Tokenizer - shouldIndex bool - reportInternalErrors bool -} - -// NewParser returns a new parser with all values properly initialized -func NewParser() *Parser { - return &Parser{ - tokenizer: NewTokenizer(), - shouldIndex: true, - reportInternalErrors: false, - } -} - -// PrepareImport prepares the Parser for importing new Nodes into an AST without directly parsing the content -func (p *Parser) PrepareImport(document *ast.Document, report *operationreport.Report) { - p.document = document - p.report = report - p.tokenize() -} - -// Parse parses all input in a Document.Input into the Document -func (p *Parser) Parse(document *ast.Document, report *operationreport.Report) { - p.document = document - p.report = report - p.tokenize() - p.parse() -} - -func (p *Parser) tokenize() { - p.tokenizer.Tokenize(&p.document.Input) -} - -func (p *Parser) parse() { - for { - key, literalReference := p.peekLiteral() - - switch key { - case keyword.EOF: - p.read() - return - case keyword.LBRACE: - p.parseOperationDefinition() - case keyword.STRING, keyword.BLOCKSTRING: - p.parseRootDescription() - case keyword.IDENT: - keyIdent := p.identKeywordSliceRef(literalReference) - switch keyIdent { - case identkeyword.ENUM: - p.parseEnumTypeDefinition(nil) - case identkeyword.TYPE: - p.parseObjectTypeDefinition(nil) - case identkeyword.UNION: - p.parseUnionTypeDefinition(nil) - case identkeyword.QUERY, identkeyword.MUTATION, identkeyword.SUBSCRIPTION: - p.parseOperationDefinition() - case identkeyword.INPUT: - p.parseInputObjectTypeDefinition(nil) - case identkeyword.EXTEND: - p.parseExtension() - case identkeyword.SCHEMA: - p.parseSchemaDefinition() - case identkeyword.SCALAR: - p.parseScalarTypeDefinition(nil) - case identkeyword.FRAGMENT: - p.parseFragmentDefinition() - case identkeyword.INTERFACE: - p.parseInterfaceTypeDefinition(nil) - case identkeyword.DIRECTIVE: - p.parseDirectiveDefinition(nil) - default: - p.errUnexpectedIdentKey(p.read(), keyIdent, identkeyword.ENUM, identkeyword.TYPE, identkeyword.UNION, identkeyword.QUERY, identkeyword.INPUT, identkeyword.EXTEND, identkeyword.SCHEMA, identkeyword.SCALAR, identkeyword.FRAGMENT, identkeyword.INTERFACE, identkeyword.DIRECTIVE) - } - default: - p.errUnexpectedToken(p.read(), keyword.EOF, keyword.LBRACE, keyword.COMMENT, keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT) - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) identKeywordToken(token token.Token) identkeyword.IdentKeyword { - return identkeyword.KeywordFromLiteral(p.document.Input.ByteSlice(token.Literal)) -} - -func (p *Parser) identKeywordSliceRef(ref ast.ByteSliceReference) identkeyword.IdentKeyword { - return identkeyword.KeywordFromLiteral(p.document.Input.ByteSlice(ref)) -} - -func (p *Parser) errUnexpectedIdentKey(unexpected token.Token, unexpectedKey identkeyword.IdentKeyword, expectedKeywords ...identkeyword.IdentKeyword) { - - if p.report.HasErrors() { - return - } - - p.report.AddExternalError(operationreport.ExternalError{ - Message: fmt.Sprintf("unexpected literal - got: %s want one of: %v", unexpectedKey, expectedKeywords), - Locations: []graphqlerrors.Location{ - { - Line: unexpected.TextPosition.LineStart, - Column: unexpected.TextPosition.CharStart, - }, - }, - }) - - if !p.reportInternalErrors { - return - } - - origins := make([]origin, 3) - for i := range origins { - fpcs := make([]uintptr, 1) - callers := runtime.Callers(2+i, fpcs) - - if callers == 0 { - origins = origins[:i] - break - } - - fn := runtime.FuncForPC(fpcs[0]) - file, line := fn.FileLine(fpcs[0]) - - origins[i].file = file - origins[i].line = line - origins[i].funcName = fn.Name() - } - - p.report.AddInternalError(ErrUnexpectedIdentKey{ - keyword: unexpectedKey, - position: unexpected.TextPosition, - literal: p.document.Input.ByteSliceString(unexpected.Literal), - origins: origins, - expected: expectedKeywords, - }) -} - -func (p *Parser) errUnexpectedToken(unexpected token.Token, expectedKeywords ...keyword.Keyword) { - - if p.report.HasErrors() { - return - } - - p.report.AddExternalError(operationreport.ExternalError{ - Message: fmt.Sprintf("unexpected token - got: %s want one of: %v", unexpected.Keyword, expectedKeywords), - Locations: []graphqlerrors.Location{ - { - Line: unexpected.TextPosition.LineStart, - Column: unexpected.TextPosition.CharStart, - }, - }, - }) - - if !p.reportInternalErrors { - return - } - - origins := make([]origin, 3) - for i := range origins { - fpcs := make([]uintptr, 1) - callers := runtime.Callers(2+i, fpcs) - - if callers == 0 { - origins = origins[:i] - break - } - - fn := runtime.FuncForPC(fpcs[0]) - file, line := fn.FileLine(fpcs[0]) - - origins[i].file = file - origins[i].line = line - origins[i].funcName = fn.Name() - } - - p.report.AddInternalError(ErrUnexpectedToken{ - keyword: unexpected.Keyword, - position: unexpected.TextPosition, - literal: p.document.Input.ByteSliceString(unexpected.Literal), - origins: origins, - expected: expectedKeywords, - }) -} - -func (p *Parser) parseSchemaDefinition() { - - schemaLiteral := p.read() - - schemaDefinition := ast.SchemaDefinition{ - SchemaLiteral: schemaLiteral.TextPosition, - } - - if p.peekEquals(keyword.AT) { - schemaDefinition.Directives = p.parseDirectiveList() - schemaDefinition.HasDirectives = len(schemaDefinition.Directives.Refs) > 0 - } - - p.parseRootOperationTypeDefinitionList(&schemaDefinition.RootOperationTypeDefinitions) - - p.document.SchemaDefinitions = append(p.document.SchemaDefinitions, schemaDefinition) - - ref := len(p.document.SchemaDefinitions) - 1 - rootNode := ast.Node{ - Kind: ast.NodeKindSchemaDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(schemaLiteral.Literal, rootNode) - } - p.document.RootNodes = append(p.document.RootNodes, rootNode) -} - -func (p *Parser) parseRootOperationTypeDefinitionList(list *ast.RootOperationTypeDefinitionList) { - - curlyBracketOpen := p.mustRead(keyword.LBRACE) - - for { - next := p.peek() - switch next { - case keyword.RBRACE: - - curlyBracketClose := p.read() - list.LBrace = curlyBracketOpen.TextPosition - list.RBrace = curlyBracketClose.TextPosition - return - case keyword.IDENT: - - _, operationType := p.mustReadOneOf(identkeyword.QUERY, identkeyword.MUTATION, identkeyword.SUBSCRIPTION) - colon := p.mustRead(keyword.COLON) - namedType := p.mustRead(keyword.IDENT) - - rootOperationTypeDefinition := ast.RootOperationTypeDefinition{ - OperationType: p.operationTypeFromIdentKeyword(operationType), - Colon: colon.TextPosition, - NamedType: ast.Type{ - TypeKind: ast.TypeKindNamed, - Name: namedType.Literal, - OfType: ast.InvalidRef, - }, - } - - p.document.RootOperationTypeDefinitions = append(p.document.RootOperationTypeDefinitions, rootOperationTypeDefinition) - ref := len(p.document.RootOperationTypeDefinitions) - 1 - - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - - list.Refs = append(list.Refs, ref) - - if p.shouldIndex { - p.indexRootOperationTypeDefinition(rootOperationTypeDefinition) - } - - default: - p.errUnexpectedToken(p.read()) - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) indexRootOperationTypeDefinition(definition ast.RootOperationTypeDefinition) { - switch definition.OperationType { - case ast.OperationTypeQuery: - p.document.Index.QueryTypeName = p.document.Input.ByteSlice(definition.NamedType.Name) - case ast.OperationTypeMutation: - p.document.Index.MutationTypeName = p.document.Input.ByteSlice(definition.NamedType.Name) - case ast.OperationTypeSubscription: - p.document.Index.SubscriptionTypeName = p.document.Input.ByteSlice(definition.NamedType.Name) - } -} - -func (p *Parser) operationTypeFromIdentKeyword(key identkeyword.IdentKeyword) ast.OperationType { - switch key { - case identkeyword.QUERY: - return ast.OperationTypeQuery - case identkeyword.MUTATION: - return ast.OperationTypeMutation - case identkeyword.SUBSCRIPTION: - return ast.OperationTypeSubscription - default: - return ast.OperationTypeUnknown - } -} - -func (p *Parser) parseDirectiveList() (list ast.DirectiveList) { - - for { - - if p.peek() != keyword.AT { - break - } - - at := p.read() - name := p.mustRead(keyword.IDENT) - - directive := ast.Directive{ - At: at.TextPosition, - Name: name.Literal, - } - - if p.peekEquals(keyword.LPAREN) { - directive.Arguments = p.parseArgumentList() - directive.HasArguments = len(directive.Arguments.Refs) > 0 - } - - p.document.Directives = append(p.document.Directives, directive) - ref := len(p.document.Directives) - 1 - - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - - list.Refs = append(list.Refs, ref) - - if p.report.HasErrors() { - return - } - } - - return -} - -func (p *Parser) parseArgumentList() (list ast.ArgumentList) { - - bracketOpen := p.mustRead(keyword.LPAREN) - -Loop: - for { - - next := p.peek() - switch next { - case keyword.IDENT: - default: - break Loop - } - - name := p.read() - colon := p.mustRead(keyword.COLON) - value := p.ParseValue() - - argument := ast.Argument{ - Name: name.Literal, - Colon: colon.TextPosition, - Value: value, - Position: name.TextPosition, - } - - p.document.Arguments = append(p.document.Arguments, argument) - ref := len(p.document.Arguments) - 1 - - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - - list.Refs = append(list.Refs, ref) - - if p.report.HasErrors() { - return - } - } - - bracketClose := p.mustRead(keyword.RPAREN) - - list.LPAREN = bracketOpen.TextPosition - list.RPAREN = bracketClose.TextPosition - - return -} - -func (p *Parser) ParseValue() (value ast.Value) { - - next, literal := p.peekLiteral() - - switch next { - case keyword.STRING, keyword.BLOCKSTRING: - value.Kind = ast.ValueKindString - value.Ref, value.Position = p.parseStringValue() - case keyword.IDENT: - key := p.identKeywordSliceRef(literal) - switch key { - case identkeyword.TRUE, identkeyword.FALSE: - value.Kind = ast.ValueKindBoolean - value.Ref, value.Position = p.parseBooleanValue() - case identkeyword.NULL: - value.Kind = ast.ValueKindNull - value.Position = p.read().TextPosition - default: - value.Kind = ast.ValueKindEnum - value.Ref, value.Position = p.parseEnumValue() - } - case keyword.DOLLAR: - value.Kind = ast.ValueKindVariable - value.Ref, value.Position = p.parseVariableValue() - case keyword.INTEGER: - value.Kind = ast.ValueKindInteger - value.Ref, value.Position = p.parseIntegerValue(nil) - case keyword.FLOAT: - value.Kind = ast.ValueKindFloat - value.Ref, value.Position = p.parseFloatValue(nil) - case keyword.SUB: - value = p.parseNegativeNumberValue() - case keyword.LBRACK: - value.Kind = ast.ValueKindList - value.Ref = p.parseValueList() - case keyword.LBRACE: - value.Kind = ast.ValueKindObject - value.Ref, value.Position = p.parseObjectValue() - default: - p.errUnexpectedToken(p.read()) - } - - return -} - -func (p *Parser) parseObjectValue() (ref int, pos position.Position) { - var objectValue ast.ObjectValue - objectValue.LBRACE = p.mustRead(keyword.LBRACE).TextPosition - - for { - next := p.peek() - switch next { - case keyword.RBRACE: - objectValue.RBRACE = p.read().TextPosition - return p.document.AddObjectValue(objectValue), objectValue.LBRACE - case keyword.IDENT: - ref := p.parseObjectField() - if cap(objectValue.Refs) == 0 { - objectValue.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - objectValue.Refs = append(objectValue.Refs, ref) - default: - p.errUnexpectedToken(p.read(), keyword.IDENT, keyword.RBRACE) - return ast.InvalidRef, position.Position{} - } - - if p.report.HasErrors() { - return ast.InvalidRef, position.Position{} - } - } -} - -func (p *Parser) parseObjectField() int { - nameToken := p.mustRead(keyword.IDENT) - - objectField := ast.ObjectField{ - Name: nameToken.Literal, - Colon: p.mustRead(keyword.COLON).TextPosition, - Value: p.ParseValue(), - Position: nameToken.TextPosition, - } - - return p.document.AddObjectField(objectField) -} - -func (p *Parser) parseValueList() int { - var list ast.ListValue - list.LBRACK = p.mustRead(keyword.LBRACK).TextPosition - - for { - next := p.peek() - switch next { - case keyword.RBRACK: - list.RBRACK = p.read().TextPosition - p.document.ListValues = append(p.document.ListValues, list) - return len(p.document.ListValues) - 1 - default: - value := p.ParseValue() - p.document.Values = append(p.document.Values, value) - ref := len(p.document.Values) - 1 - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - list.Refs = append(list.Refs, ref) - } - - if p.report.HasErrors() { - return ast.InvalidRef - } - } -} - -func (p *Parser) parseNegativeNumberValue() (value ast.Value) { - negativeSign := p.mustRead(keyword.SUB).TextPosition - switch p.peek() { - case keyword.INTEGER: - value.Kind = ast.ValueKindInteger - value.Ref, _ = p.parseIntegerValue(&negativeSign) - value.Position = negativeSign - case keyword.FLOAT: - value.Kind = ast.ValueKindFloat - value.Ref, _ = p.parseFloatValue(&negativeSign) - value.Position = negativeSign - default: - p.errUnexpectedToken(p.read(), keyword.INTEGER, keyword.FLOAT) - } - - return -} - -func (p *Parser) parseFloatValue(negativeSign *position.Position) (ref int, pos position.Position) { - - value := p.mustRead(keyword.FLOAT) - - if negativeSign != nil && negativeSign.CharEnd != value.TextPosition.CharStart { - p.errUnexpectedToken(value) - return ast.InvalidRef, position.Position{} - } - - floatValue := ast.FloatValue{ - Raw: value.Literal, - } - if negativeSign != nil { - floatValue.Negative = true - floatValue.NegativeSign = *negativeSign - } - - return p.document.AddFloatValue(floatValue), value.TextPosition -} - -func (p *Parser) parseIntegerValue(negativeSign *position.Position) (ref int, pos position.Position) { - - value := p.mustRead(keyword.INTEGER) - - if negativeSign != nil && negativeSign.CharEnd != value.TextPosition.CharStart { - p.errUnexpectedToken(value) - return ast.InvalidRef, position.Position{} - } - - intValue := ast.IntValue{ - Raw: value.Literal, - } - if negativeSign != nil { - intValue.Negative = true - intValue.NegativeSign = *negativeSign - } - - p.document.IntValues = append(p.document.IntValues, intValue) - return len(p.document.IntValues) - 1, value.TextPosition -} - -func (p *Parser) parseVariableValue() (ref int, pos position.Position) { - dollar := p.mustRead(keyword.DOLLAR) - var value token.Token - - next := p.peek() - switch next { - case keyword.IDENT: - value = p.read() - default: - p.errUnexpectedToken(p.read(), keyword.IDENT) - return ast.InvalidRef, position.Position{} - } - - if dollar.TextPosition.CharEnd != value.TextPosition.CharStart { - p.errUnexpectedToken(p.read(), keyword.IDENT) - return ast.InvalidRef, position.Position{} - } - - variable := ast.VariableValue{ - Dollar: dollar.TextPosition, - Name: value.Literal, - } - - p.document.VariableValues = append(p.document.VariableValues, variable) - return len(p.document.VariableValues) - 1, dollar.TextPosition -} - -func (p *Parser) parseBooleanValue() (ref int, pos position.Position) { - value := p.read() - identKey := p.identKeywordToken(value) - switch identKey { - case identkeyword.FALSE: - return 0, value.TextPosition - case identkeyword.TRUE: - return 1, value.TextPosition - default: - p.errUnexpectedIdentKey(value, identKey, identkeyword.TRUE, identkeyword.FALSE) - return ast.InvalidRef, position.Position{} - } -} - -func (p *Parser) parseEnumValue() (ref int, pos position.Position) { - value := p.mustRead(keyword.IDENT) - - enum := ast.EnumValue{ - Name: value.Literal, - } - - return p.document.AddEnumValue(enum), value.TextPosition -} - -func (p *Parser) parseStringValue() (ref int, pos position.Position) { - value := p.read() - if value.Keyword != keyword.STRING && value.Keyword != keyword.BLOCKSTRING { - p.errUnexpectedToken(value, keyword.STRING, keyword.BLOCKSTRING) - return ast.InvalidRef, position.Position{} - } - stringValue := ast.StringValue{ - Content: value.Literal, - BlockString: value.Keyword == keyword.BLOCKSTRING, - } - - return p.document.AddStringValue(stringValue), value.TextPosition -} - -func (p *Parser) parseObjectTypeDefinition(description *ast.Description) { - var objectTypeDefinition ast.ObjectTypeDefinition - if description != nil { - objectTypeDefinition.Description = *description - } - objectTypeDefinition.TypeLiteral = p.mustReadIdentKey(identkeyword.TYPE).TextPosition - objectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEqualsIdentKey(identkeyword.IMPLEMENTS) { - objectTypeDefinition.ImplementsInterfaces = p.parseImplementsInterfaces() - } - if p.peekEquals(keyword.AT) { - objectTypeDefinition.Directives = p.parseDirectiveList() - objectTypeDefinition.HasDirectives = len(objectTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - objectTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList() - objectTypeDefinition.HasFieldDefinitions = len(objectTypeDefinition.FieldsDefinition.Refs) > 0 - } - p.document.ObjectTypeDefinitions = append(p.document.ObjectTypeDefinitions, objectTypeDefinition) - ref := len(p.document.ObjectTypeDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindObjectTypeDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(objectTypeDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) indexNode(key ast.ByteSliceReference, value ast.Node) { - name := p.document.Input.ByteSlice(key) - p.document.Index.AddNodeBytes(name, value) -} - -func (p *Parser) parseRootDescription() { - - description := p.parseDescription() - - key, literal := p.peekLiteral() - if key != keyword.IDENT { - p.errUnexpectedToken(p.read(), keyword.IDENT) - return - } - - next := p.identKeywordSliceRef(literal) - - switch next { - case identkeyword.TYPE: - p.parseObjectTypeDefinition(&description) - case identkeyword.INPUT: - p.parseInputObjectTypeDefinition(&description) - case identkeyword.SCALAR: - p.parseScalarTypeDefinition(&description) - case identkeyword.INTERFACE: - p.parseInterfaceTypeDefinition(&description) - case identkeyword.UNION: - p.parseUnionTypeDefinition(&description) - case identkeyword.ENUM: - p.parseEnumTypeDefinition(&description) - case identkeyword.DIRECTIVE: - p.parseDirectiveDefinition(&description) - case identkeyword.EXTEND: - p.parseExtension() - default: - p.errUnexpectedIdentKey(p.read(), next, identkeyword.TYPE, identkeyword.INPUT, identkeyword.SCALAR, identkeyword.INTERFACE, identkeyword.UNION, identkeyword.ENUM, identkeyword.DIRECTIVE) - } -} - -func (p *Parser) parseImplementsInterfaces() (list ast.TypeList) { - - p.read() // implements - - acceptIdent := true - acceptAnd := true - - for { - next := p.peek() - switch next { - case keyword.AND: - if acceptAnd { - acceptAnd = false - acceptIdent = true - p.read() - } else { - p.errUnexpectedToken(p.read()) - return - } - case keyword.IDENT: - if acceptIdent { - acceptIdent = false - acceptAnd = true - name := p.read() - ref := p.document.AddNamedTypeWithPosition(name.Literal, name.TextPosition) - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - list.Refs = append(list.Refs, ref) - } else { - p.errUnexpectedToken(p.read()) - return - } - default: - if acceptIdent { - p.errUnexpectedToken(p.read()) - } - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseFieldDefinitionList() (list ast.FieldDefinitionList) { - - list.LBRACE = p.mustRead(keyword.LBRACE).TextPosition - - refsInitialized := false - - for { - - next := p.peek() - - switch next { - case keyword.RBRACE: - list.RBRACE = p.read().TextPosition - return - case keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT: - ref := p.parseFieldDefinition() - if !refsInitialized { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - refsInitialized = true - } - list.Refs = append(list.Refs, ref) - default: - p.errUnexpectedToken(p.read()) - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseFieldDefinition() int { - - var fieldDefinition ast.FieldDefinition - - name := p.peek() - switch name { - case keyword.STRING, keyword.BLOCKSTRING: - fieldDefinition.Description = p.parseDescription() - case keyword.IDENT: - break - default: - p.errUnexpectedToken(p.read()) - return ast.InvalidRef - } - - nameToken := p.read() - if nameToken.Keyword != keyword.IDENT { - p.errUnexpectedToken(nameToken, keyword.IDENT) - return ast.InvalidRef - } - - fieldDefinition.Name = nameToken.Literal - if p.peekEquals(keyword.LPAREN) { - fieldDefinition.ArgumentsDefinition = p.parseInputValueDefinitionList(keyword.RPAREN) - fieldDefinition.HasArgumentsDefinitions = len(fieldDefinition.ArgumentsDefinition.Refs) > 0 - } - fieldDefinition.Colon = p.mustRead(keyword.COLON).TextPosition - fieldDefinition.Type = p.ParseType() - if p.peek() == keyword.AT { - fieldDefinition.Directives = p.parseDirectiveList() - fieldDefinition.HasDirectives = len(fieldDefinition.Directives.Refs) > 0 - } - - p.document.FieldDefinitions = append(p.document.FieldDefinitions, fieldDefinition) - return len(p.document.FieldDefinitions) - 1 -} - -func (p *Parser) parseNamedType() (ref int) { - ident := p.mustRead(keyword.IDENT) - - return p.document.AddNamedTypeWithPosition(ident.Literal, ident.TextPosition) -} - -func (p *Parser) ParseType() (ref int) { - - first := p.peek() - - if first == keyword.IDENT { - tok := p.read() - ref = p.document.AddNamedTypeWithPosition(tok.Literal, tok.TextPosition) - } else if first == keyword.LBRACK { - - openList := p.read() - ofType := p.ParseType() - closeList := p.mustRead(keyword.RBRACK) - - ref = p.document.AddListTypeWithPosition(ofType, openList.TextPosition, closeList.TextPosition) - } else { - p.errUnexpectedToken(p.read(), keyword.IDENT, keyword.LBRACK) - return - } - - next := p.peek() - if next == keyword.BANG { - bangPosition := p.read().TextPosition - if p.peek() == keyword.BANG { - p.errUnexpectedToken(p.read()) - return - } - - ref = p.document.AddNonNullTypeWithBangPosition(ref, bangPosition) - } - - return -} - -func (p *Parser) parseDescription() ast.Description { - tok := p.read() - return ast.Description{ - IsDefined: true, - Content: tok.Literal, - Position: tok.TextPosition, - IsBlockString: tok.Keyword == keyword.BLOCKSTRING, - } -} - -func (p *Parser) parseInputValueDefinitionList(closingKeyword keyword.Keyword) (list ast.InputValueDefinitionList) { - - list.LPAREN = p.read().TextPosition - - for { - next := p.peek() - switch next { - case closingKeyword: - list.RPAREN = p.read().TextPosition - return - case keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT: - ref := p.parseInputValueDefinition() - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - list.Refs = append(list.Refs, ref) - default: - p.errUnexpectedToken(p.read()) - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseInputValueDefinition() int { - - var inputValueDefinition ast.InputValueDefinition - - name := p.peek() - switch name { - case keyword.STRING, keyword.BLOCKSTRING: - inputValueDefinition.Description = p.parseDescription() - case keyword.IDENT: - break - default: - p.errUnexpectedToken(p.read()) - return ast.InvalidRef - } - - inputValueDefinition.Name = p.read().Literal - inputValueDefinition.Colon = p.mustRead(keyword.COLON).TextPosition - inputValueDefinition.Type = p.ParseType() - if p.peekEquals(keyword.EQUALS) { - equals := p.read() - inputValueDefinition.DefaultValue.IsDefined = true - inputValueDefinition.DefaultValue.Equals = equals.TextPosition - inputValueDefinition.DefaultValue.Value = p.ParseValue() - } - if p.peekEquals(keyword.AT) { - inputValueDefinition.Directives = p.parseDirectiveList() - inputValueDefinition.HasDirectives = len(inputValueDefinition.Directives.Refs) > 0 - } - - p.document.InputValueDefinitions = append(p.document.InputValueDefinitions, inputValueDefinition) - return len(p.document.InputValueDefinitions) - 1 -} - -func (p *Parser) parseInputObjectTypeDefinition(description *ast.Description) { - var inputObjectTypeDefinition ast.InputObjectTypeDefinition - if description != nil { - inputObjectTypeDefinition.Description = *description - } - inputObjectTypeDefinition.InputLiteral = p.mustReadIdentKey(identkeyword.INPUT).TextPosition - inputObjectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - inputObjectTypeDefinition.Directives = p.parseDirectiveList() - inputObjectTypeDefinition.HasDirectives = len(inputObjectTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - inputObjectTypeDefinition.InputFieldsDefinition = p.parseInputValueDefinitionList(keyword.RBRACE) - inputObjectTypeDefinition.HasInputFieldsDefinition = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0 - } - p.document.InputObjectTypeDefinitions = append(p.document.InputObjectTypeDefinitions, inputObjectTypeDefinition) - ref := len(p.document.InputObjectTypeDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindInputObjectTypeDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(inputObjectTypeDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) parseScalarTypeDefinition(description *ast.Description) { - var scalarTypeDefinition ast.ScalarTypeDefinition - if description != nil { - scalarTypeDefinition.Description = *description - } - scalarTypeDefinition.ScalarLiteral = p.mustReadIdentKey(identkeyword.SCALAR).TextPosition - scalarTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - scalarTypeDefinition.Directives = p.parseDirectiveList() - scalarTypeDefinition.HasDirectives = len(scalarTypeDefinition.Directives.Refs) > 0 - } - p.document.ScalarTypeDefinitions = append(p.document.ScalarTypeDefinitions, scalarTypeDefinition) - ref := len(p.document.ScalarTypeDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindScalarTypeDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(scalarTypeDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) parseInterfaceTypeDefinition(description *ast.Description) { - var interfaceTypeDefinition ast.InterfaceTypeDefinition - if description != nil { - interfaceTypeDefinition.Description = *description - } - interfaceTypeDefinition.InterfaceLiteral = p.mustReadIdentKey(identkeyword.INTERFACE).TextPosition - interfaceTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEqualsIdentKey(identkeyword.IMPLEMENTS) { - interfaceTypeDefinition.ImplementsInterfaces = p.parseImplementsInterfaces() - } - if p.peekEquals(keyword.AT) { - interfaceTypeDefinition.Directives = p.parseDirectiveList() - interfaceTypeDefinition.HasDirectives = len(interfaceTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - interfaceTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList() - interfaceTypeDefinition.HasFieldDefinitions = len(interfaceTypeDefinition.FieldsDefinition.Refs) > 0 - } - p.document.InterfaceTypeDefinitions = append(p.document.InterfaceTypeDefinitions, interfaceTypeDefinition) - ref := len(p.document.InterfaceTypeDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindInterfaceTypeDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(interfaceTypeDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) parseUnionTypeDefinition(description *ast.Description) { - var unionTypeDefinition ast.UnionTypeDefinition - if description != nil { - unionTypeDefinition.Description = *description - } - unionTypeDefinition.UnionLiteral = p.mustReadIdentKey(identkeyword.UNION).TextPosition - unionTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - unionTypeDefinition.Directives = p.parseDirectiveList() - unionTypeDefinition.HasDirectives = len(unionTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.EQUALS) { - unionTypeDefinition.Equals = p.mustRead(keyword.EQUALS).TextPosition - unionTypeDefinition.UnionMemberTypes = p.parseUnionMemberTypes() - unionTypeDefinition.HasUnionMemberTypes = len(unionTypeDefinition.UnionMemberTypes.Refs) > 0 - } - p.document.UnionTypeDefinitions = append(p.document.UnionTypeDefinitions, unionTypeDefinition) - ref := len(p.document.UnionTypeDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindUnionTypeDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(unionTypeDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) parseUnionMemberTypes() (list ast.TypeList) { - - acceptPipe := true - acceptIdent := true - expectNext := true - - for { - next := p.peek() - switch next { - case keyword.PIPE: - if acceptPipe { - acceptPipe = false - acceptIdent = true - expectNext = true - p.read() - } else { - p.errUnexpectedToken(p.read()) - return - } - case keyword.IDENT: - if acceptIdent { - acceptPipe = true - acceptIdent = false - expectNext = false - - ident := p.read() - - ref := p.document.AddNamedTypeWithPosition(ident.Literal, ident.TextPosition) - - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - list.Refs = append(list.Refs, ref) - } else { - return - } - default: - if expectNext { - p.errUnexpectedToken(p.read()) - } - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseEnumTypeDefinition(description *ast.Description) { - var enumTypeDefinition ast.EnumTypeDefinition - if description != nil { - enumTypeDefinition.Description = *description - } - enumTypeDefinition.EnumLiteral = p.mustReadIdentKey(identkeyword.ENUM).TextPosition - enumTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - enumTypeDefinition.Directives = p.parseDirectiveList() - enumTypeDefinition.HasDirectives = len(enumTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - enumTypeDefinition.EnumValuesDefinition = p.parseEnumValueDefinitionList() - enumTypeDefinition.HasEnumValuesDefinition = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0 - } - p.document.EnumTypeDefinitions = append(p.document.EnumTypeDefinitions, enumTypeDefinition) - ref := len(p.document.EnumTypeDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindEnumTypeDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(enumTypeDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) parseEnumValueDefinitionList() (list ast.EnumValueDefinitionList) { - - list.LBRACE = p.mustRead(keyword.LBRACE).TextPosition - - for { - next := p.peek() - switch next { - case keyword.STRING, keyword.BLOCKSTRING, keyword.IDENT: - ref := p.parseEnumValueDefinition() - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - list.Refs = append(list.Refs, ref) - case keyword.RBRACE: - list.RBRACE = p.read().TextPosition - return - default: - p.errUnexpectedToken(p.read()) - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseEnumValueDefinition() int { - var enumValueDefinition ast.EnumValueDefinition - next := p.peek() - switch next { - case keyword.STRING, keyword.BLOCKSTRING: - enumValueDefinition.Description = p.parseDescription() - case keyword.IDENT: - break - default: - p.errUnexpectedToken(p.read()) - return ast.InvalidRef - } - - enumValueDefinition.EnumValue = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - enumValueDefinition.Directives = p.parseDirectiveList() - enumValueDefinition.HasDirectives = len(enumValueDefinition.Directives.Refs) > 0 - } - - p.document.EnumValueDefinitions = append(p.document.EnumValueDefinitions, enumValueDefinition) - return len(p.document.EnumValueDefinitions) - 1 -} - -func (p *Parser) parseDirectiveDefinition(description *ast.Description) { - var directiveDefinition ast.DirectiveDefinition - if description != nil { - directiveDefinition.Description = *description - } - directiveDefinition.DirectiveLiteral = p.mustReadIdentKey(identkeyword.DIRECTIVE).TextPosition - directiveDefinition.At = p.mustRead(keyword.AT).TextPosition - directiveDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.LPAREN) { - directiveDefinition.ArgumentsDefinition = p.parseInputValueDefinitionList(keyword.RPAREN) - directiveDefinition.HasArgumentsDefinitions = len(directiveDefinition.ArgumentsDefinition.Refs) > 0 - } - - if p.peekEqualsIdentKey(identkeyword.REPEATABLE) { - directiveDefinition.Repeatable.IsRepeatable = true - directiveDefinition.Repeatable.Position = p.mustReadIdentKey(identkeyword.REPEATABLE).TextPosition - } - - directiveDefinition.On = p.mustReadIdentKey(identkeyword.ON).TextPosition - p.parseDirectiveLocations(&directiveDefinition.DirectiveLocations) - p.document.DirectiveDefinitions = append(p.document.DirectiveDefinitions, directiveDefinition) - ref := len(p.document.DirectiveDefinitions) - 1 - node := ast.Node{ - Kind: ast.NodeKindDirectiveDefinition, - Ref: ref, - } - if p.shouldIndex { - p.indexNode(directiveDefinition.Name, node) - } - p.document.RootNodes = append(p.document.RootNodes, node) -} - -func (p *Parser) parseDirectiveLocations(locations *ast.DirectiveLocations) { - acceptPipe := true - acceptIdent := true - expectNext := true - for { - next := p.peek() - switch next { - case keyword.IDENT: - if acceptIdent { - acceptIdent = false - acceptPipe = true - expectNext = false - - ident := p.read() - raw := p.document.Input.ByteSlice(ident.Literal) - err := locations.SetFromRaw(raw) - if err != nil { - p.report.AddExternalError(operationreport.ExternalError{ - Message: fmt.Sprintf("invalid directive location: %s", unsafebytes.BytesToString(raw)), - Locations: []graphqlerrors.Location{ - { - Line: ident.TextPosition.LineStart, - Column: ident.TextPosition.CharStart, - }, - }, - }) - if p.reportInternalErrors { - p.report.AddInternalError(err) - } - return - } - - } else { - return - } - case keyword.PIPE: - if acceptPipe { - acceptPipe = false - acceptIdent = true - expectNext = true - p.read() - } else { - p.errUnexpectedToken(p.read()) - return - } - default: - if expectNext { - p.errUnexpectedToken(p.read()) - } - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseSelectionSet() (int, bool) { - - var set ast.SelectionSet - - set.SelectionRefs = p.document.Refs[p.document.NextRefIndex()][:0] - lbraceToken := p.mustRead(keyword.LBRACE) - set.LBrace = lbraceToken.TextPosition - - for { - switch p.peek() { - case keyword.RBRACE: - rbraceToken := p.read() - set.RBrace = rbraceToken.TextPosition - - if len(set.SelectionRefs) == 0 { - return 0, false - } - - p.document.SelectionSets = append(p.document.SelectionSets, set) - return len(p.document.SelectionSets) - 1, true - - case keyword.IDENT, keyword.SPREAD: - if cap(set.SelectionRefs) == 0 { - set.SelectionRefs = p.document.Refs[p.document.NextRefIndex()][:0] - } - ref := p.parseSelection() - set.SelectionRefs = append(set.SelectionRefs, ref) - default: - p.errUnexpectedToken(p.read(), keyword.RBRACE, keyword.IDENT, keyword.SPREAD) - } - - if p.report.HasErrors() { - return ast.InvalidRef, false - } - } -} - -func (p *Parser) parseSelection() int { - next := p.peek() - switch next { - case keyword.IDENT: - p.document.Selections = append(p.document.Selections, ast.Selection{ - Kind: ast.SelectionKindField, - Ref: p.parseField(), - }) - return len(p.document.Selections) - 1 - case keyword.SPREAD: - spreadToken := p.read() - return p.parseFragmentSelection(spreadToken.TextPosition) - default: - nextToken := p.read() - p.errUnexpectedToken(nextToken, keyword.IDENT, keyword.SPREAD) - return ast.InvalidRef - } -} - -func (p *Parser) parseFragmentSelection(spread position.Position) int { - - var selection ast.Selection - - next, literal := p.peekLiteral() - switch next { - case keyword.LBRACE, keyword.AT: - selection.Kind = ast.SelectionKindInlineFragment - selection.Ref = p.parseInlineFragment(spread) - case keyword.IDENT: - key := p.identKeywordSliceRef(literal) - switch key { - case identkeyword.ON: - selection.Kind = ast.SelectionKindInlineFragment - selection.Ref = p.parseInlineFragment(spread) - default: - selection.Kind = ast.SelectionKindFragmentSpread - selection.Ref = p.parseFragmentSpread(spread) - } - default: - nextToken := p.read() - p.errUnexpectedToken(nextToken, keyword.IDENT) - } - - p.document.Selections = append(p.document.Selections, selection) - return len(p.document.Selections) - 1 -} - -func (p *Parser) parseField() int { - - var field ast.Field - - firstToken := p.read() - if firstToken.Keyword != keyword.IDENT { - p.errUnexpectedToken(firstToken, keyword.IDENT) - } - - if p.peek() == keyword.COLON { - field.Alias.IsDefined = true - field.Alias.Name = firstToken.Literal - colonToken := p.read() - field.Alias.Colon = colonToken.TextPosition - nameToken := p.mustRead(keyword.IDENT) - field.Name = nameToken.Literal - } else { - field.Name = firstToken.Literal - } - field.Position = firstToken.TextPosition - - if p.peekEquals(keyword.LPAREN) { - field.Arguments = p.parseArgumentList() - field.HasArguments = len(field.Arguments.Refs) > 0 - } - if p.peekEquals(keyword.AT) { - field.Directives = p.parseDirectiveList() - field.HasDirectives = len(field.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - field.SelectionSet, field.HasSelections = p.parseSelectionSet() - } - - p.document.Fields = append(p.document.Fields, field) - return len(p.document.Fields) - 1 -} - -func (p *Parser) parseFragmentSpread(spread position.Position) int { - var fragmentSpread ast.FragmentSpread - fragmentSpread.Spread = spread - fragmentSpread.FragmentName = p.mustReadExceptIdentKey(identkeyword.ON).Literal - if p.peekEquals(keyword.AT) { - fragmentSpread.Directives = p.parseDirectiveList() - fragmentSpread.HasDirectives = len(fragmentSpread.Directives.Refs) > 0 - } - p.document.FragmentSpreads = append(p.document.FragmentSpreads, fragmentSpread) - return len(p.document.FragmentSpreads) - 1 -} - -func (p *Parser) parseInlineFragment(spread position.Position) int { - fragment := ast.InlineFragment{ - TypeCondition: ast.TypeCondition{ - Type: ast.InvalidRef, - }, - } - fragment.Spread = spread - if p.peekEqualsIdentKey(identkeyword.ON) { - fragment.TypeCondition = p.parseTypeCondition() - } - if p.peekEquals(keyword.AT) { - fragment.Directives = p.parseDirectiveList() - fragment.HasDirectives = len(fragment.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - fragment.SelectionSet, fragment.HasSelections = p.parseSelectionSet() - } - p.document.InlineFragments = append(p.document.InlineFragments, fragment) - return len(p.document.InlineFragments) - 1 -} - -func (p *Parser) parseTypeCondition() (typeCondition ast.TypeCondition) { - typeCondition.On = p.mustReadIdentKey(identkeyword.ON).TextPosition - typeCondition.Type = p.parseNamedType() - return -} - -func (p *Parser) parseOperationDefinition() { - - var operationDefinition ast.OperationDefinition - - next, literal := p.peekLiteral() - switch next { - case keyword.IDENT: - key := p.identKeywordSliceRef(literal) - switch key { - case identkeyword.QUERY: - operationDefinition.OperationTypeLiteral = p.read().TextPosition - operationDefinition.OperationType = ast.OperationTypeQuery - case identkeyword.MUTATION: - operationDefinition.OperationTypeLiteral = p.read().TextPosition - operationDefinition.OperationType = ast.OperationTypeMutation - case identkeyword.SUBSCRIPTION: - operationDefinition.OperationTypeLiteral = p.read().TextPosition - operationDefinition.OperationType = ast.OperationTypeSubscription - default: - p.errUnexpectedIdentKey(p.read(), key, identkeyword.QUERY, identkeyword.MUTATION, identkeyword.SUBSCRIPTION) - return - } - case keyword.LBRACE: - operationDefinition.OperationType = ast.OperationTypeQuery - operationDefinition.SelectionSet, operationDefinition.HasSelections = p.parseSelectionSet() - p.document.OperationDefinitions = append(p.document.OperationDefinitions, operationDefinition) - ref := len(p.document.OperationDefinitions) - 1 - rootNode := ast.Node{ - Kind: ast.NodeKindOperationDefinition, - Ref: ref, - } - p.document.RootNodes = append(p.document.RootNodes, rootNode) - return - default: - p.errUnexpectedToken(p.read(), keyword.IDENT, keyword.LBRACE) - return - } - - if p.peekEquals(keyword.IDENT) { - operationDefinition.Name = p.read().Literal - } - if p.peekEquals(keyword.LPAREN) { - operationDefinition.VariableDefinitions = p.parseVariableDefinitionList() - operationDefinition.HasVariableDefinitions = len(operationDefinition.VariableDefinitions.Refs) > 0 - } - if p.peekEquals(keyword.AT) { - operationDefinition.Directives = p.parseDirectiveList() - operationDefinition.HasDirectives = len(operationDefinition.Directives.Refs) > 0 - } - - operationDefinition.SelectionSet, operationDefinition.HasSelections = p.parseSelectionSet() - - p.document.OperationDefinitions = append(p.document.OperationDefinitions, operationDefinition) - ref := len(p.document.OperationDefinitions) - 1 - rootNode := ast.Node{ - Kind: ast.NodeKindOperationDefinition, - Ref: ref, - } - p.document.RootNodes = append(p.document.RootNodes, rootNode) -} - -func (p *Parser) parseVariableDefinitionList() (list ast.VariableDefinitionList) { - - list.LPAREN = p.mustRead(keyword.LPAREN).TextPosition - - for { - next := p.peek() - switch next { - case keyword.RPAREN: - list.RPAREN = p.read().TextPosition - return - case keyword.DOLLAR: - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - ref := p.parseVariableDefinition() - if cap(list.Refs) == 0 { - list.Refs = p.document.Refs[p.document.NextRefIndex()][:0] - } - list.Refs = append(list.Refs, ref) - default: - p.errUnexpectedToken(p.read(), keyword.RPAREN, keyword.DOLLAR) - return - } - - if p.report.HasErrors() { - return - } - } -} - -func (p *Parser) parseVariableDefinition() int { - - var variableDefinition ast.VariableDefinition - - variableDefinition.VariableValue.Kind = ast.ValueKindVariable - variableDefinition.VariableValue.Ref, variableDefinition.VariableValue.Position = p.parseVariableValue() - - variableDefinition.Colon = p.mustRead(keyword.COLON).TextPosition - variableDefinition.Type = p.ParseType() - if p.peekEquals(keyword.EQUALS) { - variableDefinition.DefaultValue = p.parseDefaultValue() - } - if p.peekEquals(keyword.AT) { - variableDefinition.Directives = p.parseDirectiveList() - variableDefinition.HasDirectives = len(variableDefinition.Directives.Refs) > 0 - } - p.document.VariableDefinitions = append(p.document.VariableDefinitions, variableDefinition) - return len(p.document.VariableDefinitions) - 1 -} - -func (p *Parser) parseDefaultValue() ast.DefaultValue { - equals := p.mustRead(keyword.EQUALS).TextPosition - value := p.ParseValue() - return ast.DefaultValue{ - IsDefined: true, - Equals: equals, - Value: value, - } -} - -func (p *Parser) parseFragmentDefinition() { - var fragmentDefinition ast.FragmentDefinition - fragmentDefinition.FragmentLiteral = p.mustReadIdentKey(identkeyword.FRAGMENT).TextPosition - fragmentDefinition.Name = p.mustRead(keyword.IDENT).Literal - fragmentDefinition.TypeCondition = p.parseTypeCondition() - if p.peekEquals(keyword.AT) { - fragmentDefinition.Directives = p.parseDirectiveList() - fragmentDefinition.HasDirectives = len(fragmentDefinition.Directives.Refs) > 0 - } - fragmentDefinition.SelectionSet, fragmentDefinition.HasSelections = p.parseSelectionSet() - p.document.FragmentDefinitions = append(p.document.FragmentDefinitions, fragmentDefinition) - - ref := len(p.document.FragmentDefinitions) - 1 - p.document.RootNodes = append(p.document.RootNodes, ast.Node{ - Kind: ast.NodeKindFragmentDefinition, - Ref: ref, - }) -} - -func (p *Parser) parseExtension() { - extend := p.mustReadIdentKey(identkeyword.EXTEND).TextPosition - next, literal := p.peekLiteral() - - if next != keyword.IDENT { - p.errUnexpectedToken(p.read(), keyword.IDENT) - return - } - - key := p.identKeywordSliceRef(literal) - - switch key { - case identkeyword.SCHEMA: - p.parseSchemaExtension(extend) - case identkeyword.TYPE: - p.parseObjectTypeExtension(extend) - case identkeyword.INTERFACE: - p.parseInterfaceTypeExtension(extend) - case identkeyword.SCALAR: - p.parseScalarTypeExtension(extend) - case identkeyword.UNION: - p.parseUnionTypeExtension(extend) - case identkeyword.ENUM: - p.parseEnumTypeExtension(extend) - case identkeyword.INPUT: - p.parseInputObjectTypeExtension(extend) - default: - p.errUnexpectedIdentKey(p.read(), key, identkeyword.SCHEMA, identkeyword.TYPE, identkeyword.INTERFACE, identkeyword.SCALAR, identkeyword.UNION, identkeyword.ENUM, identkeyword.INPUT, identkeyword.EXTEND) - } -} - -func (p *Parser) parseSchemaExtension(extend position.Position) { - schemaLiteral := p.read() - schemaDefinition := ast.SchemaDefinition{ - SchemaLiteral: schemaLiteral.TextPosition, - } - if p.peekEquals(keyword.AT) { - schemaDefinition.Directives = p.parseDirectiveList() - schemaDefinition.HasDirectives = len(schemaDefinition.Directives.Refs) > 0 - } - p.parseRootOperationTypeDefinitionList(&schemaDefinition.RootOperationTypeDefinitions) - - schemaExtension := ast.SchemaExtension{ - ExtendLiteral: extend, - SchemaDefinition: schemaDefinition, - } - p.document.SchemaExtensions = append(p.document.SchemaExtensions, schemaExtension) - ref := len(p.document.SchemaExtensions) - 1 - p.document.RootNodes = append(p.document.RootNodes, ast.Node{Ref: ref, Kind: ast.NodeKindSchemaExtension}) -} - -func (p *Parser) parseObjectTypeExtension(extend position.Position) { - var objectTypeDefinition ast.ObjectTypeDefinition - objectTypeDefinition.TypeLiteral = p.mustReadIdentKey(identkeyword.TYPE).TextPosition - objectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEqualsIdentKey(identkeyword.IMPLEMENTS) { - objectTypeDefinition.ImplementsInterfaces = p.parseImplementsInterfaces() - } - if p.peekEquals(keyword.AT) { - objectTypeDefinition.Directives = p.parseDirectiveList() - objectTypeDefinition.HasDirectives = len(objectTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - objectTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList() - objectTypeDefinition.HasFieldDefinitions = len(objectTypeDefinition.FieldsDefinition.Refs) > 0 - } - objectTypeExtension := ast.ObjectTypeExtension{ - ExtendLiteral: extend, - ObjectTypeDefinition: objectTypeDefinition, - } - p.document.ObjectTypeExtensions = append(p.document.ObjectTypeExtensions, objectTypeExtension) - ref := len(p.document.ObjectTypeExtensions) - 1 - node := ast.Node{Ref: ref, Kind: ast.NodeKindObjectTypeExtension} - p.document.RootNodes = append(p.document.RootNodes, node) - - if p.shouldIndex { - p.indexNode(objectTypeDefinition.Name, node) - } -} - -func (p *Parser) parseInterfaceTypeExtension(extend position.Position) { - var interfaceTypeDefinition ast.InterfaceTypeDefinition - interfaceTypeDefinition.InterfaceLiteral = p.mustReadIdentKey(identkeyword.INTERFACE).TextPosition - interfaceTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEqualsIdentKey(identkeyword.IMPLEMENTS) { - interfaceTypeDefinition.ImplementsInterfaces = p.parseImplementsInterfaces() - } - if p.peekEquals(keyword.AT) { - interfaceTypeDefinition.Directives = p.parseDirectiveList() - interfaceTypeDefinition.HasDirectives = len(interfaceTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - interfaceTypeDefinition.FieldsDefinition = p.parseFieldDefinitionList() - interfaceTypeDefinition.HasFieldDefinitions = len(interfaceTypeDefinition.FieldsDefinition.Refs) > 0 - } - interfaceTypeExtension := ast.InterfaceTypeExtension{ - ExtendLiteral: extend, - InterfaceTypeDefinition: interfaceTypeDefinition, - } - p.document.InterfaceTypeExtensions = append(p.document.InterfaceTypeExtensions, interfaceTypeExtension) - ref := len(p.document.InterfaceTypeExtensions) - 1 - node := ast.Node{Ref: ref, Kind: ast.NodeKindInterfaceTypeExtension} - p.document.RootNodes = append(p.document.RootNodes, node) - - if p.shouldIndex { - p.indexNode(interfaceTypeExtension.Name, node) - } -} - -func (p *Parser) parseScalarTypeExtension(extend position.Position) { - var scalarTypeDefinition ast.ScalarTypeDefinition - scalarTypeDefinition.ScalarLiteral = p.mustReadIdentKey(identkeyword.SCALAR).TextPosition - scalarTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - scalarTypeDefinition.Directives = p.parseDirectiveList() - scalarTypeDefinition.HasDirectives = len(scalarTypeDefinition.Directives.Refs) > 0 - } - scalarTypeExtension := ast.ScalarTypeExtension{ - ExtendLiteral: extend, - ScalarTypeDefinition: scalarTypeDefinition, - } - p.document.ScalarTypeExtensions = append(p.document.ScalarTypeExtensions, scalarTypeExtension) - ref := len(p.document.ScalarTypeExtensions) - 1 - node := ast.Node{Ref: ref, Kind: ast.NodeKindScalarTypeExtension} - p.document.RootNodes = append(p.document.RootNodes, node) - - if p.shouldIndex { - p.indexNode(scalarTypeExtension.Name, node) - } -} - -func (p *Parser) parseUnionTypeExtension(extend position.Position) { - var unionTypeDefinition ast.UnionTypeDefinition - unionTypeDefinition.UnionLiteral = p.mustReadIdentKey(identkeyword.UNION).TextPosition - unionTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - unionTypeDefinition.Directives = p.parseDirectiveList() - unionTypeDefinition.HasDirectives = len(unionTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.EQUALS) { - unionTypeDefinition.Equals = p.mustRead(keyword.EQUALS).TextPosition - unionTypeDefinition.UnionMemberTypes = p.parseUnionMemberTypes() - unionTypeDefinition.HasUnionMemberTypes = len(unionTypeDefinition.UnionMemberTypes.Refs) > 0 - } - unionTypeExtension := ast.UnionTypeExtension{ - ExtendLiteral: extend, - UnionTypeDefinition: unionTypeDefinition, - } - p.document.UnionTypeExtensions = append(p.document.UnionTypeExtensions, unionTypeExtension) - ref := len(p.document.UnionTypeExtensions) - 1 - node := ast.Node{Ref: ref, Kind: ast.NodeKindUnionTypeExtension} - p.document.RootNodes = append(p.document.RootNodes, node) - - if p.shouldIndex { - p.indexNode(unionTypeExtension.Name, node) - } -} - -func (p *Parser) parseEnumTypeExtension(extend position.Position) { - var enumTypeDefinition ast.EnumTypeDefinition - enumTypeDefinition.EnumLiteral = p.mustReadIdentKey(identkeyword.ENUM).TextPosition - enumTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - enumTypeDefinition.Directives = p.parseDirectiveList() - enumTypeDefinition.HasDirectives = len(enumTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - enumTypeDefinition.EnumValuesDefinition = p.parseEnumValueDefinitionList() - enumTypeDefinition.HasEnumValuesDefinition = len(enumTypeDefinition.EnumValuesDefinition.Refs) > 0 - } - enumTypeExtension := ast.EnumTypeExtension{ - ExtendLiteral: extend, - EnumTypeDefinition: enumTypeDefinition, - } - p.document.EnumTypeExtensions = append(p.document.EnumTypeExtensions, enumTypeExtension) - ref := len(p.document.EnumTypeExtensions) - 1 - node := ast.Node{Ref: ref, Kind: ast.NodeKindEnumTypeExtension} - p.document.RootNodes = append(p.document.RootNodes, node) - - if p.shouldIndex { - p.indexNode(enumTypeExtension.Name, node) - } -} - -func (p *Parser) parseInputObjectTypeExtension(extend position.Position) { - var inputObjectTypeDefinition ast.InputObjectTypeDefinition - inputObjectTypeDefinition.InputLiteral = p.mustReadIdentKey(identkeyword.INPUT).TextPosition - inputObjectTypeDefinition.Name = p.mustRead(keyword.IDENT).Literal - if p.peekEquals(keyword.AT) { - inputObjectTypeDefinition.Directives = p.parseDirectiveList() - inputObjectTypeDefinition.HasDirectives = len(inputObjectTypeDefinition.Directives.Refs) > 0 - } - if p.peekEquals(keyword.LBRACE) { - inputObjectTypeDefinition.InputFieldsDefinition = p.parseInputValueDefinitionList(keyword.RBRACE) - inputObjectTypeDefinition.HasInputFieldsDefinition = len(inputObjectTypeDefinition.InputFieldsDefinition.Refs) > 0 - } - inputObjectTypeExtension := ast.InputObjectTypeExtension{ - ExtendLiteral: extend, - InputObjectTypeDefinition: inputObjectTypeDefinition, - } - p.document.InputObjectTypeExtensions = append(p.document.InputObjectTypeExtensions, inputObjectTypeExtension) - ref := len(p.document.InputObjectTypeExtensions) - 1 - node := ast.Node{Ref: ref, Kind: ast.NodeKindInputObjectTypeExtension} - p.document.RootNodes = append(p.document.RootNodes, node) - - if p.shouldIndex { - p.indexNode(inputObjectTypeExtension.Name, node) - } -} diff --git a/pkg/astparser/parser_test.go b/pkg/astparser/parser_test.go deleted file mode 100644 index bd17e5779..000000000 --- a/pkg/astparser/parser_test.go +++ /dev/null @@ -1,2687 +0,0 @@ -package astparser - -import ( - "fmt" - "os" - "testing" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - - "github.com/stretchr/testify/assert" -) - -func TestParser_Parse(t *testing.T) { - - type check func(doc *ast.Document, extra interface{}) - type action func(parser *Parser) (interface{}, operationreport.Report) - - parse := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.Parse(parser.document, &report) - return nil, report - } - } - - parseType := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.report = &report - parser.tokenize() - ref := parser.ParseType() - return ref, report - } - } - - parseValue := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.report = &report - parser.tokenize() - value := parser.ParseValue() - return value, report - } - } - - parseSelectionSet := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.report = &report - parser.tokenize() - set, _ := parser.parseSelectionSet() - return set, report - } - } - - parseFragmentSpread := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.report = &report - parser.tokenize() - fragmentSpread := parser.parseFragmentSpread(position.Position{}) - return parser.document.FragmentSpreads[fragmentSpread], report - } - } - - parseInlineFragment := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.report = &report - parser.tokenize() - inlineFragment := parser.parseInlineFragment(position.Position{}) - return parser.document.InlineFragments[inlineFragment], report - } - } - - parseVariableDefinitionList := func() action { - return func(parser *Parser) (interface{}, operationreport.Report) { - report := operationreport.Report{} - parser.report = &report - parser.tokenize() - variableDefinitionList := parser.parseVariableDefinitionList() - return variableDefinitionList, report - } - } - - wantIndexedNode := func(key string, kind ast.NodeKind) check { - return func(doc *ast.Document, extra interface{}) { - node, exists := doc.Index.FirstNodeByNameStr(key) - if !exists { - panic("want true") - } - if node.Kind != kind { - panic(fmt.Errorf("want kind: %s, got: %s", kind, node.Kind)) - } - } - } - - run := func(inputString string, action func() action, wantErr bool, checks ...check) { - - doc := ast.NewDocument() - doc.Input.ResetInputBytes([]byte(inputString)) - - parser := NewParser() - parser.document = doc - - extra, err := action()(parser) - - if wantErr && !err.HasErrors() { - panic("want report, got nil") - } else if !wantErr && err.HasErrors() { - panic(fmt.Errorf("want nil, got report: %s", err.Error())) - } - - for _, check := range checks { - check(doc, extra) - } - } - - t.Run("tokenize", func(t *testing.T) { - - doc := ast.NewDocument() - doc.Input.ResetInputBytes([]byte( - `schema { - query: Query - mutation: Mutation - subscription: Subscription - }`, - )) - - parser := NewParser() - parser.document = doc - parser.tokenize() - - for i, want := range []keyword.Keyword{ - keyword.IDENT, keyword.LBRACE, - keyword.IDENT, keyword.COLON, keyword.IDENT, - keyword.IDENT, keyword.COLON, keyword.IDENT, - keyword.IDENT, keyword.COLON, keyword.IDENT, - keyword.RBRACE, - } { - parser.peek() - got := parser.read().Keyword - if got != want { - t.Fatalf("want keyword %s @ %d, got: %s", want, i, got) - } - } - }) - - t.Run("no report on empty input", func(t *testing.T) { - run("", parse, false) - }) - t.Run("schema", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`schema { - query: Query - mutation: Mutation - subscription: Subscription - }`, parse, - false, - func(doc *ast.Document, extra interface{}) { - definition := doc.RootNodes[0] - if definition.Ref != 0 { - panic("want 0") - } - if definition.Kind != ast.NodeKindSchemaDefinition { - panic("want NodeKindSchemaDefinition") - } - schema := doc.SchemaDefinitions[0] - query := doc.RootOperationTypeDefinitions[schema.RootOperationTypeDefinitions.Refs[0]] - if query.OperationType != ast.OperationTypeQuery { - panic("want OperationTypeQuery") - } - name := doc.Input.ByteSliceString(query.NamedType.Name) - if name != "Query" { - panic(fmt.Errorf("want 'Query', got '%s'", name)) - } - mutation := doc.RootOperationTypeDefinitions[schema.RootOperationTypeDefinitions.Refs[1]] - if mutation.OperationType != ast.OperationTypeMutation { - panic("want OperationTypeMutation") - } - name = doc.Input.ByteSliceString(mutation.NamedType.Name) - if name != "Mutation" { - panic(fmt.Errorf("want 'Mutation', got '%s'", name)) - } - subscription := doc.RootOperationTypeDefinitions[schema.RootOperationTypeDefinitions.Refs[2]] - if subscription.OperationType != ast.OperationTypeSubscription { - panic("want OperationTypeSubscription") - } - name = doc.Input.ByteSliceString(subscription.NamedType.Name) - if name != "Subscription" { - panic(fmt.Errorf("want 'Subscription', got '%s'", name)) - } - }) - }) - t.Run("with directives", func(t *testing.T) { - run(`schema @foo @bar(baz: "bal") { - query: Query - }`, parse, false, func(doc *ast.Document, extra interface{}) { - schema := doc.SchemaDefinitions[0] - foo := doc.Directives[schema.Directives.Refs[0]] - fooName := doc.Input.ByteSliceString(foo.Name) - if fooName != "foo" { - panic("want foo, got: " + fooName) - } - if len(foo.Arguments.Refs) != 0 { - panic("should not HasNext") - } - bar := doc.Directives[schema.Directives.Refs[1]] - barName := doc.Input.ByteSliceString(bar.Name) - if barName != "bar" { - panic("want bar, got: " + barName) - } - baz := doc.Arguments[bar.Arguments.Refs[0]] - bazName := doc.Input.ByteSliceString(baz.Name) - if bazName != "baz" { - panic("want baz, got: " + bazName) - } - if baz.Value.Kind != ast.ValueKindString { - panic("want ValueKindString") - } - bal := doc.Input.ByteSliceString(doc.StringValues[baz.Value.Ref].Content) - if bal != "bal" { - panic("want bal, got: " + bal) - } - }) - }) - t.Run("invalid body missing", func(t *testing.T) { - run(`schema`, parse, true) - }) - t.Run("invalid body unclosed", func(t *testing.T) { - run(`schema {`, parse, true) - }) - t.Run("invalid directive arguments unclosed", func(t *testing.T) { - run(`schema @foo( {}`, parse, true) - }) - t.Run("invalid directive without @", func(t *testing.T) { - run(`schema foo {}`, parse, true) - }) - t.Run("no report on schema with comments everywhere", func(t *testing.T) { - run(` - #comment - scalar #comment - Date #comment - - schema #comment - { #comment - query#comment - :#comment - #comment - Query#comment - #comment - }#comment - - #comment - type#comment - Query#comment - {#comment - me#comment - :#comment - User#comment - !#comment - user(#comment - id#comment - :#comment - ID#comment - !#comment - )#comment - :#comment - User#comment - allUsers#comment - :#comment - [#comment - #comment - User#comment - ]#comment - search#comment - (#comment - term#comment - :#comment - String#comment - !#comment - )#comment - :#comment - [#comment - SearchResult#comment - !#comment - ]#comment - !#comment - myChats:#comment - [#comment - Chat#comment - !#comment - ]!#comment - } - - enum#comment - Role#comment - {#comment - #comment - USER#comment - ,#comment - ADMIN#comment - ,#comment - #comment - }#comment - - interface#comment - Node {#comment - id#comment - :#comment - ID#comment - !#comment - }#comment - - union #comment - SearchResult#comment - =#comment - User#comment - |#comment - Chat#comment - |#comment - ChatMessage#comment - - type#comment - User#comment - implements#comment - Node#comment - {#comment - id#comment - :#comment - ID#comment - !#comment - username#comment - :#comment - String#comment - !#comment - email#comment - :#comment - String#comment - !#comment - role#comment - :#comment - Role#comment - !#comment - }#comment - - type#comment - Chat#comment - implements#comment - Node#comment - {#comment - id#comment - :#comment - ID#comment - !#comment - users#comment - :#comment - [#comment - User#comment - !#comment - ]!#comment - messages#comment - :#comment - [#comment - ChatMessage#comment - !#comment - ]#comment - !#comment - #comment - }#comment - - type#comment - ChatMessage#comment - implements#comment - Node#comment - {#comment - id#comment - :#comment - ID#comment - !#comment - content#comment - :#comment - String#comment - !#comment - time#comment - :#comment - Date#comment - !#comment - user#comment - :#comment - User#comment - !#comment - #comment - }#comment`, parse, false) - }) - }) - t.Run("schema extension", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`extend schema { - query: Query - mutation: Mutation - subscription: Subscription - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - - schema := doc.SchemaExtensions[0] - - query := doc.RootOperationTypeDefinitions[schema.RootOperationTypeDefinitions.Refs[0]] - if query.OperationType != ast.OperationTypeQuery { - panic("want OperationTypeQuery") - } - name := doc.Input.ByteSliceString(query.NamedType.Name) - if name != "Query" { - panic(fmt.Errorf("want 'Query', got '%s'", name)) - } - - mutation := doc.RootOperationTypeDefinitions[schema.RootOperationTypeDefinitions.Refs[1]] - if mutation.OperationType != ast.OperationTypeMutation { - panic("want OperationTypeMutation") - } - name = doc.Input.ByteSliceString(mutation.NamedType.Name) - if name != "Mutation" { - panic(fmt.Errorf("want 'Mutation', got '%s'", name)) - } - subscription := doc.RootOperationTypeDefinitions[schema.RootOperationTypeDefinitions.Refs[2]] - if subscription.OperationType != ast.OperationTypeSubscription { - panic("want OperationTypeSubscription") - } - name = doc.Input.ByteSliceString(subscription.NamedType.Name) - if name != "Subscription" { - panic(fmt.Errorf("want 'Subscription', got '%s'", name)) - } - }) - }) - }) - t.Run("object type extension", func(t *testing.T) { - t.Run("complex", func(t *testing.T) { - run(`extend type Person implements Foo & Bar { - name: String - "age of the person" - age: Int - """ - date of birth - """ - dateOfBirth: Date - }`, parse, false, func(doc *ast.Document, extra interface{}) { - - person := doc.ObjectTypeExtensions[0] - personName := doc.Input.ByteSliceString(person.Name) - if personName != "Person" { - panic("want person") - } - - // interfaces - - implementsFoo := doc.Types[person.ImplementsInterfaces.Refs[0]] - if implementsFoo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsFoo.Name) != "Foo" { - panic("want Foo") - } - - implementsBar := doc.Types[person.ImplementsInterfaces.Refs[1]] - if implementsBar.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsBar.Name) != "Bar" { - panic("want Bar") - } - - // field definitions - nameString := doc.FieldDefinitions[person.FieldsDefinition.Refs[0]] - name := doc.Input.ByteSliceString(nameString.Name) - if name != "name" { - panic("want name") - } - nameStringType := doc.Types[nameString.Type] - if nameStringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - stringName := doc.Input.ByteSliceString(nameStringType.Name) - if stringName != "String" { - panic("want String") - } - - ageField := doc.FieldDefinitions[person.FieldsDefinition.Refs[1]] - if !ageField.Description.IsDefined { - panic("want true") - } - if ageField.Description.IsBlockString { - panic("want false ") - } - if doc.Input.ByteSliceString(ageField.Description.Content) != "age of the person" { - panic("want 'age of the person'") - } - if doc.Input.ByteSliceString(ageField.Name) != "age" { - panic("want age") - } - intType := doc.Types[ageField.Type] - if intType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(intType.Name) != "Int" { - panic("want Int") - } - - dateOfBirthField := doc.FieldDefinitions[person.FieldsDefinition.Refs[2]] - if doc.Input.ByteSliceString(dateOfBirthField.Name) != "dateOfBirth" { - panic("want dateOfBirth") - } - if !dateOfBirthField.Description.IsDefined { - panic("want true") - } - if !dateOfBirthField.Description.IsBlockString { - panic("want true") - } - if doc.Input.ByteSliceString(dateOfBirthField.Description.Content) != "date of birth" { - panic(fmt.Sprintf("want 'date of birth' got: '%s'", doc.Input.ByteSliceString(dateOfBirthField.Description.Content))) - } - dateType := doc.Types[dateOfBirthField.Type] - if doc.Input.ByteSliceString(dateType.Name) != "Date" { - panic("want Date") - } - }) - }) - }) - t.Run("interface type extension", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`extend interface NamedEntity @foo { - name: String - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - namedEntity := doc.InterfaceTypeExtensions[0] - if doc.Input.ByteSliceString(namedEntity.Name) != "NamedEntity" { - panic("want NamedEntity") - } - - // fields - name := doc.FieldDefinitions[namedEntity.FieldsDefinition.Refs[0]] - if doc.Input.ByteSliceString(name.Name) != "name" { - panic("want name") - } - - // directives - foo := doc.Directives[namedEntity.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - }) - }) - t.Run("interface implements interface", func(t *testing.T) { - run(`extend interface NamedEntity implements Foo & Bar { - name: String - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - namedEntity := doc.InterfaceTypeExtensions[0] - if doc.Input.ByteSliceString(namedEntity.Name) != "NamedEntity" { - panic("want NamedEntity") - } - - implementsFoo := doc.Types[namedEntity.ImplementsInterfaces.Refs[0]] - if implementsFoo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsFoo.Name) != "Foo" { - panic("want Foo") - } - - implementsBar := doc.Types[namedEntity.ImplementsInterfaces.Refs[1]] - if implementsBar.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsBar.Name) != "Bar" { - panic("want Bar") - } - - // fields - name := doc.FieldDefinitions[namedEntity.FieldsDefinition.Refs[0]] - if doc.Input.ByteSliceString(name.Name) != "name" { - panic("want name") - } - }) - }) - }) - t.Run("scalar type extension", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`extend scalar JSON @foo`, parse, false, - func(doc *ast.Document, extra interface{}) { - scalar := doc.ScalarTypeExtensions[0] - if doc.Input.ByteSliceString(scalar.Name) != "JSON" { - panic("want JSON") - } - foo := doc.Directives[scalar.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - }) - }) - }) - t.Run("union type extension", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`extend union SearchResult = Photo | Person`, parse, false, - func(doc *ast.Document, extra interface{}) { - SearchResult := doc.UnionTypeExtensions[0] - - // union member types - - // Photo - Photo := doc.Types[SearchResult.UnionMemberTypes.Refs[0]] - if Photo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(Photo.Name) != "Photo" { - panic("want Photo") - } - - // Person - Person := doc.Types[SearchResult.UnionMemberTypes.Refs[1]] - if Person.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(Person.Name) != "Person" { - panic("want Person") - } - - // no more types - if len(SearchResult.UnionMemberTypes.Refs) != 2 { - t.Fatalf("want 2") - } - }) - }) - }) - t.Run("enum type extension", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`extend enum Direction @bar { - NORTH - EAST - SOUTH - "describes WEST" - WEST @foo - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - direction := doc.EnumTypeExtensions[0] - if doc.Input.ByteSliceString(direction.Name) != "Direction" { - panic("want Direction") - } - - // directives - bar := doc.Directives[direction.Directives.Refs[0]] - if doc.Input.ByteSliceString(bar.Name) != "bar" { - panic("want bar") - } - - // values - - wantValue := func(index int, name string) { - enum := doc.EnumValueDefinitions[direction.EnumValuesDefinition.Refs[index]] - if doc.Input.ByteSliceString(enum.EnumValue) != name { - panic(fmt.Sprintf("want %s", name)) - } - } - - wantValue(0, "NORTH") - wantValue(1, "EAST") - wantValue(2, "SOUTH") - wantValue(3, "WEST") - - west := doc.EnumValueDefinitions[direction.EnumValuesDefinition.Refs[3]] - if !west.Description.IsDefined { - panic("want true") - } - if doc.Input.ByteSliceString(west.Description.Content) != "describes WEST" { - panic("want describes WEST") - } - - foo := doc.Directives[west.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - - if len(direction.EnumValuesDefinition.Refs) != 4 { - panic("want 4") - } - }) - }) - }) - t.Run("input object type extension", func(t *testing.T) { - t.Run("complex", func(t *testing.T) { - run(` extend input Person { - name: String = "Gopher" - }`, parse, - false, func(doc *ast.Document, extra interface{}) { - person := doc.InputObjectTypeExtensions[0] - if doc.Input.ByteSliceString(person.Name) != "Person" { - panic("want person") - } - - name := doc.InputValueDefinitions[person.InputFieldsDefinition.Refs[0]] - if doc.Input.ByteSliceString(name.Name) != "name" { - panic("want name") - } - if !name.DefaultValue.IsDefined { - panic("want true") - } - if name.DefaultValue.Value.Kind != ast.ValueKindString { - panic("want ValueKindString") - } - if doc.Input.ByteSliceString(doc.StringValues[name.DefaultValue.Value.Ref].Content) != "Gopher" { - panic("want Gopher") - } - }) - }) - }) - t.Run("ignore block string before extend type", func(t *testing.T) { - run(`""" - Schema BlockString to ignore - """ - extend type Schema { - } - """" - Object Type BlockString to ignore - """ - extend type Person { - } - """" - Interface Type BlockString to ignore - """ - extend interface NamedEntity { - } - """" - Scalar Type BlockString to ignore - """ - extend scalar JSON { - } - """" - Union Type BlockString to ignore - """ - extend union SearchResult = Photo | Person { - } - """" - Input Type BlockString to ignore - """ - extend input NamedEntity { - }`, parse, false) - }) - t.Run("scalar type definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`scalar JSON`, parse, false, - func(doc *ast.Document, extra interface{}) { - scalar := doc.ScalarTypeDefinitions[0] - if doc.Input.ByteSliceString(scalar.Name) != "JSON" { - panic("want JSON") - } - }) - }) - t.Run("with description", func(t *testing.T) { - run(`"JSON scalar description" scalar JSON`, parse, false, - func(doc *ast.Document, extra interface{}) { - scalar := doc.ScalarTypeDefinitions[0] - if doc.Input.ByteSliceString(scalar.Name) != "JSON" { - panic("want JSON") - } - if !scalar.Description.IsDefined { - panic("want true") - } - if doc.Input.ByteSliceString(scalar.Description.Content) != "JSON scalar description" { - panic("want 'JSON scalar description'") - } - }) - }) - t.Run("with directive", func(t *testing.T) { - run(`scalar JSON @foo`, parse, false, - func(doc *ast.Document, extra interface{}) { - scalar := doc.ScalarTypeDefinitions[0] - if doc.Input.ByteSliceString(scalar.Name) != "JSON" { - panic("want JSON") - } - foo := doc.Directives[scalar.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - }) - }) - }) - t.Run("object type definition", func(t *testing.T) { - t.Run("complex", func(t *testing.T) { - run(`type Person implements Foo & Bar { - name: String - "age of the person" - age: Int - """ - date of birth - """ - dateOfBirth: Date - }`, parse, false, func(doc *ast.Document, extra interface{}) { - person := doc.ObjectTypeDefinitions[0] - personName := doc.Input.ByteSliceString(person.Name) - if personName != "Person" { - panic("want person") - } - - // interfaces - - implementsFoo := doc.Types[person.ImplementsInterfaces.Refs[0]] - if implementsFoo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsFoo.Name) != "Foo" { - panic("want Foo") - } - - implementsBar := doc.Types[person.ImplementsInterfaces.Refs[1]] - if implementsBar.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsBar.Name) != "Bar" { - panic("want Bar") - } - - // field definitions - nameString := doc.FieldDefinitions[person.FieldsDefinition.Refs[0]] - name := doc.Input.ByteSliceString(nameString.Name) - if name != "name" { - panic("want name") - } - nameStringType := doc.Types[nameString.Type] - if nameStringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - stringName := doc.Input.ByteSliceString(nameStringType.Name) - if stringName != "String" { - panic("want String") - } - - ageField := doc.FieldDefinitions[person.FieldsDefinition.Refs[1]] - if !ageField.Description.IsDefined { - panic("want true") - } - if ageField.Description.IsBlockString { - panic("want false ") - } - if doc.Input.ByteSliceString(ageField.Description.Content) != "age of the person" { - panic("want 'age of the person'") - } - if doc.Input.ByteSliceString(ageField.Name) != "age" { - panic("want age") - } - intType := doc.Types[ageField.Type] - if intType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(intType.Name) != "Int" { - panic("want Int") - } - - dateOfBirthField := doc.FieldDefinitions[person.FieldsDefinition.Refs[2]] - if doc.Input.ByteSliceString(dateOfBirthField.Name) != "dateOfBirth" { - panic("want dateOfBirth") - } - if !dateOfBirthField.Description.IsDefined { - panic("want true") - } - if !dateOfBirthField.Description.IsBlockString { - panic("want true") - } - if doc.Input.ByteSliceString(dateOfBirthField.Description.Content) != "date of birth" { - panic(fmt.Sprintf("want 'date of birth' got: '%s'", doc.Input.ByteSliceString(dateOfBirthField.Description.Content))) - } - dateType := doc.Types[dateOfBirthField.Type] - if doc.Input.ByteSliceString(dateType.Name) != "Date" { - panic("want Date") - } - }) - }) - t.Run("with directives", func(t *testing.T) { - run(`type Person @foo @bar {}`, parse, false, func(doc *ast.Document, extra interface{}) { - person := doc.ObjectTypeDefinitions[0] - personName := doc.Input.ByteSliceString(person.Name) - if personName != "Person" { - panic("want person") - } - - // directives - - foo := doc.Directives[person.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - - bar := doc.Directives[person.Directives.Refs[1]] - if doc.Input.ByteSliceString(bar.Name) != "bar" { - panic("want bar") - } - }) - }) - t.Run("implements optional variant", func(t *testing.T) { - run(`type Person implements & Foo & Bar {}`, parse, false, func(doc *ast.Document, extra interface{}) { - person := doc.ObjectTypeDefinitions[0] - personName := doc.Input.ByteSliceString(person.Name) - if personName != "Person" { - panic("want person") - } - // interfaces - - implementsFoo := doc.Types[person.ImplementsInterfaces.Refs[0]] - if implementsFoo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsFoo.Name) != "Foo" { - panic("want Foo") - } - - implementsBar := doc.Types[person.ImplementsInterfaces.Refs[1]] - if implementsBar.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsBar.Name) != "Bar" { - panic("want Bar") - } - }) - }) - t.Run("input value definition list", func(t *testing.T) { - run(` type Person { - "name description" - name( - a: String! - "b description" - b: Int - """ - c description - """ - c: Float - ): String - }`, parse, false, func(doc *ast.Document, extra interface{}) { - person := doc.ObjectTypeDefinitions[0] - personName := doc.Input.ByteSliceString(person.Name) - if personName != "Person" { - panic("want person") - } - - name := doc.FieldDefinitions[person.FieldsDefinition.Refs[0]] - if !name.Description.IsDefined { - panic("want true") - } - if doc.Input.ByteSliceString(name.Description.Content) != "name description" { - panic("want 'name description'") - } - - // a - - a := doc.InputValueDefinitions[name.ArgumentsDefinition.Refs[0]] - if doc.Input.ByteSliceString(a.Name) != "a" { - panic("want a") - } - if doc.Types[a.Type].TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(doc.Types[doc.Types[a.Type].OfType].Name) != "String" { - panic("want String") - } - - // b - - b := doc.InputValueDefinitions[name.ArgumentsDefinition.Refs[1]] - if doc.Input.ByteSliceString(b.Name) != "b" { - panic("want b") - } - if doc.Input.ByteSliceString(b.Description.Content) != "b description" { - panic("want 'b description'") - } - if doc.Types[b.Type].TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(doc.Types[b.Type].Name) != "Int" { - panic("want Float") - } - - // c - - c := doc.InputValueDefinitions[name.ArgumentsDefinition.Refs[2]] - if doc.Input.ByteSliceString(c.Name) != "c" { - panic("want b") - } - if !c.Description.IsDefined { - panic("want true") - } - if !c.Description.IsBlockString { - panic("want true") - } - if doc.Input.ByteSliceString(c.Description.Content) != "c description" { - panic("want 'c description'") - } - if doc.Types[c.Type].TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(doc.Types[c.Type].Name) != "Float" { - panic("want Float") - } - }) - }) - t.Run("object type with commented out field", func(t *testing.T) { - run(`type Person { - name: String - # tbd: String - age: Int - }`, parse, false, func(doc *ast.Document, extra interface{}) { - person := doc.ObjectTypeDefinitions[0] - personName := doc.Input.ByteSliceString(person.Name) - if personName != "Person" { - t.Fatal("want person") - } - - // field definitions - if len(person.FieldsDefinition.Refs) != 2 { - t.Fatal("want 2") - } - nameString := doc.FieldDefinitions[person.FieldsDefinition.Refs[0]] - name := doc.Input.ByteSliceString(nameString.Name) - if name != "name" { - t.Fatal("want name") - } - nameStringType := doc.Types[nameString.Type] - if nameStringType.TypeKind != ast.TypeKindNamed { - t.Fatal("want TypeKindNamed") - } - stringName := doc.Input.ByteSliceString(nameStringType.Name) - if stringName != "String" { - t.Fatal("want String") - } - ageInt := doc.FieldDefinitions[person.FieldsDefinition.Refs[1]] - age := doc.Input.ByteSliceString(ageInt.Name) - if age != "age" { - t.Fatal("want age") - } - ageIntType := doc.Types[ageInt.Type] - if ageIntType.TypeKind != ast.TypeKindNamed { - t.Fatal("want TypeKindNamed") - } - intAge := doc.Input.ByteSliceString(ageIntType.Name) - if intAge != "Int" { - t.Fatal("want String") - } - }) - }) - t.Run("implements & without next", func(t *testing.T) { - run(`type Person implements Foo & {}`, parse, true) - }) - }) - t.Run("input object type definition", func(t *testing.T) { - t.Run("complex", func(t *testing.T) { - run(` input Person { - name: String = "Gopher" - }`, parse, - false, func(doc *ast.Document, extra interface{}) { - person := doc.InputObjectTypeDefinitions[0] - if doc.Input.ByteSliceString(person.Name) != "Person" { - panic("want person") - } - - name := doc.InputValueDefinitions[person.InputFieldsDefinition.Refs[0]] - if doc.Input.ByteSliceString(name.Name) != "name" { - panic("want name") - } - if !name.DefaultValue.IsDefined { - panic("want true") - } - if name.DefaultValue.Value.Kind != ast.ValueKindString { - panic("want ValueKindString") - } - if doc.Input.ByteSliceString(doc.StringValues[name.DefaultValue.Value.Ref].Content) != "Gopher" { - panic("want Gopher") - } - }) - }) - }) - t.Run("interface type definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`interface NamedEntity @foo { - name: String - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - namedEntity := doc.InterfaceTypeDefinitions[0] - if doc.Input.ByteSliceString(namedEntity.Name) != "NamedEntity" { - panic("want NamedEntity") - } - - // fields - name := doc.FieldDefinitions[namedEntity.FieldsDefinition.Refs[0]] - if doc.Input.ByteSliceString(name.Name) != "name" { - panic("want name") - } - - // directives - foo := doc.Directives[namedEntity.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - }) - }) - t.Run("with description", func(t *testing.T) { - run(`"describes NamedEntity" interface NamedEntity { - name: String - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - namedEntity := doc.InterfaceTypeDefinitions[0] - if doc.Input.ByteSliceString(namedEntity.Name) != "NamedEntity" { - panic("want NamedEntity") - } - if !namedEntity.Description.IsDefined { - panic("want true") - } - if doc.Input.ByteSliceString(namedEntity.Description.Content) != "describes NamedEntity" { - panic("want 'describes NamedEntity'") - } - }) - }) - t.Run("with interface implementation", func(t *testing.T) { - run(`interface NamedEntity implements Foo & Bar { - name: String - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - namedEntity := doc.InterfaceTypeDefinitions[0] - if doc.Input.ByteSliceString(namedEntity.Name) != "NamedEntity" { - panic("want NamedEntity") - } - implementsFoo := doc.Types[namedEntity.ImplementsInterfaces.Refs[0]] - if implementsFoo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsFoo.Name) != "Foo" { - panic("want Foo") - } - - implementsBar := doc.Types[namedEntity.ImplementsInterfaces.Refs[1]] - if implementsBar.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(implementsBar.Name) != "Bar" { - panic("want Bar") - } - }) - }) - }) - t.Run("union type definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`union SearchResult = Photo | Person`, parse, false, - func(doc *ast.Document, extra interface{}) { - SearchResult := doc.UnionTypeDefinitions[0] - - // union member types - - // Photo - Photo := doc.Types[SearchResult.UnionMemberTypes.Refs[0]] - if Photo.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(Photo.Name) != "Photo" { - panic("want Photo") - } - - // Person - Person := doc.Types[SearchResult.UnionMemberTypes.Refs[1]] - if Person.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(Person.Name) != "Person" { - panic("want Person") - } - - // no more types - if len(SearchResult.UnionMemberTypes.Refs) != 2 { - panic("want 2") - } - }) - }) - t.Run("without members", func(t *testing.T) { - run(`union SearchResult`, parse, false, - func(doc *ast.Document, extra interface{}) { - SearchResult := doc.UnionTypeDefinitions[0] - - // union member types - - // no more types - if len(SearchResult.UnionMemberTypes.Refs) != 0 { - panic("want 0") - } - }) - }) - t.Run("member missing after pipe", func(t *testing.T) { - run(`union SearchResult = Photo |`, parse, true) - }) - t.Run("without members", func(t *testing.T) { - run(`union SearchResult =`, parse, true) - }) - }) - t.Run("type", func(t *testing.T) { - t.Run("named", func(t *testing.T) { - run("String", parseType, false, func(doc *ast.Document, extra interface{}) { - stringType := doc.Types[0] - if stringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(stringType.Name) != "String" { - panic("want String") - } - }) - }) - t.Run("non null named", func(t *testing.T) { - run("String!", parseType, false, func(doc *ast.Document, extra interface{}) { - nonNull := doc.Types[1] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - stringType := doc.Types[nonNull.OfType] - if stringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(stringType.Name) != "String" { - panic("want String") - } - }) - }) - t.Run("non null list of named", func(t *testing.T) { - run("[String]!", parseType, false, func(doc *ast.Document, extra interface{}) { - nonNull := doc.Types[2] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - list := doc.Types[nonNull.OfType] - if list.TypeKind != ast.TypeKindList { - panic("want TypeKindList") - } - stringType := doc.Types[list.OfType] - if stringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(stringType.Name) != "String" { - panic("want String") - } - }) - }) - t.Run("non null list of non null named", func(t *testing.T) { - run("[String!]!", parseType, false, func(doc *ast.Document, extra interface{}) { - nonNull := doc.Types[3] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - list := doc.Types[nonNull.OfType] - if list.TypeKind != ast.TypeKindList { - panic("want TypeKindList") - } - nonNull = doc.Types[list.OfType] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - stringType := doc.Types[nonNull.OfType] - if stringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(stringType.Name) != "String" { - panic("want String") - } - }) - }) - t.Run("non null list of non null list of named", func(t *testing.T) { - run("[[String]!]!", parseType, false, func(doc *ast.Document, extra interface{}) { - nonNull := doc.Types[4] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - list := doc.Types[nonNull.OfType] - if list.TypeKind != ast.TypeKindList { - panic("want TypeKindList") - } - nonNull = doc.Types[list.OfType] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - list = doc.Types[nonNull.OfType] - if list.TypeKind != ast.TypeKindList { - panic("want TypeKindList") - } - stringType := doc.Types[list.OfType] - if stringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(stringType.Name) != "String" { - panic("want String") - } - }) - }) - t.Run("non null list of non null list of non null named", func(t *testing.T) { - run("[[String!]!]!", parseType, false, func(doc *ast.Document, extra interface{}) { - nonNull := doc.Types[5] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - list := doc.Types[nonNull.OfType] - if list.TypeKind != ast.TypeKindList { - panic("want TypeKindList") - } - nonNull = doc.Types[list.OfType] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - list = doc.Types[nonNull.OfType] - if list.TypeKind != ast.TypeKindList { - panic("want TypeKindList") - } - nonNull = doc.Types[list.OfType] - if nonNull.TypeKind != ast.TypeKindNonNull { - panic("want TypeKindNonNull") - } - stringType := doc.Types[nonNull.OfType] - if stringType.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(stringType.Name) != "String" { - panic("want String") - } - }) - }) - t.Run("report unexpected bang", func(t *testing.T) { - run("!", parseType, true) - }) - t.Run("report empty list", func(t *testing.T) { - run("[]", parseType, true) - }) - t.Run("report incomplete list", func(t *testing.T) { - run("[", parseType, true) - }) - t.Run("report unclosed list", func(t *testing.T) { - run("[String", parseType, true) - }) - t.Run("report unclosed list with bang", func(t *testing.T) { - run("[String!", parseType, true) - }) - t.Run("report double bang", func(t *testing.T) { - run("String!!", parseType, true) - }) - t.Run("report list close at beginning", func(t *testing.T) { - run("]String", parseType, true) - }) - }) - t.Run("enum type definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`"enums" - enum Direction @bar { - NORTH - EAST - SOUTH - "describes WEST" - WEST @foo - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - direction := doc.EnumTypeDefinitions[0] - if doc.Input.ByteSliceString(direction.Name) != "Direction" { - panic("want Direction") - } - - // directives - bar := doc.Directives[direction.Directives.Refs[0]] - if doc.Input.ByteSliceString(bar.Name) != "bar" { - panic("want bar") - } - - // values - - wantValue := func(index int, name string) { - enum := doc.EnumValueDefinitions[direction.EnumValuesDefinition.Refs[index]] - if doc.Input.ByteSliceString(enum.EnumValue) != name { - panic(fmt.Sprintf("want %s", name)) - } - } - - wantValue(0, "NORTH") - wantValue(1, "EAST") - wantValue(2, "SOUTH") - wantValue(3, "WEST") - - west := doc.EnumValueDefinitions[direction.EnumValuesDefinition.Refs[3]] - if !west.Description.IsDefined { - panic("want true") - } - if doc.Input.ByteSliceString(west.Description.Content) != "describes WEST" { - panic("want describes WEST") - } - - foo := doc.Directives[west.Directives.Refs[0]] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - panic("want foo") - } - - if len(direction.EnumValuesDefinition.Refs) != 4 { - panic("want 4") - } - }) - }) - }) - t.Run("directive definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`directive @example on FIELD`, parse, false, - func(doc *ast.Document, extra interface{}) { - example := doc.DirectiveDefinitions[0] - if doc.Input.ByteSliceString(example.Name) != "example" { - panic("want example") - } - locations := example.DirectiveLocations.Iterable() - if !locations.Next() { - panic("want next") - } - if locations.Value() != ast.ExecutableDirectiveLocationField { - panic("want ExecutableDirectiveLocationField") - } - if locations.Next() { - panic("want false") - } - }) - }) - t.Run("repeatable", func(t *testing.T) { - run(`directive @example repeatable on FIELD`, parse, false, - func(doc *ast.Document, extra interface{}) { - example := doc.DirectiveDefinitions[0] - if doc.Input.ByteSliceString(example.Name) != "example" { - panic("want example") - } - assert.True(t, example.Repeatable.IsRepeatable) - assert.Equal(t, uint32(20), example.Repeatable.Position.CharStart) - assert.Equal(t, uint32(30), example.Repeatable.Position.CharEnd) - }) - }) - t.Run("multiple directive locations", func(t *testing.T) { - run(`directive @example on FIELD | SCALAR | SCHEMA`, parse, false, - func(doc *ast.Document, extra interface{}) { - example := doc.DirectiveDefinitions[0] - if doc.Input.ByteSliceString(example.Name) != "example" { - panic("want example") - } - locations := example.DirectiveLocations.Iterable() - if !locations.Next() { - panic("want next") - } - if locations.Value() != ast.ExecutableDirectiveLocationField { - panic("want ExecutableDirectiveLocationField") - } - if !locations.Next() { - panic("want next") - } - if locations.Value() != ast.TypeSystemDirectiveLocationSchema { - panic("want TypeSystemDirectiveLocationSchema") - } - if !locations.Next() { - panic("want next") - } - if locations.Value() != ast.TypeSystemDirectiveLocationScalar { - panic("want TypeSystemDirectiveLocationScalar") - } - if locations.Next() { - panic("want false") - } - }) - }) - t.Run("report pipe at end", func(t *testing.T) { - run(`directive @example on FIELD | SCALAR | SCHEMA |`, parse, true) - }) - t.Run("missing location", func(t *testing.T) { - run(`directive @example on`, parse, true) - }) - t.Run("invalid location", func(t *testing.T) { - run(`directive @example on INVALID`, parse, true) - }) - }) - t.Run("value", func(t *testing.T) { - t.Run("variable value", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`$foo`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindVariable { - t.Fatal("want ValueKindVariable") - } - foo := doc.VariableValues[value.Ref] - if doc.Input.ByteSliceString(foo.Name) != "foo" { - t.Fatal("want foo") - } - }) - }) - t.Run("with underscore", func(t *testing.T) { - run(`$_foo`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindVariable { - t.Fatal("want ValueKindVariable") - } - foo := doc.VariableValues[value.Ref] - if doc.Input.ByteSliceString(foo.Name) != "_foo" { - t.Fatal("want foo") - } - }) - }) - t.Run("with numbers", func(t *testing.T) { - run(`$foo123`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindVariable { - t.Fatal("want ValueKindVariable") - } - foo := doc.VariableValues[value.Ref] - if doc.Input.ByteSliceString(foo.Name) != "foo123" { - t.Fatal("want foo123") - } - }) - }) - t.Run("report space", func(t *testing.T) { - run(`$ foo`, parseValue, true) - }) - t.Run("report start with A-Za-z", func(t *testing.T) { - run(`$123`, parseValue, true) - }) - }) - t.Run("int value", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`123`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindInteger { - panic("want ValueKindInteger") - } - intValue := doc.IntValues[value.Ref] - if doc.Input.ByteSliceString(intValue.Raw) != "123" { - panic("want 123") - } - if intValue.Negative { - panic("want false") - } - }) - }) - t.Run("negative", func(t *testing.T) { - run(`-123`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindInteger { - panic("want ValueKindInteger") - } - intValue := doc.IntValues[value.Ref] - if doc.Input.ByteSliceString(intValue.Raw) != "123" { - panic("want 123") - } - if !intValue.Negative { - panic("want false") - } - }) - }) - t.Run("report space after negative sign", func(t *testing.T) { - run(`- 123`, parseValue, true) - }) - }) - t.Run("float value", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`13.37`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindFloat { - panic("want ValueKindFloat") - } - intValue := doc.FloatValues[value.Ref] - if doc.Input.ByteSliceString(intValue.Raw) != "13.37" { - panic("want 13.37") - } - if intValue.Negative { - panic("want false") - } - }) - }) - t.Run("negative", func(t *testing.T) { - run(`-13.37`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindFloat { - panic("want ValueKindFloat") - } - intValue := doc.FloatValues[value.Ref] - if doc.Input.ByteSliceString(intValue.Raw) != "13.37" { - panic("want 13.37") - } - if !intValue.Negative { - panic("want false") - } - }) - }) - t.Run("report space after negative sign", func(t *testing.T) { - run(`- 13.37`, parseValue, true) - }) - }) - t.Run("null value", func(t *testing.T) { - run(`null`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindNull { - panic("want ValueKindNull") - } - }) - }) - t.Run("list value", func(t *testing.T) { - t.Run("complex", func(t *testing.T) { - run(`[1,2,"3",[4]]`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindList { - panic("want ValueKindList") - } - - list := doc.ListValues[value.Ref] - - // 1 - val := doc.Values[list.Refs[0]] - if val.Kind != ast.ValueKindInteger { - panic("want ValueKindInteger") - } - if doc.Input.ByteSliceString(doc.IntValues[val.Ref].Raw) != "1" { - panic("want 1") - } - - // 2 - val = doc.Values[list.Refs[1]] - if val.Kind != ast.ValueKindInteger { - panic("want ValueKindInteger") - } - if doc.Input.ByteSliceString(doc.IntValues[val.Ref].Raw) != "2" { - panic("want 1") - } - - // "3" - val = doc.Values[list.Refs[2]] - if val.Kind != ast.ValueKindString { - panic("want ValueKindString") - } - if doc.Input.ByteSliceString(doc.StringValues[val.Ref].Content) != "3" { - panic("want 3") - } - - // [4] - val = doc.Values[list.Refs[3]] - if val.Kind != ast.ValueKindList { - panic("want ValueKindString") - } - inner := doc.ListValues[val.Ref] - - four := doc.Values[inner.Refs[0]] - if four.Kind != ast.ValueKindInteger { - panic("want ValueKindInteger") - } - if doc.Input.ByteSliceString(doc.IntValues[four.Ref].Raw) != "4" { - panic("want 4") - } - if len(inner.Refs) != 1 { - panic("want 1") - } - - // no more - if len(list.Refs) != 4 { - panic("want 4") - } - }) - }) - }) - t.Run("object value", func(t *testing.T) { - t.Run("complex", func(t *testing.T) { - run(`{lon: 12.43, lat: -53.211, list: [1] }`, parseValue, false, - func(doc *ast.Document, extra interface{}) { - value := extra.(ast.Value) - if value.Kind != ast.ValueKindObject { - panic("want ValueKindObject") - } - object := doc.ObjectValues[value.Ref] - - // lon - lon := doc.ObjectFields[object.Refs[0]] - if doc.Input.ByteSliceString(lon.Name) != "lon" { - panic("want lon") - } - if lon.Value.Kind != ast.ValueKindFloat { - panic("want float") - } - if doc.Input.ByteSliceString(doc.FloatValues[lon.Value.Ref].Raw) != "12.43" { - panic("want 12.43") - } - - // lat - lat := doc.ObjectFields[object.Refs[1]] - if doc.Input.ByteSliceString(lat.Name) != "lat" { - panic("want lat") - } - if lon.Value.Kind != ast.ValueKindFloat { - panic("want float") - } - if !doc.FloatValues[lat.Value.Ref].Negative { - panic("want negative") - } - if doc.Input.ByteSliceString(doc.FloatValues[lat.Value.Ref].Raw) != "53.211" { - panic("want 53.211") - } - - // list - list := doc.ObjectFields[object.Refs[2]] - if list.Value.Kind != ast.ValueKindList { - panic("want ValueKindList") - } - listValue := doc.ListValues[list.Value.Ref] - one := doc.Values[listValue.Refs[0]] - if doc.Input.ByteSliceString(doc.IntValues[one.Ref].Raw) != "1" { - panic("want 1") - } - if len(listValue.Refs) != 1 { - panic("want 1") - } - - if len(object.Refs) != 3 { - panic("want 3") - } - }) - }) - }) - }) - t.Run("operation definition", func(t *testing.T) { - t.Run("unnamed query", func(t *testing.T) { - run(`query {field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - query := doc.OperationDefinitions[0] - if query.OperationType != ast.OperationTypeQuery { - panic("want OperationTypeQuery") - } - if doc.Input.ByteSliceString(query.Name) != "" { - panic("want empty string") - } - fieldSelection := doc.Selections[doc.SelectionSets[query.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - if field.Position.LineStart != 1 || field.Position.CharStart != 8 { - panic("want correct position") - } - }) - }) - t.Run("shorthand query", func(t *testing.T) { - run(`{field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - query := doc.OperationDefinitions[0] - if query.OperationType != ast.OperationTypeQuery { - panic("want OperationTypeQuery") - } - if doc.Input.ByteSliceString(query.Name) != "" { - panic("want empty string") - } - fieldSelection := doc.Selections[doc.SelectionSets[query.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - }) - }) - t.Run("named query", func(t *testing.T) { - run(`query Query1 {field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - query := doc.OperationDefinitions[0] - if query.OperationType != ast.OperationTypeQuery { - panic("want OperationTypeQuery") - } - if doc.Input.ByteSliceString(query.Name) != "Query1" { - panic("want Query1") - } - fieldSelection := doc.Selections[doc.SelectionSets[query.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - }) - }) - t.Run("unnamed mutation", func(t *testing.T) { - run(`mutation {field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - mutation := doc.OperationDefinitions[0] - if mutation.OperationType != ast.OperationTypeMutation { - panic("want OperationTypeMutation") - } - if doc.Input.ByteSliceString(mutation.Name) != "" { - panic("want empty string") - } - fieldSelection := doc.Selections[doc.SelectionSets[mutation.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - }) - }) - t.Run("named mutation", func(t *testing.T) { - run(`mutation Mutation1 {field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - mutation := doc.OperationDefinitions[0] - if mutation.OperationType != ast.OperationTypeMutation { - panic("want OperationTypeMutation") - } - if doc.Input.ByteSliceString(mutation.Name) != "Mutation1" { - panic("want Mutation1") - } - fieldSelection := doc.Selections[doc.SelectionSets[mutation.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - }) - }) - t.Run("unnamed subscription", func(t *testing.T) { - run(`subscription {field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - mutation := doc.OperationDefinitions[0] - if mutation.OperationType != ast.OperationTypeSubscription { - panic("want OperationTypeSubscription") - } - if doc.Input.ByteSliceString(mutation.Name) != "" { - panic("want empty string") - } - fieldSelection := doc.Selections[doc.SelectionSets[mutation.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - }) - }) - t.Run("named subscription", func(t *testing.T) { - run(`subscription Sub1 {field}`, parse, false, - func(doc *ast.Document, extra interface{}) { - mutation := doc.OperationDefinitions[0] - if mutation.OperationType != ast.OperationTypeSubscription { - panic("want OperationTypeSubscription") - } - if doc.Input.ByteSliceString(mutation.Name) != "Sub1" { - panic("want empty Sub1") - } - fieldSelection := doc.Selections[doc.SelectionSets[mutation.SelectionSet].SelectionRefs[0]] - if fieldSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - field := doc.Fields[fieldSelection.Ref] - if doc.Input.ByteSliceString(field.Name) != "field" { - panic("want field") - } - }) - }) - t.Run("complex nested subscription", func(t *testing.T) { - run(`subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { - storyLikeSubscribe(input: $input) { - story { - likers { - count - } - likeSentence { - text - } - } - } - }`, - parse, false, - func(doc *ast.Document, extra interface{}) { - subscription := doc.OperationDefinitions[0] - if subscription.OperationType != ast.OperationTypeSubscription { - panic("want OperationTypeSubscription") - } - }) - }) - - t.Run("operation with comments everywhere", func(t *testing.T) { - run(` - query #comment - findUser#comment - (#comment - $userId#comment - :#comment - ID#comment - !#comment - #comment - )#comment - {#comment - user#comment - (#comment - id#comment - :#comment - $userId#comment - #comment - )#comment - #comment - {#comment - ...#comment - UserFields#comment - ... #comment - on #comment - User#comment - {#comment - email#comment - }#comment - }#comment - }#comment - - fragment #comment - UserFields #comment - on #comment - User#comment - {#comment - id#comment - #username#comment - role#comment - }#comment`, parse, false) - }) - }) - t.Run("variable definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`($devicePicSize: Int = 1 $var2: String)`, parseVariableDefinitionList, false, - func(doc *ast.Document, extra interface{}) { - list := extra.(ast.VariableDefinitionList) - - var1 := doc.VariableDefinitions[list.Refs[0]] - devicePicSize := doc.VariableValues[var1.VariableValue.Ref] - if doc.Input.ByteSliceString(devicePicSize.Name) != "devicePicSize" { - panic("want devicePicSize") - } - Int := doc.Types[var1.Type] - if Int.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(Int.Name) != "Int" { - panic("want Int") - } - if !var1.DefaultValue.IsDefined { - panic("want true") - } - if var1.DefaultValue.Value.Kind != ast.ValueKindInteger { - panic("want ValueKindInteger") - } - one := doc.IntValues[var1.DefaultValue.Value.Ref] - if doc.Input.ByteSliceString(one.Raw) != "1" { - panic("want 1") - } - - var2 := doc.VariableDefinitions[list.Refs[1]] - var2Variable := doc.VariableValues[var2.VariableValue.Ref] - if doc.Input.ByteSliceString(var2Variable.Name) != "var2" { - panic("want var2") - } - String := doc.Types[var2.Type] - if String.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(String.Name) != "String" { - panic("want String") - } - - if len(list.Refs) != 2 { - panic("want 2") - } - }) - }) - }) - t.Run("selection set", func(t *testing.T) { - t.Run("No 8", func(t *testing.T) { - run(`{ - me { - ... on Person @foo { - personID - } - ...personFragment @bar - id - firstName - lastName - birthday { - month - day - } - friends { - name - } - } - }`, parseSelectionSet, false, - func(doc *ast.Document, extra interface{}) { - set := doc.SelectionSets[extra.(int)] - - // me - meSelection := doc.Selections[set.SelectionRefs[0]] - if meSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - me := doc.Fields[meSelection.Ref] - if doc.Input.ByteSliceString(me.Name) != "me" { - panic("want me") - } - - // ... on Person - - onPersonSelection := doc.Selections[doc.SelectionSets[me.SelectionSet].SelectionRefs[0]] - if onPersonSelection.Kind != ast.SelectionKindInlineFragment { - panic("want SelectionKindInlineFragment") - } - onPersonFragment := doc.InlineFragments[onPersonSelection.Ref] - if len(onPersonFragment.Directives.Refs) != 1 { - panic("want 1") - } - Person := doc.Types[onPersonFragment.TypeCondition.Type] - if doc.Input.ByteSliceString(Person.Name) != "Person" { - panic("want Person") - } - personIdSelection := doc.Selections[doc.SelectionSets[onPersonFragment.SelectionSet].SelectionRefs[0]] - if personIdSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - personId := doc.Fields[personIdSelection.Ref] - if doc.Input.ByteSliceString(personId.Name) != "personID" { - panic("want personID") - } - if personId.Position.LineStart != 4 || personId.Position.CharStart != 10 { - panic("want correct position for a person id field") - } - - // ...personFragment - personFragmentSelection := doc.Selections[doc.SelectionSets[me.SelectionSet].SelectionRefs[1]] - if personFragmentSelection.Kind != ast.SelectionKindFragmentSpread { - panic("want SelectionKindFragmentSpread") - } - personFragment := doc.FragmentSpreads[personFragmentSelection.Ref] - if doc.Input.ByteSliceString(personFragment.FragmentName) != "personFragment" { - panic("want personFragment") - } - if len(personFragment.Directives.Refs) != 1 { - panic("want 1") - } - - // id - idSelection := doc.Selections[doc.SelectionSets[me.SelectionSet].SelectionRefs[2]] - if idSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - id := doc.Fields[idSelection.Ref] - if doc.Input.ByteSliceString(id.Name) != "id" { - panic("want id") - } - - // birthday - birthdaySelection := doc.Selections[doc.SelectionSets[me.SelectionSet].SelectionRefs[5]] - if birthdaySelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - birthday := doc.Fields[birthdaySelection.Ref] - if doc.Input.ByteSliceString(birthday.Name) != "birthday" { - panic("want birthday") - } - - // month - monthSelection := doc.Selections[doc.SelectionSets[birthday.SelectionSet].SelectionRefs[0]] - if monthSelection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - month := doc.Fields[monthSelection.Ref] - if doc.Input.ByteSliceString(month.Name) != "month" { - panic("want month") - } - }) - }) - }) - t.Run("fragment spread", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`friendFields @foo`, parseFragmentSpread, false, - func(doc *ast.Document, extra interface{}) { - fragmentSpread := extra.(ast.FragmentSpread) - if doc.Input.ByteSliceString(fragmentSpread.FragmentName) != "friendFields" { - panic("want friendFields") - } - if len(fragmentSpread.Directives.Refs) != 1 { - panic("want 1") - } - }) - }) - t.Run("report fragment name must not be on", func(t *testing.T) { - run(`on`, parseFragmentSpread, true) - }) - }) - t.Run("inline fragment", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`on User { - friends { - count - } - }`, parseInlineFragment, false, - func(doc *ast.Document, extra interface{}) { - fragment := extra.(ast.InlineFragment) - user := doc.Types[fragment.TypeCondition.Type] - if user.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(user.Name) != "User" { - panic("want User") - } - - selection := doc.Selections[doc.SelectionSets[fragment.SelectionSet].SelectionRefs[0]] - if selection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - friends := doc.Fields[selection.Ref] - if doc.Input.ByteSliceString(friends.Name) != "friends" { - panic("want friends") - } - - selection = doc.Selections[doc.SelectionSets[friends.SelectionSet].SelectionRefs[0]] - if selection.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - count := doc.Fields[selection.Ref] - if doc.Input.ByteSliceString(count.Name) != "count" { - panic("want count") - } - }) - }) - }) - t.Run("fragment definition", func(t *testing.T) { - t.Run("simple", func(t *testing.T) { - run(`fragment friendFields on User { - id - name - profilePic(size: 50) - }`, parse, false, - func(doc *ast.Document, extra interface{}) { - fragment := doc.FragmentDefinitions[0] - if doc.Input.ByteSliceString(fragment.Name) != "friendFields" { - panic("want friendFields") - } - onUser := doc.Types[fragment.TypeCondition.Type] - if onUser.TypeKind != ast.TypeKindNamed { - panic("want TypeKindNamed") - } - if doc.Input.ByteSliceString(onUser.Name) != "User" { - panic("want User") - } - - selection1 := doc.Selections[doc.SelectionSets[fragment.SelectionSet].SelectionRefs[0]] - if selection1.Kind != ast.SelectionKindField { - panic("want SelectionKindField") - } - id := doc.Fields[selection1.Ref] - if doc.Input.ByteSliceString(id.Name) != "id" { - panic("want id") - } - }) - }) - }) - t.Run("index", func(t *testing.T) { - run(` - schema { - query: Query - mutation: Mutation - subscription: Subscription - } - scalar Scalar1 {} - scalar Scalar2 {} - type Type1 {} - type Type2 {} - interface Iface1 {} - interface Iface2 {} - input Input1 {} - input Input2 {} - union Union1 - union Union2 - enum Enum1 {} - enum Enum2 {} - directive @directive1 on FIELD - directive @directive2 on FIELD - `, parse, false, - func(doc *ast.Document, extra interface{}) { - if string(doc.Index.QueryTypeName) != "Query" { - panic("want Query") - } - if string(doc.Index.MutationTypeName) != "Mutation" { - panic("want mutation") - } - if string(doc.Index.SubscriptionTypeName) != "Subscription" { - panic("want Subscription") - } - }, - wantIndexedNode("Scalar1", ast.NodeKindScalarTypeDefinition), - wantIndexedNode("Scalar2", ast.NodeKindScalarTypeDefinition), - wantIndexedNode("Type1", ast.NodeKindObjectTypeDefinition), - wantIndexedNode("Type2", ast.NodeKindObjectTypeDefinition), - wantIndexedNode("Iface1", ast.NodeKindInterfaceTypeDefinition), - wantIndexedNode("Iface2", ast.NodeKindInterfaceTypeDefinition), - wantIndexedNode("Input1", ast.NodeKindInputObjectTypeDefinition), - wantIndexedNode("Input2", ast.NodeKindInputObjectTypeDefinition), - wantIndexedNode("Union1", ast.NodeKindUnionTypeDefinition), - wantIndexedNode("Union2", ast.NodeKindUnionTypeDefinition), - wantIndexedNode("Enum1", ast.NodeKindEnumTypeDefinition), - wantIndexedNode("Enum2", ast.NodeKindEnumTypeDefinition), - wantIndexedNode("directive1", ast.NodeKindDirectiveDefinition), - wantIndexedNode("directive2", ast.NodeKindDirectiveDefinition), - ) - }) -} - -func TestErrorReport(t *testing.T) { - t.Run("missing ident", func(t *testing.T) { - _, report := ParseGraphqlDocumentString(` - { - me { - ... on Person @foo { - personID: - } - } - } - `) - - if !report.HasErrors() { - t.Fatalf("want err, got nil") - } - - want := "external: unexpected token - got: RBRACE want one of: [IDENT], locations: [{Line:6 Column:6}], path: []" - if report.Error() != want { - t.Fatalf("want:\n%s\ngot:\n%s\n", want, report.Error()) - } - }) - t.Run("at instead of on", func(t *testing.T) { - _, report := ParseGraphqlDocumentString(` - { - me { - ... on @Person @foo { - personID - } - } - } - `) - - if !report.HasErrors() { - t.Fatalf("want err, got nil") - } - - want := "external: unexpected token - got: AT want one of: [IDENT], locations: [{Line:4 Column:13}], path: []" - if report.Error() != want { - t.Fatalf("want:\n%s\ngot:\n%s\n", want, report.Error()) - } - }) -} - -func TestParseStarwars(t *testing.T) { - - starWarsSchema, err := os.ReadFile("./testdata/starwars.schema.graphql") - if err != nil { - t.Fatal(err) - } - - _, report := ParseGraphqlDocumentBytes(starWarsSchema) - if report.HasErrors() { - t.Fatal(report) - } -} - -func TestParseTodo(t *testing.T) { - - inputFileName := "./testdata/todo.graphql" - schema, err := os.ReadFile(inputFileName) - if err != nil { - t.Fatal(err) - } - - doc, report := ParseGraphqlDocumentBytes(schema) - if report.HasErrors() { - t.Fatal(report) - } - - _ = doc -} - -func BenchmarkParseStarwars(b *testing.B) { - - inputFileName := "./testdata/starwars.schema.graphql" - starwarsSchema, err := os.ReadFile(inputFileName) - if err != nil { - b.Fatal(err) - } - - doc := ast.NewDocument() - report := operationreport.Report{} - parser := NewParser() - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(starwarsSchema))) - - for i := 0; i < b.N; i++ { - doc.Reset() - doc.Input.ResetInputBytes(starwarsSchema) - report.Reset() - parser.Parse(doc, &report) - if report.HasErrors() { - b.Fatal(report.Error()) - } - } -} - -func BenchmarkParseGithub(b *testing.B) { - - inputFileName := "./testdata/github.schema.graphql" - schemaFile, err := os.ReadFile(inputFileName) - if err != nil { - b.Fatal(err) - } - - doc := ast.NewDocument() - report := operationreport.Report{} - parser := NewParser() - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(schemaFile))) - - for i := 0; i < b.N; i++ { - doc.Reset() - doc.Input.ResetInputBytes(schemaFile) - parser.Parse(doc, &report) - if report.HasErrors() { - b.Fatal(report.Error()) - } - } -} - -func BenchmarkSelectionSet(b *testing.B) { - - doc := ast.NewDocument() - parser := NewParser() - report := operationreport.Report{} - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(selectionSet))) - - for i := 0; i < b.N; i++ { - doc.Reset() - doc.Input.ResetInputBytes(selectionSet) - report.Reset() - parser.Parse(doc, &report) - if report.HasErrors() { - b.Fatal(report.Error()) - } - } -} - -func BenchmarkIntrospectionQuery(b *testing.B) { - - doc := ast.NewDocument() - parser := NewParser() - report := operationreport.Report{} - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(introspectionQuery))) - - for i := 0; i < b.N; i++ { - doc.Reset() - doc.Input.ResetInputBytes(introspectionQuery) - parser.Parse(doc, &report) - if report.HasErrors() { - b.Fatal(report.Error()) - } - } -} - -func BenchmarkKitchenSink(b *testing.B) { - - doc := ast.NewDocument() - parser := NewParser() - report := operationreport.Report{} - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(kitchenSinkData))) - - for i := 0; i < b.N; i++ { - doc.Reset() - doc.Input.ResetInputBytes(kitchenSinkData) - report.Reset() - parser.Parse(doc, &report) - } -} - -func BenchmarkParse(b *testing.B) { - - doc := ast.NewDocument() - parser := NewParser() - report := operationreport.Report{} - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(inputBytes))) - - for i := 0; i < b.N; i++ { - doc.Reset() - doc.Input.ResetInputBytes(inputBytes) - parser.Parse(doc, &report) - if report.HasErrors() { - b.Fatal(report.Error()) - } - } -} - -var selectionSet = []byte(`{ - me { - ... on Person @foo { - personID - } - ...personFragment @bar - id - firstName - lastName - birthday { - month - day - } - friends { - name - } - } - }`) - -var inputBytes = []byte(` schema @foo @bar(baz: "bal") { - query: Query - mutation: Mutation - subscription: Subscription - } - - """ - Person type description - """ - type Person implements Foo & Bar { - name: String - "age of the person" - age: Int - """ - date of birth - """ - dateOfBirth: Date - } - - type PersonWithArgs { - "name description" - name( - a: String! - "b description" - b: Int - """ - c description - """ - c: Float - ): String - } - - "scalars" - scalar JSON - - "inputs" - input Person { - name: String = "Gopher" - } - - "unions" - union SearchResult = Photo | Person - - "interfaces" - interface NamedEntity @foo { - name: String - } - - "enums" - enum Direction { - NORTH - EAST - SOUTH - WEST - } - - "directives" - directive @example on FIELD | SCALAR | SCHEMA - - query MyQuery { - me { - ... on Person @foo { - personID - } - ...personFragment @bar - id - firstName - lastName - birthday { - month - day - } - friends { - name - } - } - } -`) - -var kitchenSinkData = []byte(`# Copyright (c) 2015-present, Facebook, Inc. -# -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -query queryName($foo: ComplexType, $site: Site = MOBILE) { - whoever123is: node(id: [123, 456]) { - id , - ... on User @defer { - field2 { - id , - alias: field1(first:10, after:$foo,) @include(if: $foo) { - id, - ...frag - } - } - } - ... @skip(unless: $foo) { - id - } - ... { - id - } - } -} - -mutation likeStory { - like(story: 123) @defer { - story { - id - } - } -} - -subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) { - storyLikeSubscribe(input: $input) { - story { - likers { - count - } - likeSentence { - text - } - } - } -} - -fragment frag on Friend { - foo(size: $size, bar: $b, obj: {key: "value", block: """ - - block string uses \""" - - """}) -} - -{ - unnamed(truthy: true, falsey: false, nullish: null), - query -} -`) - -var introspectionQuery = []byte(`query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -}`) diff --git a/pkg/astparser/parser_token_helpers.go b/pkg/astparser/parser_token_helpers.go deleted file mode 100644 index c8f0cdd14..000000000 --- a/pkg/astparser/parser_token_helpers.go +++ /dev/null @@ -1,90 +0,0 @@ -package astparser - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/identkeyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/token" -) - -// read - reads and returns next token -func (p *Parser) read() token.Token { - return p.tokenizer.Read() -} - -// peek - returns token next to currentToken -// returns keyword.EOF when reached end of document -func (p *Parser) peek() keyword.Keyword { - tok := p.tokenizer.Peek() - return tok.Keyword -} - -// peekLiteral - returns keyword.Keyword and literal ast.ByteSliceReference of token next to currentToken -// returns keyword.EOF when reached end of document -func (p *Parser) peekLiteral() (keyword.Keyword, ast.ByteSliceReference) { - tok := p.tokenizer.Peek() - if tok.Keyword != keyword.EOF { - return tok.Keyword, tok.Literal - } - return keyword.EOF, ast.ByteSliceReference{} -} - -// peekEquals - checks that next token keyword is equal to key -func (p *Parser) peekEquals(key keyword.Keyword) bool { - return p.peek() == key -} - -// peekEqualsIdentKey - checks that next token is an identifier of the given key -func (p *Parser) peekEqualsIdentKey(identKey identkeyword.IdentKeyword) bool { - key, literal := p.peekLiteral() - if key != keyword.IDENT { - return false - } - actualKey := p.identKeywordSliceRef(literal) - return actualKey == identKey -} - -func (p *Parser) mustRead(key keyword.Keyword) (next token.Token) { - next = p.read() - if next.Keyword != key { - p.errUnexpectedToken(next, key) - } - return -} - -func (p *Parser) mustReadIdentKey(key identkeyword.IdentKeyword) (next token.Token) { - next = p.read() - if next.Keyword != keyword.IDENT { - p.errUnexpectedToken(next, keyword.IDENT) - } - identKey := p.identKeywordToken(next) - if identKey != key { - p.errUnexpectedIdentKey(next, identKey, key) - } - return -} - -func (p *Parser) mustReadExceptIdentKey(key identkeyword.IdentKeyword) (next token.Token) { - next = p.read() - if next.Keyword != keyword.IDENT { - p.errUnexpectedToken(next, keyword.IDENT) - } - identKey := p.identKeywordToken(next) - if identKey == key { - p.errUnexpectedIdentKey(next, identKey, key) - } - return -} - -func (p *Parser) mustReadOneOf(keys ...identkeyword.IdentKeyword) (token.Token, identkeyword.IdentKeyword) { - next := p.read() - - identKey := p.identKeywordToken(next) - for _, expectation := range keys { - if identKey == expectation { - return next, identKey - } - } - p.errUnexpectedToken(next) - return next, identKey -} diff --git a/pkg/astparser/testdata/big_schema.graphql b/pkg/astparser/testdata/big_schema.graphql deleted file mode 100644 index b60bc84e3..000000000 --- a/pkg/astparser/testdata/big_schema.graphql +++ /dev/null @@ -1,16688 +0,0 @@ -type AggregateAlphazap { - count: Int! -} - -type AggregateAsset { - count: Int! -} - -type AggregateBamity { - count: Int! -} - -type AggregateBigtax { - count: Int! -} - -type AggregateColor { - count: Int! -} - -type AggregateDaltfresh { - count: Int! -} - -type AggregateHatity { - count: Int! -} - -type AggregateJob { - count: Int! -} - -type AggregateKeylex { - count: Int! -} - -type AggregateKonklab { - count: Int! -} - -type AggregateKonklux { - count: Int! -} - -type AggregateLatlux { - count: Int! -} - -type AggregateLocation { - count: Int! -} - -type AggregateLotlux { - count: Int! -} - -type AggregateLotstring { - count: Int! -} - -type AggregateOtcom { - count: Int! -} - -type AggregateOverhold { - count: Int! -} - -type AggregateRedhold { - count: Int! -} - -type AggregateRonstring { - count: Int! -} - -type AggregateSonair { - count: Int! -} - -type AggregateSonsing { - count: Int! -} - -type AggregateStim { - count: Int! -} - -type AggregateStringtough { - count: Int! -} - -type AggregateStronghold { - count: Int! -} - -type AggregateSubin { - count: Int! -} - -type AggregateTemp { - count: Int! -} - -type AggregateToughjoyfax { - count: Int! -} - -type AggregateTranscof { - count: Int! -} - -type AggregateTreeflex { - count: Int! -} - -type AggregateTresom { - count: Int! -} - -type AggregateVentosanzap { - count: Int! -} - -type AggregateViva { - count: Int! -} - -type AggregateVoltsillam { - count: Int! -} - -type AggregateVoyatouch { - count: Int! -} - -type AggregateZamit { - count: Int! -} - -type AggregateZathin { - count: Int! -} - -type AggregateZoolab { - count: Int! -} - -type Alphazap implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - indigo: [Daugherty!]! - salmon: [Harris!]! - turquoise: [Muller!]! - azure( - where: TresomWhereInput - orderBy: TresomOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Tresom!] -} - -# A connection to a list of items. -type AlphazapConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [AlphazapEdge]! - aggregate: AggregateAlphazap! -} - -input AlphazapCreateindigoInput { - set: [Daugherty!] -} - -input AlphazapCreateInput { - status: Status - indigo: AlphazapCreateindigoInput - salmon: AlphazapCreatesalmonInput - turquoise: AlphazapCreateturquoiseInput - azure: TresomCreateManyWithoutTealInput -} - -input AlphazapCreateOneWithoutAzureInput { - create: AlphazapCreateWithoutAzureInput - connect: AlphazapWhereUniqueInput -} - -input AlphazapCreatesalmonInput { - set: [Harris!] -} - -input AlphazapCreateturquoiseInput { - set: [Muller!] -} - -input AlphazapCreateWithoutAzureInput { - status: Status - indigo: AlphazapCreateindigoInput - salmon: AlphazapCreatesalmonInput - turquoise: AlphazapCreateturquoiseInput -} - -# An edge in a connection. -type AlphazapEdge { - # The item at the end of the edge. - node: Alphazap! - # A cursor for use in pagination. - cursor: String! -} - -enum AlphazapOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC -} - -type AlphazapPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - indigo: [Daugherty!]! - salmon: [Harris!]! - turquoise: [Muller!]! -} - -type AlphazapSubscriptionPayload { - mutation: MutationType! - node: Alphazap - updatedFields: [String!] - previousValues: AlphazapPreviousValues -} - -input AlphazapSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [AlphazapSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [AlphazapSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [AlphazapSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: AlphazapWhereInput -} - -input AlphazapUpdateindigoInput { - set: [Daugherty!] -} - -input AlphazapUpdateInput { - status: Status - indigo: AlphazapUpdateindigoInput - salmon: AlphazapUpdatesalmonInput - turquoise: AlphazapUpdateturquoiseInput - azure: TresomUpdateManyWithoutTealInput -} - -input AlphazapUpdateManyMutationInput { - status: Status - indigo: AlphazapUpdateindigoInput - salmon: AlphazapUpdatesalmonInput - turquoise: AlphazapUpdateturquoiseInput -} - -input AlphazapUpdateOneWithoutAzureInput { - create: AlphazapCreateWithoutAzureInput - connect: AlphazapWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AlphazapUpdateWithoutAzureDataInput - upsert: AlphazapUpsertWithoutAzureInput -} - -input AlphazapUpdatesalmonInput { - set: [Harris!] -} - -input AlphazapUpdateturquoiseInput { - set: [Muller!] -} - -input AlphazapUpdateWithoutAzureDataInput { - status: Status - indigo: AlphazapUpdateindigoInput - salmon: AlphazapUpdatesalmonInput - turquoise: AlphazapUpdateturquoiseInput -} - -input AlphazapUpsertWithoutAzureInput { - update: AlphazapUpdateWithoutAzureDataInput! - create: AlphazapCreateWithoutAzureInput! -} - -input AlphazapWhereInput { - # Logical AND on all given filters. - AND: [AlphazapWhereInput!] - # Logical OR on all given filters. - OR: [AlphazapWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [AlphazapWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - azure_every: TresomWhereInput - azure_some: TresomWhereInput - azure_none: TresomWhereInput -} - -input AlphazapWhereUniqueInput { - id: ID -} - -type Asset implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp( - where: TempWhereInput - orderBy: TempOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Temp!] - goldLotstring( - where: LotstringWhereInput - orderBy: LotstringOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Lotstring!] - maroonDaltfresh( - where: DaltfreshWhereInput - orderBy: DaltfreshOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Daltfresh!] - greenStronghold( - where: StrongholdWhereInput - orderBy: StrongholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stronghold!] - tealStronghold( - where: StrongholdWhereInput - orderBy: StrongholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stronghold!] - silverStronghold( - where: StrongholdWhereInput - orderBy: StrongholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stronghold!] - lavenderStronghold( - where: StrongholdWhereInput - orderBy: StrongholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stronghold!] - goldOtcom( - where: OtcomWhereInput - orderBy: OtcomOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Otcom!] - greyZamit( - where: ZamitWhereInput - orderBy: ZamitOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Zamit!] - # Get the url for the asset with provided transformations applied. - url(transformation: AssetTransformationInput): String! -} - -# A connection to a list of items. -type AssetConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [AssetEdge]! - aggregate: AggregateAsset! -} - -input AssetCreateInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateManyWithoutGoldLotstringInput { - create: [AssetCreateWithoutGoldLotstringInput!] - connect: [AssetWhereUniqueInput!] -} - -input AssetCreateOneWithoutGoldOtcomInput { - create: AssetCreateWithoutGoldOtcomInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutGreenStrongholdInput { - create: AssetCreateWithoutGreenStrongholdInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutGreyZamitInput { - create: AssetCreateWithoutGreyZamitInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutLavenderStrongholdInput { - create: AssetCreateWithoutLavenderStrongholdInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutMaroonDaltfreshInput { - create: AssetCreateWithoutMaroonDaltfreshInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutOliveTempInput { - create: AssetCreateWithoutOliveTempInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutSilverStrongholdInput { - create: AssetCreateWithoutSilverStrongholdInput - connect: AssetWhereUniqueInput -} - -input AssetCreateOneWithoutTealStrongholdInput { - create: AssetCreateWithoutTealStrongholdInput - connect: AssetWhereUniqueInput -} - -input AssetCreateWithoutGoldLotstringInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutGoldOtcomInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutGreenStrongholdInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutGreyZamitInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput -} - -input AssetCreateWithoutLavenderStrongholdInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutMaroonDaltfreshInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutOliveTempInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutSilverStrongholdInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - tealStronghold: StrongholdCreateManyWithoutTealInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -input AssetCreateWithoutTealStrongholdInput { - status: Status - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempCreateManyWithoutOliveInput - goldLotstring: LotstringCreateManyWithoutGoldInput - maroonDaltfresh: DaltfreshCreateManyWithoutMaroonInput - greenStronghold: StrongholdCreateManyWithoutGreenInput - silverStronghold: StrongholdCreateManyWithoutSilverInput - lavenderStronghold: StrongholdCreateManyWithoutLavenderInput - goldOtcom: OtcomCreateManyWithoutGoldInput - greyZamit: ZamitCreateManyWithoutGreyInput -} - -# An edge in a connection. -type AssetEdge { - # The item at the end of the edge. - node: Asset! - # A cursor for use in pagination. - cursor: String! -} - -enum AssetOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - handle_ASC - handle_DESC - fileName_ASC - fileName_DESC - height_ASC - height_DESC - width_ASC - width_DESC - size_ASC - size_DESC - mimeType_ASC - mimeType_DESC -} - -type AssetPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - handle: String! - fileName: String! - height: Float - width: Float - size: Float - mimeType: String -} - -input AssetScalarWhereInput { - # Logical AND on all given filters. - AND: [AssetScalarWhereInput!] - # Logical OR on all given filters. - OR: [AssetScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [AssetScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - handle: String - # All values that are not equal to given value. - handle_not: String - # All values that are contained in given list. - handle_in: [String!] - # All values that are not contained in given list. - handle_not_in: [String!] - # All values less than the given value. - handle_lt: String - # All values less than or equal the given value. - handle_lte: String - # All values greater than the given value. - handle_gt: String - # All values greater than or equal the given value. - handle_gte: String - # All values containing the given string. - handle_contains: String - # All values not containing the given string. - handle_not_contains: String - # All values starting with the given string. - handle_starts_with: String - # All values not starting with the given string. - handle_not_starts_with: String - # All values ending with the given string. - handle_ends_with: String - # All values not ending with the given string. - handle_not_ends_with: String - fileName: String - # All values that are not equal to given value. - fileName_not: String - # All values that are contained in given list. - fileName_in: [String!] - # All values that are not contained in given list. - fileName_not_in: [String!] - # All values less than the given value. - fileName_lt: String - # All values less than or equal the given value. - fileName_lte: String - # All values greater than the given value. - fileName_gt: String - # All values greater than or equal the given value. - fileName_gte: String - # All values containing the given string. - fileName_contains: String - # All values not containing the given string. - fileName_not_contains: String - # All values starting with the given string. - fileName_starts_with: String - # All values not starting with the given string. - fileName_not_starts_with: String - # All values ending with the given string. - fileName_ends_with: String - # All values not ending with the given string. - fileName_not_ends_with: String - height: Float - # All values that are not equal to given value. - height_not: Float - # All values that are contained in given list. - height_in: [Float!] - # All values that are not contained in given list. - height_not_in: [Float!] - # All values less than the given value. - height_lt: Float - # All values less than or equal the given value. - height_lte: Float - # All values greater than the given value. - height_gt: Float - # All values greater than or equal the given value. - height_gte: Float - width: Float - # All values that are not equal to given value. - width_not: Float - # All values that are contained in given list. - width_in: [Float!] - # All values that are not contained in given list. - width_not_in: [Float!] - # All values less than the given value. - width_lt: Float - # All values less than or equal the given value. - width_lte: Float - # All values greater than the given value. - width_gt: Float - # All values greater than or equal the given value. - width_gte: Float - size: Float - # All values that are not equal to given value. - size_not: Float - # All values that are contained in given list. - size_in: [Float!] - # All values that are not contained in given list. - size_not_in: [Float!] - # All values less than the given value. - size_lt: Float - # All values less than or equal the given value. - size_lte: Float - # All values greater than the given value. - size_gt: Float - # All values greater than or equal the given value. - size_gte: Float - mimeType: String - # All values that are not equal to given value. - mimeType_not: String - # All values that are contained in given list. - mimeType_in: [String!] - # All values that are not contained in given list. - mimeType_not_in: [String!] - # All values less than the given value. - mimeType_lt: String - # All values less than or equal the given value. - mimeType_lte: String - # All values greater than the given value. - mimeType_gt: String - # All values greater than or equal the given value. - mimeType_gte: String - # All values containing the given string. - mimeType_contains: String - # All values not containing the given string. - mimeType_not_contains: String - # All values starting with the given string. - mimeType_starts_with: String - # All values not starting with the given string. - mimeType_not_starts_with: String - # All values ending with the given string. - mimeType_ends_with: String - # All values not ending with the given string. - mimeType_not_ends_with: String -} - -type AssetSubscriptionPayload { - mutation: MutationType! - node: Asset - updatedFields: [String!] - previousValues: AssetPreviousValues -} - -input AssetSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [AssetSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [AssetSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [AssetSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: AssetWhereInput -} - -# Transformations for Assets -input AssetTransformationInput { - image: ImageTransformationInput - document: DocumentTransformationInput - # Pass `true` if you want to validate the passed transformation parameters - validateOptions: Boolean = false -} - -input AssetUpdateInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateManyDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String -} - -input AssetUpdateManyMutationInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String -} - -input AssetUpdateManyWithoutGoldLotstringInput { - create: [AssetCreateWithoutGoldLotstringInput!] - connect: [AssetWhereUniqueInput!] - set: [AssetWhereUniqueInput!] - disconnect: [AssetWhereUniqueInput!] - delete: [AssetWhereUniqueInput!] - update: [AssetUpdateWithWhereUniqueWithoutGoldLotstringInput!] - updateMany: [AssetUpdateManyWithWhereNestedInput!] - deleteMany: [AssetScalarWhereInput!] - upsert: [AssetUpsertWithWhereUniqueWithoutGoldLotstringInput!] -} - -input AssetUpdateManyWithWhereNestedInput { - where: AssetScalarWhereInput! - data: AssetUpdateManyDataInput! -} - -input AssetUpdateOneWithoutGoldOtcomInput { - create: AssetCreateWithoutGoldOtcomInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutGoldOtcomDataInput - upsert: AssetUpsertWithoutGoldOtcomInput -} - -input AssetUpdateOneWithoutGreenStrongholdInput { - create: AssetCreateWithoutGreenStrongholdInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutGreenStrongholdDataInput - upsert: AssetUpsertWithoutGreenStrongholdInput -} - -input AssetUpdateOneWithoutGreyZamitInput { - create: AssetCreateWithoutGreyZamitInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutGreyZamitDataInput - upsert: AssetUpsertWithoutGreyZamitInput -} - -input AssetUpdateOneWithoutLavenderStrongholdInput { - create: AssetCreateWithoutLavenderStrongholdInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutLavenderStrongholdDataInput - upsert: AssetUpsertWithoutLavenderStrongholdInput -} - -input AssetUpdateOneWithoutMaroonDaltfreshInput { - create: AssetCreateWithoutMaroonDaltfreshInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutMaroonDaltfreshDataInput - upsert: AssetUpsertWithoutMaroonDaltfreshInput -} - -input AssetUpdateOneWithoutOliveTempInput { - create: AssetCreateWithoutOliveTempInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutOliveTempDataInput - upsert: AssetUpsertWithoutOliveTempInput -} - -input AssetUpdateOneWithoutSilverStrongholdInput { - create: AssetCreateWithoutSilverStrongholdInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutSilverStrongholdDataInput - upsert: AssetUpsertWithoutSilverStrongholdInput -} - -input AssetUpdateOneWithoutTealStrongholdInput { - create: AssetCreateWithoutTealStrongholdInput - connect: AssetWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: AssetUpdateWithoutTealStrongholdDataInput - upsert: AssetUpsertWithoutTealStrongholdInput -} - -input AssetUpdateWithoutGoldLotstringDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutGoldOtcomDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutGreenStrongholdDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutGreyZamitDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput -} - -input AssetUpdateWithoutLavenderStrongholdDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutMaroonDaltfreshDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutOliveTempDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutSilverStrongholdDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - tealStronghold: StrongholdUpdateManyWithoutTealInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithoutTealStrongholdDataInput { - status: Status - handle: String - fileName: String - height: Float - width: Float - size: Float - mimeType: String - oliveTemp: TempUpdateManyWithoutOliveInput - goldLotstring: LotstringUpdateManyWithoutGoldInput - maroonDaltfresh: DaltfreshUpdateManyWithoutMaroonInput - greenStronghold: StrongholdUpdateManyWithoutGreenInput - silverStronghold: StrongholdUpdateManyWithoutSilverInput - lavenderStronghold: StrongholdUpdateManyWithoutLavenderInput - goldOtcom: OtcomUpdateManyWithoutGoldInput - greyZamit: ZamitUpdateManyWithoutGreyInput -} - -input AssetUpdateWithWhereUniqueWithoutGoldLotstringInput { - where: AssetWhereUniqueInput! - data: AssetUpdateWithoutGoldLotstringDataInput! -} - -input AssetUpsertWithoutGoldOtcomInput { - update: AssetUpdateWithoutGoldOtcomDataInput! - create: AssetCreateWithoutGoldOtcomInput! -} - -input AssetUpsertWithoutGreenStrongholdInput { - update: AssetUpdateWithoutGreenStrongholdDataInput! - create: AssetCreateWithoutGreenStrongholdInput! -} - -input AssetUpsertWithoutGreyZamitInput { - update: AssetUpdateWithoutGreyZamitDataInput! - create: AssetCreateWithoutGreyZamitInput! -} - -input AssetUpsertWithoutLavenderStrongholdInput { - update: AssetUpdateWithoutLavenderStrongholdDataInput! - create: AssetCreateWithoutLavenderStrongholdInput! -} - -input AssetUpsertWithoutMaroonDaltfreshInput { - update: AssetUpdateWithoutMaroonDaltfreshDataInput! - create: AssetCreateWithoutMaroonDaltfreshInput! -} - -input AssetUpsertWithoutOliveTempInput { - update: AssetUpdateWithoutOliveTempDataInput! - create: AssetCreateWithoutOliveTempInput! -} - -input AssetUpsertWithoutSilverStrongholdInput { - update: AssetUpdateWithoutSilverStrongholdDataInput! - create: AssetCreateWithoutSilverStrongholdInput! -} - -input AssetUpsertWithoutTealStrongholdInput { - update: AssetUpdateWithoutTealStrongholdDataInput! - create: AssetCreateWithoutTealStrongholdInput! -} - -input AssetUpsertWithWhereUniqueWithoutGoldLotstringInput { - where: AssetWhereUniqueInput! - update: AssetUpdateWithoutGoldLotstringDataInput! - create: AssetCreateWithoutGoldLotstringInput! -} - -input AssetWhereInput { - # Logical AND on all given filters. - AND: [AssetWhereInput!] - # Logical OR on all given filters. - OR: [AssetWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [AssetWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - handle: String - # All values that are not equal to given value. - handle_not: String - # All values that are contained in given list. - handle_in: [String!] - # All values that are not contained in given list. - handle_not_in: [String!] - # All values less than the given value. - handle_lt: String - # All values less than or equal the given value. - handle_lte: String - # All values greater than the given value. - handle_gt: String - # All values greater than or equal the given value. - handle_gte: String - # All values containing the given string. - handle_contains: String - # All values not containing the given string. - handle_not_contains: String - # All values starting with the given string. - handle_starts_with: String - # All values not starting with the given string. - handle_not_starts_with: String - # All values ending with the given string. - handle_ends_with: String - # All values not ending with the given string. - handle_not_ends_with: String - fileName: String - # All values that are not equal to given value. - fileName_not: String - # All values that are contained in given list. - fileName_in: [String!] - # All values that are not contained in given list. - fileName_not_in: [String!] - # All values less than the given value. - fileName_lt: String - # All values less than or equal the given value. - fileName_lte: String - # All values greater than the given value. - fileName_gt: String - # All values greater than or equal the given value. - fileName_gte: String - # All values containing the given string. - fileName_contains: String - # All values not containing the given string. - fileName_not_contains: String - # All values starting with the given string. - fileName_starts_with: String - # All values not starting with the given string. - fileName_not_starts_with: String - # All values ending with the given string. - fileName_ends_with: String - # All values not ending with the given string. - fileName_not_ends_with: String - height: Float - # All values that are not equal to given value. - height_not: Float - # All values that are contained in given list. - height_in: [Float!] - # All values that are not contained in given list. - height_not_in: [Float!] - # All values less than the given value. - height_lt: Float - # All values less than or equal the given value. - height_lte: Float - # All values greater than the given value. - height_gt: Float - # All values greater than or equal the given value. - height_gte: Float - width: Float - # All values that are not equal to given value. - width_not: Float - # All values that are contained in given list. - width_in: [Float!] - # All values that are not contained in given list. - width_not_in: [Float!] - # All values less than the given value. - width_lt: Float - # All values less than or equal the given value. - width_lte: Float - # All values greater than the given value. - width_gt: Float - # All values greater than or equal the given value. - width_gte: Float - size: Float - # All values that are not equal to given value. - size_not: Float - # All values that are contained in given list. - size_in: [Float!] - # All values that are not contained in given list. - size_not_in: [Float!] - # All values less than the given value. - size_lt: Float - # All values less than or equal the given value. - size_lte: Float - # All values greater than the given value. - size_gt: Float - # All values greater than or equal the given value. - size_gte: Float - mimeType: String - # All values that are not equal to given value. - mimeType_not: String - # All values that are contained in given list. - mimeType_in: [String!] - # All values that are not contained in given list. - mimeType_not_in: [String!] - # All values less than the given value. - mimeType_lt: String - # All values less than or equal the given value. - mimeType_lte: String - # All values greater than the given value. - mimeType_gt: String - # All values greater than or equal the given value. - mimeType_gte: String - # All values containing the given string. - mimeType_contains: String - # All values not containing the given string. - mimeType_not_contains: String - # All values starting with the given string. - mimeType_starts_with: String - # All values not starting with the given string. - mimeType_not_starts_with: String - # All values ending with the given string. - mimeType_ends_with: String - # All values not ending with the given string. - mimeType_not_ends_with: String - oliveTemp_every: TempWhereInput - oliveTemp_some: TempWhereInput - oliveTemp_none: TempWhereInput - goldLotstring_every: LotstringWhereInput - goldLotstring_some: LotstringWhereInput - goldLotstring_none: LotstringWhereInput - maroonDaltfresh_every: DaltfreshWhereInput - maroonDaltfresh_some: DaltfreshWhereInput - maroonDaltfresh_none: DaltfreshWhereInput - greenStronghold_every: StrongholdWhereInput - greenStronghold_some: StrongholdWhereInput - greenStronghold_none: StrongholdWhereInput - tealStronghold_every: StrongholdWhereInput - tealStronghold_some: StrongholdWhereInput - tealStronghold_none: StrongholdWhereInput - silverStronghold_every: StrongholdWhereInput - silverStronghold_some: StrongholdWhereInput - silverStronghold_none: StrongholdWhereInput - lavenderStronghold_every: StrongholdWhereInput - lavenderStronghold_some: StrongholdWhereInput - lavenderStronghold_none: StrongholdWhereInput - goldOtcom_every: OtcomWhereInput - goldOtcom_some: OtcomWhereInput - goldOtcom_none: OtcomWhereInput - greyZamit_every: ZamitWhereInput - greyZamit_some: ZamitWhereInput - greyZamit_none: ZamitWhereInput -} - -input AssetWhereUniqueInput { - id: ID - handle: String -} - -type Bamity implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - blue: DateTime - tan: DateTime - orange: Rice! - purple: String - maroon: Stronghold -} - -# A connection to a list of items. -type BamityConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [BamityEdge]! - aggregate: AggregateBamity! -} - -input BamityCreateInput { - status: Status - blue: DateTime - tan: DateTime - orange: Rice! - purple: String - maroon: StrongholdCreateOneWithoutOrchidInput -} - -input BamityCreateManyWithoutMaroonInput { - create: [BamityCreateWithoutMaroonInput!] - connect: [BamityWhereUniqueInput!] -} - -input BamityCreateWithoutMaroonInput { - status: Status - blue: DateTime - tan: DateTime - orange: Rice! - purple: String -} - -# An edge in a connection. -type BamityEdge { - # The item at the end of the edge. - node: Bamity! - # A cursor for use in pagination. - cursor: String! -} - -enum BamityOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - blue_ASC - blue_DESC - tan_ASC - tan_DESC - orange_ASC - orange_DESC - purple_ASC - purple_DESC -} - -type BamityPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - blue: DateTime - tan: DateTime - orange: Rice! - purple: String -} - -input BamityScalarWhereInput { - # Logical AND on all given filters. - AND: [BamityScalarWhereInput!] - # Logical OR on all given filters. - OR: [BamityScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [BamityScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - blue: DateTime - # All values that are not equal to given value. - blue_not: DateTime - # All values that are contained in given list. - blue_in: [DateTime!] - # All values that are not contained in given list. - blue_not_in: [DateTime!] - # All values less than the given value. - blue_lt: DateTime - # All values less than or equal the given value. - blue_lte: DateTime - # All values greater than the given value. - blue_gt: DateTime - # All values greater than or equal the given value. - blue_gte: DateTime - tan: DateTime - # All values that are not equal to given value. - tan_not: DateTime - # All values that are contained in given list. - tan_in: [DateTime!] - # All values that are not contained in given list. - tan_not_in: [DateTime!] - # All values less than the given value. - tan_lt: DateTime - # All values less than or equal the given value. - tan_lte: DateTime - # All values greater than the given value. - tan_gt: DateTime - # All values greater than or equal the given value. - tan_gte: DateTime - orange: Rice - # All values that are not equal to given value. - orange_not: Rice - # All values that are contained in given list. - orange_in: [Rice!] - # All values that are not contained in given list. - orange_not_in: [Rice!] - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String -} - -type BamitySubscriptionPayload { - mutation: MutationType! - node: Bamity - updatedFields: [String!] - previousValues: BamityPreviousValues -} - -input BamitySubscriptionWhereInput { - # Logical AND on all given filters. - AND: [BamitySubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [BamitySubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [BamitySubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: BamityWhereInput -} - -input BamityUpdateInput { - status: Status - blue: DateTime - tan: DateTime - orange: Rice - purple: String - maroon: StrongholdUpdateOneWithoutOrchidInput -} - -input BamityUpdateManyDataInput { - status: Status - blue: DateTime - tan: DateTime - orange: Rice - purple: String -} - -input BamityUpdateManyMutationInput { - status: Status - blue: DateTime - tan: DateTime - orange: Rice - purple: String -} - -input BamityUpdateManyWithoutMaroonInput { - create: [BamityCreateWithoutMaroonInput!] - connect: [BamityWhereUniqueInput!] - set: [BamityWhereUniqueInput!] - disconnect: [BamityWhereUniqueInput!] - delete: [BamityWhereUniqueInput!] - update: [BamityUpdateWithWhereUniqueWithoutMaroonInput!] - updateMany: [BamityUpdateManyWithWhereNestedInput!] - deleteMany: [BamityScalarWhereInput!] - upsert: [BamityUpsertWithWhereUniqueWithoutMaroonInput!] -} - -input BamityUpdateManyWithWhereNestedInput { - where: BamityScalarWhereInput! - data: BamityUpdateManyDataInput! -} - -input BamityUpdateWithoutMaroonDataInput { - status: Status - blue: DateTime - tan: DateTime - orange: Rice - purple: String -} - -input BamityUpdateWithWhereUniqueWithoutMaroonInput { - where: BamityWhereUniqueInput! - data: BamityUpdateWithoutMaroonDataInput! -} - -input BamityUpsertWithWhereUniqueWithoutMaroonInput { - where: BamityWhereUniqueInput! - update: BamityUpdateWithoutMaroonDataInput! - create: BamityCreateWithoutMaroonInput! -} - -input BamityWhereInput { - # Logical AND on all given filters. - AND: [BamityWhereInput!] - # Logical OR on all given filters. - OR: [BamityWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [BamityWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - blue: DateTime - # All values that are not equal to given value. - blue_not: DateTime - # All values that are contained in given list. - blue_in: [DateTime!] - # All values that are not contained in given list. - blue_not_in: [DateTime!] - # All values less than the given value. - blue_lt: DateTime - # All values less than or equal the given value. - blue_lte: DateTime - # All values greater than the given value. - blue_gt: DateTime - # All values greater than or equal the given value. - blue_gte: DateTime - tan: DateTime - # All values that are not equal to given value. - tan_not: DateTime - # All values that are contained in given list. - tan_in: [DateTime!] - # All values that are not contained in given list. - tan_not_in: [DateTime!] - # All values less than the given value. - tan_lt: DateTime - # All values less than or equal the given value. - tan_lte: DateTime - # All values greater than the given value. - tan_gt: DateTime - # All values greater than or equal the given value. - tan_gte: DateTime - orange: Rice - # All values that are not equal to given value. - orange_not: Rice - # All values that are contained in given list. - orange_in: [Rice!] - # All values that are not contained in given list. - orange_not_in: [Rice!] - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - maroon: StrongholdWhereInput -} - -input BamityWhereUniqueInput { - id: ID -} - -type BatchPayload { - # The number of nodes that have been affected by the Batch operation. - count: Long! -} - -type Bigtax implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - gold: String! - lime: String! - yellow( - where: VoyatouchWhereInput - orderBy: VoyatouchOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Voyatouch!] - azure: Int - tan: String - green: String -} - -# A connection to a list of items. -type BigtaxConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [BigtaxEdge]! - aggregate: AggregateBigtax! -} - -input BigtaxCreateInput { - status: Status - gold: String! - lime: String! - azure: Int - tan: String - green: String - yellow: VoyatouchCreateManyWithoutTanInput -} - -input BigtaxCreateManyWithoutYellowInput { - create: [BigtaxCreateWithoutYellowInput!] - connect: [BigtaxWhereUniqueInput!] -} - -input BigtaxCreateWithoutYellowInput { - status: Status - gold: String! - lime: String! - azure: Int - tan: String - green: String -} - -# An edge in a connection. -type BigtaxEdge { - # The item at the end of the edge. - node: Bigtax! - # A cursor for use in pagination. - cursor: String! -} - -enum BigtaxOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - gold_ASC - gold_DESC - lime_ASC - lime_DESC - azure_ASC - azure_DESC - tan_ASC - tan_DESC - green_ASC - green_DESC -} - -type BigtaxPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - gold: String! - lime: String! - azure: Int - tan: String - green: String -} - -input BigtaxScalarWhereInput { - # Logical AND on all given filters. - AND: [BigtaxScalarWhereInput!] - # Logical OR on all given filters. - OR: [BigtaxScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [BigtaxScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - gold: String - # All values that are not equal to given value. - gold_not: String - # All values that are contained in given list. - gold_in: [String!] - # All values that are not contained in given list. - gold_not_in: [String!] - # All values less than the given value. - gold_lt: String - # All values less than or equal the given value. - gold_lte: String - # All values greater than the given value. - gold_gt: String - # All values greater than or equal the given value. - gold_gte: String - # All values containing the given string. - gold_contains: String - # All values not containing the given string. - gold_not_contains: String - # All values starting with the given string. - gold_starts_with: String - # All values not starting with the given string. - gold_not_starts_with: String - # All values ending with the given string. - gold_ends_with: String - # All values not ending with the given string. - gold_not_ends_with: String - lime: String - # All values that are not equal to given value. - lime_not: String - # All values that are contained in given list. - lime_in: [String!] - # All values that are not contained in given list. - lime_not_in: [String!] - # All values less than the given value. - lime_lt: String - # All values less than or equal the given value. - lime_lte: String - # All values greater than the given value. - lime_gt: String - # All values greater than or equal the given value. - lime_gte: String - # All values containing the given string. - lime_contains: String - # All values not containing the given string. - lime_not_contains: String - # All values starting with the given string. - lime_starts_with: String - # All values not starting with the given string. - lime_not_starts_with: String - # All values ending with the given string. - lime_ends_with: String - # All values not ending with the given string. - lime_not_ends_with: String - azure: Int - # All values that are not equal to given value. - azure_not: Int - # All values that are contained in given list. - azure_in: [Int!] - # All values that are not contained in given list. - azure_not_in: [Int!] - # All values less than the given value. - azure_lt: Int - # All values less than or equal the given value. - azure_lte: Int - # All values greater than the given value. - azure_gt: Int - # All values greater than or equal the given value. - azure_gte: Int - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String -} - -type BigtaxSubscriptionPayload { - mutation: MutationType! - node: Bigtax - updatedFields: [String!] - previousValues: BigtaxPreviousValues -} - -input BigtaxSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [BigtaxSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [BigtaxSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [BigtaxSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: BigtaxWhereInput -} - -input BigtaxUpdateInput { - status: Status - gold: String - lime: String - azure: Int - tan: String - green: String - yellow: VoyatouchUpdateManyWithoutTanInput -} - -input BigtaxUpdateManyDataInput { - status: Status - gold: String - lime: String - azure: Int - tan: String - green: String -} - -input BigtaxUpdateManyMutationInput { - status: Status - gold: String - lime: String - azure: Int - tan: String - green: String -} - -input BigtaxUpdateManyWithoutYellowInput { - create: [BigtaxCreateWithoutYellowInput!] - connect: [BigtaxWhereUniqueInput!] - set: [BigtaxWhereUniqueInput!] - disconnect: [BigtaxWhereUniqueInput!] - delete: [BigtaxWhereUniqueInput!] - update: [BigtaxUpdateWithWhereUniqueWithoutYellowInput!] - updateMany: [BigtaxUpdateManyWithWhereNestedInput!] - deleteMany: [BigtaxScalarWhereInput!] - upsert: [BigtaxUpsertWithWhereUniqueWithoutYellowInput!] -} - -input BigtaxUpdateManyWithWhereNestedInput { - where: BigtaxScalarWhereInput! - data: BigtaxUpdateManyDataInput! -} - -input BigtaxUpdateWithoutYellowDataInput { - status: Status - gold: String - lime: String - azure: Int - tan: String - green: String -} - -input BigtaxUpdateWithWhereUniqueWithoutYellowInput { - where: BigtaxWhereUniqueInput! - data: BigtaxUpdateWithoutYellowDataInput! -} - -input BigtaxUpsertWithWhereUniqueWithoutYellowInput { - where: BigtaxWhereUniqueInput! - update: BigtaxUpdateWithoutYellowDataInput! - create: BigtaxCreateWithoutYellowInput! -} - -input BigtaxWhereInput { - # Logical AND on all given filters. - AND: [BigtaxWhereInput!] - # Logical OR on all given filters. - OR: [BigtaxWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [BigtaxWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - gold: String - # All values that are not equal to given value. - gold_not: String - # All values that are contained in given list. - gold_in: [String!] - # All values that are not contained in given list. - gold_not_in: [String!] - # All values less than the given value. - gold_lt: String - # All values less than or equal the given value. - gold_lte: String - # All values greater than the given value. - gold_gt: String - # All values greater than or equal the given value. - gold_gte: String - # All values containing the given string. - gold_contains: String - # All values not containing the given string. - gold_not_contains: String - # All values starting with the given string. - gold_starts_with: String - # All values not starting with the given string. - gold_not_starts_with: String - # All values ending with the given string. - gold_ends_with: String - # All values not ending with the given string. - gold_not_ends_with: String - lime: String - # All values that are not equal to given value. - lime_not: String - # All values that are contained in given list. - lime_in: [String!] - # All values that are not contained in given list. - lime_not_in: [String!] - # All values less than the given value. - lime_lt: String - # All values less than or equal the given value. - lime_lte: String - # All values greater than the given value. - lime_gt: String - # All values greater than or equal the given value. - lime_gte: String - # All values containing the given string. - lime_contains: String - # All values not containing the given string. - lime_not_contains: String - # All values starting with the given string. - lime_starts_with: String - # All values not starting with the given string. - lime_not_starts_with: String - # All values ending with the given string. - lime_ends_with: String - # All values not ending with the given string. - lime_not_ends_with: String - azure: Int - # All values that are not equal to given value. - azure_not: Int - # All values that are contained in given list. - azure_in: [Int!] - # All values that are not contained in given list. - azure_not_in: [Int!] - # All values less than the given value. - azure_lt: Int - # All values less than or equal the given value. - azure_lte: Int - # All values greater than the given value. - azure_gt: Int - # All values greater than or equal the given value. - azure_gte: Int - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String - yellow_every: VoyatouchWhereInput - yellow_some: VoyatouchWhereInput - yellow_none: VoyatouchWhereInput -} - -input BigtaxWhereUniqueInput { - id: ID - gold: String -} - -enum Blick { - IPSA - EXPLICABO - QUI - IN -} - -type Color implements Node { - updatedAt: DateTime! - createdAt: DateTime! - id: ID! -} - -# A connection to a list of items. -type ColorConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [ColorEdge]! - aggregate: AggregateColor! -} - -# An edge in a connection. -type ColorEdge { - # The item at the end of the edge. - node: Color! - # A cursor for use in pagination. - cursor: String! -} - -enum ColorOrderByInput { - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC -} - -type ColorPreviousValues { - updatedAt: DateTime! - createdAt: DateTime! - id: ID! -} - -type ColorSubscriptionPayload { - mutation: MutationType! - node: Color - updatedFields: [String!] - previousValues: ColorPreviousValues -} - -input ColorSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [ColorSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [ColorSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ColorSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: ColorWhereInput -} - -input ColorWhereInput { - # Logical AND on all given filters. - AND: [ColorWhereInput!] - # Logical OR on all given filters. - OR: [ColorWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ColorWhereInput!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID -} - -input ColorWhereUniqueInput { - id: ID -} - -enum Connelly { - ZERO - ONE - TWO -} - -type Daltfresh implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - maroon: Asset - lime: String! - orchid: String! - tan: String - plum: String - grey: Lotlux - ivory: Boolean -} - -# A connection to a list of items. -type DaltfreshConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [DaltfreshEdge]! - aggregate: AggregateDaltfresh! -} - -input DaltfreshCreateInput { - status: Status - lime: String! - orchid: String! - tan: String - plum: String - ivory: Boolean - maroon: AssetCreateOneWithoutMaroonDaltfreshInput - grey: LotluxCreateOneWithoutSilverInput -} - -input DaltfreshCreateManyWithoutGreyInput { - create: [DaltfreshCreateWithoutGreyInput!] - connect: [DaltfreshWhereUniqueInput!] -} - -input DaltfreshCreateManyWithoutMaroonInput { - create: [DaltfreshCreateWithoutMaroonInput!] - connect: [DaltfreshWhereUniqueInput!] -} - -input DaltfreshCreateWithoutGreyInput { - status: Status - lime: String! - orchid: String! - tan: String - plum: String - ivory: Boolean - maroon: AssetCreateOneWithoutMaroonDaltfreshInput -} - -input DaltfreshCreateWithoutMaroonInput { - status: Status - lime: String! - orchid: String! - tan: String - plum: String - ivory: Boolean - grey: LotluxCreateOneWithoutSilverInput -} - -# An edge in a connection. -type DaltfreshEdge { - # The item at the end of the edge. - node: Daltfresh! - # A cursor for use in pagination. - cursor: String! -} - -enum DaltfreshOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - lime_ASC - lime_DESC - orchid_ASC - orchid_DESC - tan_ASC - tan_DESC - plum_ASC - plum_DESC - ivory_ASC - ivory_DESC -} - -type DaltfreshPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - lime: String! - orchid: String! - tan: String - plum: String - ivory: Boolean -} - -input DaltfreshScalarWhereInput { - # Logical AND on all given filters. - AND: [DaltfreshScalarWhereInput!] - # Logical OR on all given filters. - OR: [DaltfreshScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [DaltfreshScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - lime: String - # All values that are not equal to given value. - lime_not: String - # All values that are contained in given list. - lime_in: [String!] - # All values that are not contained in given list. - lime_not_in: [String!] - # All values less than the given value. - lime_lt: String - # All values less than or equal the given value. - lime_lte: String - # All values greater than the given value. - lime_gt: String - # All values greater than or equal the given value. - lime_gte: String - # All values containing the given string. - lime_contains: String - # All values not containing the given string. - lime_not_contains: String - # All values starting with the given string. - lime_starts_with: String - # All values not starting with the given string. - lime_not_starts_with: String - # All values ending with the given string. - lime_ends_with: String - # All values not ending with the given string. - lime_not_ends_with: String - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - ivory: Boolean - # All values that are not equal to given value. - ivory_not: Boolean -} - -type DaltfreshSubscriptionPayload { - mutation: MutationType! - node: Daltfresh - updatedFields: [String!] - previousValues: DaltfreshPreviousValues -} - -input DaltfreshSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [DaltfreshSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [DaltfreshSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [DaltfreshSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: DaltfreshWhereInput -} - -input DaltfreshUpdateInput { - status: Status - lime: String - orchid: String - tan: String - plum: String - ivory: Boolean - maroon: AssetUpdateOneWithoutMaroonDaltfreshInput - grey: LotluxUpdateOneWithoutSilverInput -} - -input DaltfreshUpdateManyDataInput { - status: Status - lime: String - orchid: String - tan: String - plum: String - ivory: Boolean -} - -input DaltfreshUpdateManyMutationInput { - status: Status - lime: String - orchid: String - tan: String - plum: String - ivory: Boolean -} - -input DaltfreshUpdateManyWithoutGreyInput { - create: [DaltfreshCreateWithoutGreyInput!] - connect: [DaltfreshWhereUniqueInput!] - set: [DaltfreshWhereUniqueInput!] - disconnect: [DaltfreshWhereUniqueInput!] - delete: [DaltfreshWhereUniqueInput!] - update: [DaltfreshUpdateWithWhereUniqueWithoutGreyInput!] - updateMany: [DaltfreshUpdateManyWithWhereNestedInput!] - deleteMany: [DaltfreshScalarWhereInput!] - upsert: [DaltfreshUpsertWithWhereUniqueWithoutGreyInput!] -} - -input DaltfreshUpdateManyWithoutMaroonInput { - create: [DaltfreshCreateWithoutMaroonInput!] - connect: [DaltfreshWhereUniqueInput!] - set: [DaltfreshWhereUniqueInput!] - disconnect: [DaltfreshWhereUniqueInput!] - delete: [DaltfreshWhereUniqueInput!] - update: [DaltfreshUpdateWithWhereUniqueWithoutMaroonInput!] - updateMany: [DaltfreshUpdateManyWithWhereNestedInput!] - deleteMany: [DaltfreshScalarWhereInput!] - upsert: [DaltfreshUpsertWithWhereUniqueWithoutMaroonInput!] -} - -input DaltfreshUpdateManyWithWhereNestedInput { - where: DaltfreshScalarWhereInput! - data: DaltfreshUpdateManyDataInput! -} - -input DaltfreshUpdateWithoutGreyDataInput { - status: Status - lime: String - orchid: String - tan: String - plum: String - ivory: Boolean - maroon: AssetUpdateOneWithoutMaroonDaltfreshInput -} - -input DaltfreshUpdateWithoutMaroonDataInput { - status: Status - lime: String - orchid: String - tan: String - plum: String - ivory: Boolean - grey: LotluxUpdateOneWithoutSilverInput -} - -input DaltfreshUpdateWithWhereUniqueWithoutGreyInput { - where: DaltfreshWhereUniqueInput! - data: DaltfreshUpdateWithoutGreyDataInput! -} - -input DaltfreshUpdateWithWhereUniqueWithoutMaroonInput { - where: DaltfreshWhereUniqueInput! - data: DaltfreshUpdateWithoutMaroonDataInput! -} - -input DaltfreshUpsertWithWhereUniqueWithoutGreyInput { - where: DaltfreshWhereUniqueInput! - update: DaltfreshUpdateWithoutGreyDataInput! - create: DaltfreshCreateWithoutGreyInput! -} - -input DaltfreshUpsertWithWhereUniqueWithoutMaroonInput { - where: DaltfreshWhereUniqueInput! - update: DaltfreshUpdateWithoutMaroonDataInput! - create: DaltfreshCreateWithoutMaroonInput! -} - -input DaltfreshWhereInput { - # Logical AND on all given filters. - AND: [DaltfreshWhereInput!] - # Logical OR on all given filters. - OR: [DaltfreshWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [DaltfreshWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - lime: String - # All values that are not equal to given value. - lime_not: String - # All values that are contained in given list. - lime_in: [String!] - # All values that are not contained in given list. - lime_not_in: [String!] - # All values less than the given value. - lime_lt: String - # All values less than or equal the given value. - lime_lte: String - # All values greater than the given value. - lime_gt: String - # All values greater than or equal the given value. - lime_gte: String - # All values containing the given string. - lime_contains: String - # All values not containing the given string. - lime_not_contains: String - # All values starting with the given string. - lime_starts_with: String - # All values not starting with the given string. - lime_not_starts_with: String - # All values ending with the given string. - lime_ends_with: String - # All values not ending with the given string. - lime_not_ends_with: String - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - ivory: Boolean - # All values that are not equal to given value. - ivory_not: Boolean - maroon: AssetWhereInput - grey: LotluxWhereInput -} - -input DaltfreshWhereUniqueInput { - id: ID -} - -scalar DateTime - -enum Daugherty { - ZERO - ONE - TWO - THREE - FOUR - FIVE - SIX - SEVEN - EIGHT - NINE - TEN - ELEVEN - TWELVE - THIRTEEN - FOURTEEN - FIFTEEN - SIXTEEN - SEVENTEEN - EIGHTEEN - NINETEEN - TWENTY - TWENTY_ONE - TWENTY_TWO - TWENTY_THREE - TWENTY_FOUR - TWENTY_FIVE - TWENTY_SIX - TWENTY_SEVEN -} - -enum DocumentFileTypes { - jpg - odp - ods - odt - png - svg - txt - webp - docx - html - pdf - doc - xlsx - xls - pptx - ppt -} - -input DocumentOutputInput { - # Transforms a document into a desired file type. - # See this matrix for format support: - # - # PDF: jpg, odp, ods, odt, png, svg, txt, and webp - # DOC: docx, html, jpg, odt, pdf, png, svg, txt, and webp - # DOCX: doc, html, jpg, odt, pdf, png, svg, txt, and webp - # ODT: doc, docx, html, jpg, pdf, png, svg, txt, and webp - # XLS: jpg, pdf, ods, png, svg, xlsx, and webp - # XLSX: jpg, pdf, ods, png, svg, xls, and webp - # ODS: jpg, pdf, png, xls, svg, xlsx, and webp - # PPT: jpg, odp, pdf, png, svg, pptx, and webp - # PPTX: jpg, odp, pdf, png, svg, ppt, and webp - # ODP: jpg, pdf, png, ppt, svg, pptx, and webp - # BMP: jpg, odp, ods, odt, pdf, png, svg, and webp - # GIF: jpg, odp, ods, odt, pdf, png, svg, and webp - # JPG: jpg, odp, ods, odt, pdf, png, svg, and webp - # PNG: jpg, odp, ods, odt, pdf, png, svg, and webp - # WEBP: jpg, odp, ods, odt, pdf, png, svg, and webp - # TIFF: jpg, odp, ods, odt, pdf, png, svg, and webp - # AI: jpg, odp, ods, odt, pdf, png, svg, and webp - # PSD: jpg, odp, ods, odt, pdf, png, svg, and webp - # SVG: jpg, odp, ods, odt, pdf, png, and webp - # HTML: jpg, odt, pdf, svg, txt, and webp - # TXT: jpg, html, odt, pdf, svg, and webp - format: DocumentFileTypes -} - -# Transformations for Documents -input DocumentTransformationInput { - # Changes the output for the file. - output: DocumentOutputInput -} - -enum Harris { - ZERO - ONE - TWO - THREE - FOUR - FIVE - SIX - SEVEN - EIGHT - NINE - TEN - ELEVEN - TWELVE - THIRTEEN -} - -type Hatity implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - orchid: String - purple: String! - grey: Boolean - turquoise( - where: RedholdWhereInput - orderBy: RedholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Redhold!] - white: Connelly! - cyan: String - gold: String - plum: String - magenta: String -} - -# A connection to a list of items. -type HatityConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [HatityEdge]! - aggregate: AggregateHatity! -} - -input HatityCreateInput { - status: Status - orchid: String - purple: String! - grey: Boolean - white: Connelly! - cyan: String - gold: String - plum: String - magenta: String - turquoise: RedholdCreateManyWithoutOliveInput -} - -input HatityCreateOneWithoutTurquoiseInput { - create: HatityCreateWithoutTurquoiseInput - connect: HatityWhereUniqueInput -} - -input HatityCreateWithoutTurquoiseInput { - status: Status - orchid: String - purple: String! - grey: Boolean - white: Connelly! - cyan: String - gold: String - plum: String - magenta: String -} - -# An edge in a connection. -type HatityEdge { - # The item at the end of the edge. - node: Hatity! - # A cursor for use in pagination. - cursor: String! -} - -enum HatityOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - orchid_ASC - orchid_DESC - purple_ASC - purple_DESC - grey_ASC - grey_DESC - white_ASC - white_DESC - cyan_ASC - cyan_DESC - gold_ASC - gold_DESC - plum_ASC - plum_DESC - magenta_ASC - magenta_DESC -} - -type HatityPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - orchid: String - purple: String! - grey: Boolean - white: Connelly! - cyan: String - gold: String - plum: String - magenta: String -} - -type HatitySubscriptionPayload { - mutation: MutationType! - node: Hatity - updatedFields: [String!] - previousValues: HatityPreviousValues -} - -input HatitySubscriptionWhereInput { - # Logical AND on all given filters. - AND: [HatitySubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [HatitySubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [HatitySubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: HatityWhereInput -} - -input HatityUpdateInput { - status: Status - orchid: String - purple: String - grey: Boolean - white: Connelly - cyan: String - gold: String - plum: String - magenta: String - turquoise: RedholdUpdateManyWithoutOliveInput -} - -input HatityUpdateManyMutationInput { - status: Status - orchid: String - purple: String - grey: Boolean - white: Connelly - cyan: String - gold: String - plum: String - magenta: String -} - -input HatityUpdateOneWithoutTurquoiseInput { - create: HatityCreateWithoutTurquoiseInput - connect: HatityWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: HatityUpdateWithoutTurquoiseDataInput - upsert: HatityUpsertWithoutTurquoiseInput -} - -input HatityUpdateWithoutTurquoiseDataInput { - status: Status - orchid: String - purple: String - grey: Boolean - white: Connelly - cyan: String - gold: String - plum: String - magenta: String -} - -input HatityUpsertWithoutTurquoiseInput { - update: HatityUpdateWithoutTurquoiseDataInput! - create: HatityCreateWithoutTurquoiseInput! -} - -input HatityWhereInput { - # Logical AND on all given filters. - AND: [HatityWhereInput!] - # Logical OR on all given filters. - OR: [HatityWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [HatityWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - grey: Boolean - # All values that are not equal to given value. - grey_not: Boolean - white: Connelly - # All values that are not equal to given value. - white_not: Connelly - # All values that are contained in given list. - white_in: [Connelly!] - # All values that are not contained in given list. - white_not_in: [Connelly!] - cyan: String - # All values that are not equal to given value. - cyan_not: String - # All values that are contained in given list. - cyan_in: [String!] - # All values that are not contained in given list. - cyan_not_in: [String!] - # All values less than the given value. - cyan_lt: String - # All values less than or equal the given value. - cyan_lte: String - # All values greater than the given value. - cyan_gt: String - # All values greater than or equal the given value. - cyan_gte: String - # All values containing the given string. - cyan_contains: String - # All values not containing the given string. - cyan_not_contains: String - # All values starting with the given string. - cyan_starts_with: String - # All values not starting with the given string. - cyan_not_starts_with: String - # All values ending with the given string. - cyan_ends_with: String - # All values not ending with the given string. - cyan_not_ends_with: String - gold: String - # All values that are not equal to given value. - gold_not: String - # All values that are contained in given list. - gold_in: [String!] - # All values that are not contained in given list. - gold_not_in: [String!] - # All values less than the given value. - gold_lt: String - # All values less than or equal the given value. - gold_lte: String - # All values greater than the given value. - gold_gt: String - # All values greater than or equal the given value. - gold_gte: String - # All values containing the given string. - gold_contains: String - # All values not containing the given string. - gold_not_contains: String - # All values starting with the given string. - gold_starts_with: String - # All values not starting with the given string. - gold_not_starts_with: String - # All values ending with the given string. - gold_ends_with: String - # All values not ending with the given string. - gold_not_ends_with: String - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - magenta: String - # All values that are not equal to given value. - magenta_not: String - # All values that are contained in given list. - magenta_in: [String!] - # All values that are not contained in given list. - magenta_not_in: [String!] - # All values less than the given value. - magenta_lt: String - # All values less than or equal the given value. - magenta_lte: String - # All values greater than the given value. - magenta_gt: String - # All values greater than or equal the given value. - magenta_gte: String - # All values containing the given string. - magenta_contains: String - # All values not containing the given string. - magenta_not_contains: String - # All values starting with the given string. - magenta_starts_with: String - # All values not starting with the given string. - magenta_not_starts_with: String - # All values ending with the given string. - magenta_ends_with: String - # All values not ending with the given string. - magenta_not_ends_with: String - turquoise_every: RedholdWhereInput - turquoise_some: RedholdWhereInput - turquoise_none: RedholdWhereInput -} - -input HatityWhereUniqueInput { - id: ID - purple: String -} - -enum ImageFit { - # Resizes the image to fit within the specified parameters without distorting, cropping, or changing the aspect ratio. - clip - # Resizes the image to fit the specified parameters exactly by removing any - # parts of the image that don't fit within the boundaries. - crop - # Resizes the image to fit the specified parameters exactly by scaling the image - # to the desired size. The aspect ratio of the image is not respected and the - # image can be distorted using this method. - scale - # Resizes the image to fit within the parameters, but as opposed to 'fit:clip' - # will not scale the image if the image is smaller than the output size. - max -} - -input ImageResizeInput { - # The width in pixels to resize the image to. The value must be an integer from 1 to 10000. - width: Int - # The height in pixels to resize the image to. The value must be an integer from 1 to 10000. - height: Int - # The default value for the fit parameter is fit:clip. - fit: ImageFit -} - -# Transformations for Images -input ImageTransformationInput { - # Resizes the image - resize: ImageResizeInput -} - -type Job implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - gold: String - purple: String - red: Int - tan: Zoolab -} - -# A connection to a list of items. -type JobConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [JobEdge]! - aggregate: AggregateJob! -} - -input JobCreateInput { - status: Status - gold: String - purple: String - red: Int - tan: ZoolabCreateOneWithoutTanInput -} - -input JobCreateManyWithoutTanInput { - create: [JobCreateWithoutTanInput!] - connect: [JobWhereUniqueInput!] -} - -input JobCreateWithoutTanInput { - status: Status - gold: String - purple: String - red: Int -} - -# An edge in a connection. -type JobEdge { - # The item at the end of the edge. - node: Job! - # A cursor for use in pagination. - cursor: String! -} - -enum JobOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - gold_ASC - gold_DESC - purple_ASC - purple_DESC - red_ASC - red_DESC -} - -type JobPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - gold: String - purple: String - red: Int -} - -input JobScalarWhereInput { - # Logical AND on all given filters. - AND: [JobScalarWhereInput!] - # Logical OR on all given filters. - OR: [JobScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [JobScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - gold: String - # All values that are not equal to given value. - gold_not: String - # All values that are contained in given list. - gold_in: [String!] - # All values that are not contained in given list. - gold_not_in: [String!] - # All values less than the given value. - gold_lt: String - # All values less than or equal the given value. - gold_lte: String - # All values greater than the given value. - gold_gt: String - # All values greater than or equal the given value. - gold_gte: String - # All values containing the given string. - gold_contains: String - # All values not containing the given string. - gold_not_contains: String - # All values starting with the given string. - gold_starts_with: String - # All values not starting with the given string. - gold_not_starts_with: String - # All values ending with the given string. - gold_ends_with: String - # All values not ending with the given string. - gold_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - red: Int - # All values that are not equal to given value. - red_not: Int - # All values that are contained in given list. - red_in: [Int!] - # All values that are not contained in given list. - red_not_in: [Int!] - # All values less than the given value. - red_lt: Int - # All values less than or equal the given value. - red_lte: Int - # All values greater than the given value. - red_gt: Int - # All values greater than or equal the given value. - red_gte: Int -} - -type JobSubscriptionPayload { - mutation: MutationType! - node: Job - updatedFields: [String!] - previousValues: JobPreviousValues -} - -input JobSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [JobSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [JobSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [JobSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: JobWhereInput -} - -input JobUpdateInput { - status: Status - gold: String - purple: String - red: Int - tan: ZoolabUpdateOneWithoutTanInput -} - -input JobUpdateManyDataInput { - status: Status - gold: String - purple: String - red: Int -} - -input JobUpdateManyMutationInput { - status: Status - gold: String - purple: String - red: Int -} - -input JobUpdateManyWithoutTanInput { - create: [JobCreateWithoutTanInput!] - connect: [JobWhereUniqueInput!] - set: [JobWhereUniqueInput!] - disconnect: [JobWhereUniqueInput!] - delete: [JobWhereUniqueInput!] - update: [JobUpdateWithWhereUniqueWithoutTanInput!] - updateMany: [JobUpdateManyWithWhereNestedInput!] - deleteMany: [JobScalarWhereInput!] - upsert: [JobUpsertWithWhereUniqueWithoutTanInput!] -} - -input JobUpdateManyWithWhereNestedInput { - where: JobScalarWhereInput! - data: JobUpdateManyDataInput! -} - -input JobUpdateWithoutTanDataInput { - status: Status - gold: String - purple: String - red: Int -} - -input JobUpdateWithWhereUniqueWithoutTanInput { - where: JobWhereUniqueInput! - data: JobUpdateWithoutTanDataInput! -} - -input JobUpsertWithWhereUniqueWithoutTanInput { - where: JobWhereUniqueInput! - update: JobUpdateWithoutTanDataInput! - create: JobCreateWithoutTanInput! -} - -input JobWhereInput { - # Logical AND on all given filters. - AND: [JobWhereInput!] - # Logical OR on all given filters. - OR: [JobWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [JobWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - gold: String - # All values that are not equal to given value. - gold_not: String - # All values that are contained in given list. - gold_in: [String!] - # All values that are not contained in given list. - gold_not_in: [String!] - # All values less than the given value. - gold_lt: String - # All values less than or equal the given value. - gold_lte: String - # All values greater than the given value. - gold_gt: String - # All values greater than or equal the given value. - gold_gte: String - # All values containing the given string. - gold_contains: String - # All values not containing the given string. - gold_not_contains: String - # All values starting with the given string. - gold_starts_with: String - # All values not starting with the given string. - gold_not_starts_with: String - # All values ending with the given string. - gold_ends_with: String - # All values not ending with the given string. - gold_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - red: Int - # All values that are not equal to given value. - red_not: Int - # All values that are contained in given list. - red_in: [Int!] - # All values that are not contained in given list. - red_not_in: [Int!] - # All values less than the given value. - red_lt: Int - # All values less than or equal the given value. - red_lte: Int - # All values greater than the given value. - red_gt: Int - # All values greater than or equal the given value. - red_gte: Int - tan: ZoolabWhereInput -} - -input JobWhereUniqueInput { - id: ID -} - -type Keylex implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - ivory: DateTime - tan: String! -} - -# A connection to a list of items. -type KeylexConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [KeylexEdge]! - aggregate: AggregateKeylex! -} - -input KeylexCreateInput { - status: Status - ivory: DateTime - tan: String! -} - -# An edge in a connection. -type KeylexEdge { - # The item at the end of the edge. - node: Keylex! - # A cursor for use in pagination. - cursor: String! -} - -enum KeylexOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - ivory_ASC - ivory_DESC - tan_ASC - tan_DESC -} - -type KeylexPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - ivory: DateTime - tan: String! -} - -type KeylexSubscriptionPayload { - mutation: MutationType! - node: Keylex - updatedFields: [String!] - previousValues: KeylexPreviousValues -} - -input KeylexSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [KeylexSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [KeylexSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [KeylexSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: KeylexWhereInput -} - -input KeylexUpdateInput { - status: Status - ivory: DateTime - tan: String -} - -input KeylexUpdateManyMutationInput { - status: Status - ivory: DateTime - tan: String -} - -input KeylexWhereInput { - # Logical AND on all given filters. - AND: [KeylexWhereInput!] - # Logical OR on all given filters. - OR: [KeylexWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [KeylexWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - ivory: DateTime - # All values that are not equal to given value. - ivory_not: DateTime - # All values that are contained in given list. - ivory_in: [DateTime!] - # All values that are not contained in given list. - ivory_not_in: [DateTime!] - # All values less than the given value. - ivory_lt: DateTime - # All values less than or equal the given value. - ivory_lte: DateTime - # All values greater than the given value. - ivory_gt: DateTime - # All values greater than or equal the given value. - ivory_gte: DateTime - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String -} - -input KeylexWhereUniqueInput { - id: ID - ivory: DateTime -} - -enum King { - IN - QUO - PARIATUR - FACILIS - APERIAM - EVENIET - SAPIENTE -} - -type Konklab implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - cyan: String - ivory: String - yellow: Muller! - red: String! -} - -# A connection to a list of items. -type KonklabConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [KonklabEdge]! - aggregate: AggregateKonklab! -} - -input KonklabCreateInput { - status: Status - cyan: String - ivory: String - yellow: Muller! - red: String! -} - -# An edge in a connection. -type KonklabEdge { - # The item at the end of the edge. - node: Konklab! - # A cursor for use in pagination. - cursor: String! -} - -enum KonklabOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - cyan_ASC - cyan_DESC - ivory_ASC - ivory_DESC - yellow_ASC - yellow_DESC - red_ASC - red_DESC -} - -type KonklabPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - cyan: String - ivory: String - yellow: Muller! - red: String! -} - -type KonklabSubscriptionPayload { - mutation: MutationType! - node: Konklab - updatedFields: [String!] - previousValues: KonklabPreviousValues -} - -input KonklabSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [KonklabSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [KonklabSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [KonklabSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: KonklabWhereInput -} - -input KonklabUpdateInput { - status: Status - cyan: String - ivory: String - yellow: Muller - red: String -} - -input KonklabUpdateManyMutationInput { - status: Status - cyan: String - ivory: String - yellow: Muller - red: String -} - -input KonklabWhereInput { - # Logical AND on all given filters. - AND: [KonklabWhereInput!] - # Logical OR on all given filters. - OR: [KonklabWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [KonklabWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - cyan: String - # All values that are not equal to given value. - cyan_not: String - # All values that are contained in given list. - cyan_in: [String!] - # All values that are not contained in given list. - cyan_not_in: [String!] - # All values less than the given value. - cyan_lt: String - # All values less than or equal the given value. - cyan_lte: String - # All values greater than the given value. - cyan_gt: String - # All values greater than or equal the given value. - cyan_gte: String - # All values containing the given string. - cyan_contains: String - # All values not containing the given string. - cyan_not_contains: String - # All values starting with the given string. - cyan_starts_with: String - # All values not starting with the given string. - cyan_not_starts_with: String - # All values ending with the given string. - cyan_ends_with: String - # All values not ending with the given string. - cyan_not_ends_with: String - ivory: String - # All values that are not equal to given value. - ivory_not: String - # All values that are contained in given list. - ivory_in: [String!] - # All values that are not contained in given list. - ivory_not_in: [String!] - # All values less than the given value. - ivory_lt: String - # All values less than or equal the given value. - ivory_lte: String - # All values greater than the given value. - ivory_gt: String - # All values greater than or equal the given value. - ivory_gte: String - # All values containing the given string. - ivory_contains: String - # All values not containing the given string. - ivory_not_contains: String - # All values starting with the given string. - ivory_starts_with: String - # All values not starting with the given string. - ivory_not_starts_with: String - # All values ending with the given string. - ivory_ends_with: String - # All values not ending with the given string. - ivory_not_ends_with: String - yellow: Muller - # All values that are not equal to given value. - yellow_not: Muller - # All values that are contained in given list. - yellow_in: [Muller!] - # All values that are not contained in given list. - yellow_not_in: [Muller!] - red: String - # All values that are not equal to given value. - red_not: String - # All values that are contained in given list. - red_in: [String!] - # All values that are not contained in given list. - red_not_in: [String!] - # All values less than the given value. - red_lt: String - # All values less than or equal the given value. - red_lte: String - # All values greater than the given value. - red_gt: String - # All values greater than or equal the given value. - red_gte: String - # All values containing the given string. - red_contains: String - # All values not containing the given string. - red_not_contains: String - # All values starting with the given string. - red_starts_with: String - # All values not starting with the given string. - red_not_starts_with: String - # All values ending with the given string. - red_ends_with: String - # All values not ending with the given string. - red_not_ends_with: String -} - -input KonklabWhereUniqueInput { - id: ID - yellow: Muller -} - -type Konklux implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - maroon: String - azure: String! -} - -# A connection to a list of items. -type KonkluxConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [KonkluxEdge]! - aggregate: AggregateKonklux! -} - -input KonkluxCreateInput { - status: Status - maroon: String - azure: String! -} - -# An edge in a connection. -type KonkluxEdge { - # The item at the end of the edge. - node: Konklux! - # A cursor for use in pagination. - cursor: String! -} - -enum KonkluxOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - maroon_ASC - maroon_DESC - azure_ASC - azure_DESC -} - -type KonkluxPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - maroon: String - azure: String! -} - -type KonkluxSubscriptionPayload { - mutation: MutationType! - node: Konklux - updatedFields: [String!] - previousValues: KonkluxPreviousValues -} - -input KonkluxSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [KonkluxSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [KonkluxSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [KonkluxSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: KonkluxWhereInput -} - -input KonkluxUpdateInput { - status: Status - maroon: String - azure: String -} - -input KonkluxUpdateManyMutationInput { - status: Status - maroon: String - azure: String -} - -input KonkluxWhereInput { - # Logical AND on all given filters. - AND: [KonkluxWhereInput!] - # Logical OR on all given filters. - OR: [KonkluxWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [KonkluxWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - maroon: String - # All values that are not equal to given value. - maroon_not: String - # All values that are contained in given list. - maroon_in: [String!] - # All values that are not contained in given list. - maroon_not_in: [String!] - # All values less than the given value. - maroon_lt: String - # All values less than or equal the given value. - maroon_lte: String - # All values greater than the given value. - maroon_gt: String - # All values greater than or equal the given value. - maroon_gte: String - # All values containing the given string. - maroon_contains: String - # All values not containing the given string. - maroon_not_contains: String - # All values starting with the given string. - maroon_starts_with: String - # All values not starting with the given string. - maroon_not_starts_with: String - # All values ending with the given string. - maroon_ends_with: String - # All values not ending with the given string. - maroon_not_ends_with: String - azure: String - # All values that are not equal to given value. - azure_not: String - # All values that are contained in given list. - azure_in: [String!] - # All values that are not contained in given list. - azure_not_in: [String!] - # All values less than the given value. - azure_lt: String - # All values less than or equal the given value. - azure_lte: String - # All values greater than the given value. - azure_gt: String - # All values greater than or equal the given value. - azure_gte: String - # All values containing the given string. - azure_contains: String - # All values not containing the given string. - azure_not_contains: String - # All values starting with the given string. - azure_starts_with: String - # All values not starting with the given string. - azure_not_starts_with: String - # All values ending with the given string. - azure_ends_with: String - # All values not ending with the given string. - azure_not_ends_with: String -} - -input KonkluxWhereUniqueInput { - id: ID - maroon: String -} - -type Latlux implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - tan: Morissette -} - -# A connection to a list of items. -type LatluxConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [LatluxEdge]! - aggregate: AggregateLatlux! -} - -input LatluxCreateInput { - status: Status - tan: Morissette -} - -# An edge in a connection. -type LatluxEdge { - # The item at the end of the edge. - node: Latlux! - # A cursor for use in pagination. - cursor: String! -} - -enum LatluxOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - tan_ASC - tan_DESC -} - -type LatluxPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - tan: Morissette -} - -type LatluxSubscriptionPayload { - mutation: MutationType! - node: Latlux - updatedFields: [String!] - previousValues: LatluxPreviousValues -} - -input LatluxSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [LatluxSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [LatluxSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LatluxSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: LatluxWhereInput -} - -input LatluxUpdateInput { - status: Status - tan: Morissette -} - -input LatluxUpdateManyMutationInput { - status: Status - tan: Morissette -} - -input LatluxWhereInput { - # Logical AND on all given filters. - AND: [LatluxWhereInput!] - # Logical OR on all given filters. - OR: [LatluxWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LatluxWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - tan: Morissette - # All values that are not equal to given value. - tan_not: Morissette - # All values that are contained in given list. - tan_in: [Morissette!] - # All values that are not contained in given list. - tan_not_in: [Morissette!] -} - -input LatluxWhereUniqueInput { - id: ID -} - -enum Locale { - EN -} - -type Location implements Node { - updatedAt: DateTime! - createdAt: DateTime! - id: ID! -} - -# A connection to a list of items. -type LocationConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [LocationEdge]! - aggregate: AggregateLocation! -} - -# An edge in a connection. -type LocationEdge { - # The item at the end of the edge. - node: Location! - # A cursor for use in pagination. - cursor: String! -} - -enum LocationOrderByInput { - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC -} - -type LocationPreviousValues { - updatedAt: DateTime! - createdAt: DateTime! - id: ID! -} - -type LocationSubscriptionPayload { - mutation: MutationType! - node: Location - updatedFields: [String!] - previousValues: LocationPreviousValues -} - -input LocationSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [LocationSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [LocationSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LocationSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: LocationWhereInput -} - -input LocationWhereInput { - # Logical AND on all given filters. - AND: [LocationWhereInput!] - # Logical OR on all given filters. - OR: [LocationWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LocationWhereInput!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID -} - -input LocationWhereUniqueInput { - id: ID -} - -# The `Long` scalar type -# represents non-fractional signed whole numeric values. -# Long can represent values between -(2^63) and 2^63 - 1. -scalar Long - -type Lotlux implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - olive: String! - tan: String - lavender: String - silver( - where: DaltfreshWhereInput - orderBy: DaltfreshOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Daltfresh!] - azure: Sonsing - plum: Sonsing -} - -# A connection to a list of items. -type LotluxConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [LotluxEdge]! - aggregate: AggregateLotlux! -} - -input LotluxCreateInput { - status: Status - olive: String! - tan: String - lavender: String - silver: DaltfreshCreateManyWithoutGreyInput - azure: SonsingCreateOneWithoutGoldInput - plum: SonsingCreateOneWithoutOrchidInput -} - -input LotluxCreateOneWithoutAzureInput { - create: LotluxCreateWithoutAzureInput - connect: LotluxWhereUniqueInput -} - -input LotluxCreateOneWithoutPlumInput { - create: LotluxCreateWithoutPlumInput - connect: LotluxWhereUniqueInput -} - -input LotluxCreateOneWithoutSilverInput { - create: LotluxCreateWithoutSilverInput - connect: LotluxWhereUniqueInput -} - -input LotluxCreateWithoutAzureInput { - status: Status - olive: String! - tan: String - lavender: String - silver: DaltfreshCreateManyWithoutGreyInput - plum: SonsingCreateOneWithoutOrchidInput -} - -input LotluxCreateWithoutPlumInput { - status: Status - olive: String! - tan: String - lavender: String - silver: DaltfreshCreateManyWithoutGreyInput - azure: SonsingCreateOneWithoutGoldInput -} - -input LotluxCreateWithoutSilverInput { - status: Status - olive: String! - tan: String - lavender: String - azure: SonsingCreateOneWithoutGoldInput - plum: SonsingCreateOneWithoutOrchidInput -} - -# An edge in a connection. -type LotluxEdge { - # The item at the end of the edge. - node: Lotlux! - # A cursor for use in pagination. - cursor: String! -} - -enum LotluxOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - olive_ASC - olive_DESC - tan_ASC - tan_DESC - lavender_ASC - lavender_DESC -} - -type LotluxPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - olive: String! - tan: String - lavender: String -} - -type LotluxSubscriptionPayload { - mutation: MutationType! - node: Lotlux - updatedFields: [String!] - previousValues: LotluxPreviousValues -} - -input LotluxSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [LotluxSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [LotluxSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LotluxSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: LotluxWhereInput -} - -input LotluxUpdateInput { - status: Status - olive: String - tan: String - lavender: String - silver: DaltfreshUpdateManyWithoutGreyInput - azure: SonsingUpdateOneWithoutGoldInput - plum: SonsingUpdateOneWithoutOrchidInput -} - -input LotluxUpdateManyMutationInput { - status: Status - olive: String - tan: String - lavender: String -} - -input LotluxUpdateOneWithoutAzureInput { - create: LotluxCreateWithoutAzureInput - connect: LotluxWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: LotluxUpdateWithoutAzureDataInput - upsert: LotluxUpsertWithoutAzureInput -} - -input LotluxUpdateOneWithoutPlumInput { - create: LotluxCreateWithoutPlumInput - connect: LotluxWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: LotluxUpdateWithoutPlumDataInput - upsert: LotluxUpsertWithoutPlumInput -} - -input LotluxUpdateOneWithoutSilverInput { - create: LotluxCreateWithoutSilverInput - connect: LotluxWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: LotluxUpdateWithoutSilverDataInput - upsert: LotluxUpsertWithoutSilverInput -} - -input LotluxUpdateWithoutAzureDataInput { - status: Status - olive: String - tan: String - lavender: String - silver: DaltfreshUpdateManyWithoutGreyInput - plum: SonsingUpdateOneWithoutOrchidInput -} - -input LotluxUpdateWithoutPlumDataInput { - status: Status - olive: String - tan: String - lavender: String - silver: DaltfreshUpdateManyWithoutGreyInput - azure: SonsingUpdateOneWithoutGoldInput -} - -input LotluxUpdateWithoutSilverDataInput { - status: Status - olive: String - tan: String - lavender: String - azure: SonsingUpdateOneWithoutGoldInput - plum: SonsingUpdateOneWithoutOrchidInput -} - -input LotluxUpsertWithoutAzureInput { - update: LotluxUpdateWithoutAzureDataInput! - create: LotluxCreateWithoutAzureInput! -} - -input LotluxUpsertWithoutPlumInput { - update: LotluxUpdateWithoutPlumDataInput! - create: LotluxCreateWithoutPlumInput! -} - -input LotluxUpsertWithoutSilverInput { - update: LotluxUpdateWithoutSilverDataInput! - create: LotluxCreateWithoutSilverInput! -} - -input LotluxWhereInput { - # Logical AND on all given filters. - AND: [LotluxWhereInput!] - # Logical OR on all given filters. - OR: [LotluxWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LotluxWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - olive: String - # All values that are not equal to given value. - olive_not: String - # All values that are contained in given list. - olive_in: [String!] - # All values that are not contained in given list. - olive_not_in: [String!] - # All values less than the given value. - olive_lt: String - # All values less than or equal the given value. - olive_lte: String - # All values greater than the given value. - olive_gt: String - # All values greater than or equal the given value. - olive_gte: String - # All values containing the given string. - olive_contains: String - # All values not containing the given string. - olive_not_contains: String - # All values starting with the given string. - olive_starts_with: String - # All values not starting with the given string. - olive_not_starts_with: String - # All values ending with the given string. - olive_ends_with: String - # All values not ending with the given string. - olive_not_ends_with: String - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - lavender: String - # All values that are not equal to given value. - lavender_not: String - # All values that are contained in given list. - lavender_in: [String!] - # All values that are not contained in given list. - lavender_not_in: [String!] - # All values less than the given value. - lavender_lt: String - # All values less than or equal the given value. - lavender_lte: String - # All values greater than the given value. - lavender_gt: String - # All values greater than or equal the given value. - lavender_gte: String - # All values containing the given string. - lavender_contains: String - # All values not containing the given string. - lavender_not_contains: String - # All values starting with the given string. - lavender_starts_with: String - # All values not starting with the given string. - lavender_not_starts_with: String - # All values ending with the given string. - lavender_ends_with: String - # All values not ending with the given string. - lavender_not_ends_with: String - silver_every: DaltfreshWhereInput - silver_some: DaltfreshWhereInput - silver_none: DaltfreshWhereInput - azure: SonsingWhereInput - plum: SonsingWhereInput -} - -input LotluxWhereUniqueInput { - id: ID -} - -type Lotstring implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - gold( - where: AssetWhereInput - orderBy: AssetOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Asset!] - teal: String! - purple: String! - orchid: Harris - white: String -} - -# A connection to a list of items. -type LotstringConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [LotstringEdge]! - aggregate: AggregateLotstring! -} - -input LotstringCreateInput { - status: Status - teal: String! - purple: String! - orchid: Harris - white: String - gold: AssetCreateManyWithoutGoldLotstringInput -} - -input LotstringCreateManyWithoutGoldInput { - create: [LotstringCreateWithoutGoldInput!] - connect: [LotstringWhereUniqueInput!] -} - -input LotstringCreateWithoutGoldInput { - status: Status - teal: String! - purple: String! - orchid: Harris - white: String -} - -# An edge in a connection. -type LotstringEdge { - # The item at the end of the edge. - node: Lotstring! - # A cursor for use in pagination. - cursor: String! -} - -enum LotstringOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - teal_ASC - teal_DESC - purple_ASC - purple_DESC - orchid_ASC - orchid_DESC - white_ASC - white_DESC -} - -type LotstringPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - teal: String! - purple: String! - orchid: Harris - white: String -} - -input LotstringScalarWhereInput { - # Logical AND on all given filters. - AND: [LotstringScalarWhereInput!] - # Logical OR on all given filters. - OR: [LotstringScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LotstringScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - teal: String - # All values that are not equal to given value. - teal_not: String - # All values that are contained in given list. - teal_in: [String!] - # All values that are not contained in given list. - teal_not_in: [String!] - # All values less than the given value. - teal_lt: String - # All values less than or equal the given value. - teal_lte: String - # All values greater than the given value. - teal_gt: String - # All values greater than or equal the given value. - teal_gte: String - # All values containing the given string. - teal_contains: String - # All values not containing the given string. - teal_not_contains: String - # All values starting with the given string. - teal_starts_with: String - # All values not starting with the given string. - teal_not_starts_with: String - # All values ending with the given string. - teal_ends_with: String - # All values not ending with the given string. - teal_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - orchid: Harris - # All values that are not equal to given value. - orchid_not: Harris - # All values that are contained in given list. - orchid_in: [Harris!] - # All values that are not contained in given list. - orchid_not_in: [Harris!] - white: String - # All values that are not equal to given value. - white_not: String - # All values that are contained in given list. - white_in: [String!] - # All values that are not contained in given list. - white_not_in: [String!] - # All values less than the given value. - white_lt: String - # All values less than or equal the given value. - white_lte: String - # All values greater than the given value. - white_gt: String - # All values greater than or equal the given value. - white_gte: String - # All values containing the given string. - white_contains: String - # All values not containing the given string. - white_not_contains: String - # All values starting with the given string. - white_starts_with: String - # All values not starting with the given string. - white_not_starts_with: String - # All values ending with the given string. - white_ends_with: String - # All values not ending with the given string. - white_not_ends_with: String -} - -type LotstringSubscriptionPayload { - mutation: MutationType! - node: Lotstring - updatedFields: [String!] - previousValues: LotstringPreviousValues -} - -input LotstringSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [LotstringSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [LotstringSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LotstringSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: LotstringWhereInput -} - -input LotstringUpdateInput { - status: Status - teal: String - purple: String - orchid: Harris - white: String - gold: AssetUpdateManyWithoutGoldLotstringInput -} - -input LotstringUpdateManyDataInput { - status: Status - teal: String - purple: String - orchid: Harris - white: String -} - -input LotstringUpdateManyMutationInput { - status: Status - teal: String - purple: String - orchid: Harris - white: String -} - -input LotstringUpdateManyWithoutGoldInput { - create: [LotstringCreateWithoutGoldInput!] - connect: [LotstringWhereUniqueInput!] - set: [LotstringWhereUniqueInput!] - disconnect: [LotstringWhereUniqueInput!] - delete: [LotstringWhereUniqueInput!] - update: [LotstringUpdateWithWhereUniqueWithoutGoldInput!] - updateMany: [LotstringUpdateManyWithWhereNestedInput!] - deleteMany: [LotstringScalarWhereInput!] - upsert: [LotstringUpsertWithWhereUniqueWithoutGoldInput!] -} - -input LotstringUpdateManyWithWhereNestedInput { - where: LotstringScalarWhereInput! - data: LotstringUpdateManyDataInput! -} - -input LotstringUpdateWithoutGoldDataInput { - status: Status - teal: String - purple: String - orchid: Harris - white: String -} - -input LotstringUpdateWithWhereUniqueWithoutGoldInput { - where: LotstringWhereUniqueInput! - data: LotstringUpdateWithoutGoldDataInput! -} - -input LotstringUpsertWithWhereUniqueWithoutGoldInput { - where: LotstringWhereUniqueInput! - update: LotstringUpdateWithoutGoldDataInput! - create: LotstringCreateWithoutGoldInput! -} - -input LotstringWhereInput { - # Logical AND on all given filters. - AND: [LotstringWhereInput!] - # Logical OR on all given filters. - OR: [LotstringWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [LotstringWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - teal: String - # All values that are not equal to given value. - teal_not: String - # All values that are contained in given list. - teal_in: [String!] - # All values that are not contained in given list. - teal_not_in: [String!] - # All values less than the given value. - teal_lt: String - # All values less than or equal the given value. - teal_lte: String - # All values greater than the given value. - teal_gt: String - # All values greater than or equal the given value. - teal_gte: String - # All values containing the given string. - teal_contains: String - # All values not containing the given string. - teal_not_contains: String - # All values starting with the given string. - teal_starts_with: String - # All values not starting with the given string. - teal_not_starts_with: String - # All values ending with the given string. - teal_ends_with: String - # All values not ending with the given string. - teal_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - orchid: Harris - # All values that are not equal to given value. - orchid_not: Harris - # All values that are contained in given list. - orchid_in: [Harris!] - # All values that are not contained in given list. - orchid_not_in: [Harris!] - white: String - # All values that are not equal to given value. - white_not: String - # All values that are contained in given list. - white_in: [String!] - # All values that are not contained in given list. - white_not_in: [String!] - # All values less than the given value. - white_lt: String - # All values less than or equal the given value. - white_lte: String - # All values greater than the given value. - white_gt: String - # All values greater than or equal the given value. - white_gte: String - # All values containing the given string. - white_contains: String - # All values not containing the given string. - white_not_contains: String - # All values starting with the given string. - white_starts_with: String - # All values not starting with the given string. - white_not_starts_with: String - # All values ending with the given string. - white_ends_with: String - # All values not ending with the given string. - white_not_ends_with: String - gold_every: AssetWhereInput - gold_some: AssetWhereInput - gold_none: AssetWhereInput -} - -input LotstringWhereUniqueInput { - id: ID - orchid: Harris -} - -enum Morissette { - VOLUPTATES - FUGIT - CONSEQUATUR - COMMODI - NON - NOSTRUM - SINT - RECUSANDAE - EST - AUTEM - OPTIO - QUI - SIT - LABORUM - MAGNAM - EA - VELIT - IN - FACILIS - QUIA - UT - SED -} - -enum Mraz { - IN - VOLUPTAS - RERUM - EUM - EXERCITATIONEM - SED - TEMPORA - ET -} - -enum Muller { - ZERO - ONE - TWO - THREE - FOUR - FIVE - SIX - SEVEN - EIGHT - NINE - TEN - ELEVEN - TWELVE - THIRTEEN - FOURTEEN - FIFTEEN - SIXTEEN - SEVENTEEN - EIGHTEEN - NINETEEN - TWENTY - TWENTY_ONE - TWENTY_TWO - TWENTY_THREE - TWENTY_FOUR - TWENTY_FIVE - TWENTY_SIX - TWENTY_SEVEN - TWENTY_EIGHT - TWENTY_NINE - THIRTY - THIRTY_ONE - THIRTY_TWO - THIRTY_THREE - THIRTY_FOUR - THIRTY_FIVE - THIRTY_SIX - THIRTY_SEVEN - THIRTY_EIGHT - THIRTY_NINE - FORTY - FORTY_ONE - FORTY_TWO - FORTY_THREE - FORTY_FOUR - FORTY_FIVE - FORTY_SIX - FORTY_SEVEN - FORTY_EIGHT - FORTY_NINE -} - -type Mutation { - createAsset(data: AssetCreateInput!): Asset! - createColor: Color! - createLocation: Location! - createKonklux(data: KonkluxCreateInput!): Konklux! - createSubin(data: SubinCreateInput!): Subin! - createTemp(data: TempCreateInput!): Temp! - createVoyatouch(data: VoyatouchCreateInput!): Voyatouch! - createBamity(data: BamityCreateInput!): Bamity! - createZamit(data: ZamitCreateInput!): Zamit! - createKeylex(data: KeylexCreateInput!): Keylex! - createLotstring(data: LotstringCreateInput!): Lotstring! - createViva(data: VivaCreateInput!): Viva! - createTranscof(data: TranscofCreateInput!): Transcof! - createDaltfresh(data: DaltfreshCreateInput!): Daltfresh! - createLotlux(data: LotluxCreateInput!): Lotlux! - createSonsing(data: SonsingCreateInput!): Sonsing! - createToughjoyfax(data: ToughjoyfaxCreateInput!): Toughjoyfax! - createStronghold(data: StrongholdCreateInput!): Stronghold! - createZoolab(data: ZoolabCreateInput!): Zoolab! - createJob(data: JobCreateInput!): Job! - createAlphazap(data: AlphazapCreateInput!): Alphazap! - createTresom(data: TresomCreateInput!): Tresom! - createKonklab(data: KonklabCreateInput!): Konklab! - createStim(data: StimCreateInput!): Stim! - createVentosanzap(data: VentosanzapCreateInput!): Ventosanzap! - createVoltsillam(data: VoltsillamCreateInput!): Voltsillam! - createBigtax(data: BigtaxCreateInput!): Bigtax! - createOtcom(data: OtcomCreateInput!): Otcom! - createLatlux(data: LatluxCreateInput!): Latlux! - createStringtough(data: StringtoughCreateInput!): Stringtough! - createTreeflex(data: TreeflexCreateInput!): Treeflex! - createZathin(data: ZathinCreateInput!): Zathin! - createOverhold(data: OverholdCreateInput!): Overhold! - createRedhold(data: RedholdCreateInput!): Redhold! - createHatity(data: HatityCreateInput!): Hatity! - createRonstring(data: RonstringCreateInput!): Ronstring! - createSonair(data: SonairCreateInput!): Sonair! - updateAsset(data: AssetUpdateInput!, where: AssetWhereUniqueInput!): Asset - updateKonklux( - data: KonkluxUpdateInput! - where: KonkluxWhereUniqueInput! - ): Konklux - updateSubin(data: SubinUpdateInput!, where: SubinWhereUniqueInput!): Subin - updateTemp(data: TempUpdateInput!, where: TempWhereUniqueInput!): Temp - updateVoyatouch( - data: VoyatouchUpdateInput! - where: VoyatouchWhereUniqueInput! - ): Voyatouch - updateBamity(data: BamityUpdateInput!, where: BamityWhereUniqueInput!): Bamity - updateZamit(data: ZamitUpdateInput!, where: ZamitWhereUniqueInput!): Zamit - updateKeylex(data: KeylexUpdateInput!, where: KeylexWhereUniqueInput!): Keylex - updateLotstring( - data: LotstringUpdateInput! - where: LotstringWhereUniqueInput! - ): Lotstring - updateViva(data: VivaUpdateInput!, where: VivaWhereUniqueInput!): Viva - updateTranscof( - data: TranscofUpdateInput! - where: TranscofWhereUniqueInput! - ): Transcof - updateDaltfresh( - data: DaltfreshUpdateInput! - where: DaltfreshWhereUniqueInput! - ): Daltfresh - updateLotlux(data: LotluxUpdateInput!, where: LotluxWhereUniqueInput!): Lotlux - updateSonsing( - data: SonsingUpdateInput! - where: SonsingWhereUniqueInput! - ): Sonsing - updateToughjoyfax( - data: ToughjoyfaxUpdateInput! - where: ToughjoyfaxWhereUniqueInput! - ): Toughjoyfax - updateStronghold( - data: StrongholdUpdateInput! - where: StrongholdWhereUniqueInput! - ): Stronghold - updateZoolab(data: ZoolabUpdateInput!, where: ZoolabWhereUniqueInput!): Zoolab - updateJob(data: JobUpdateInput!, where: JobWhereUniqueInput!): Job - updateAlphazap( - data: AlphazapUpdateInput! - where: AlphazapWhereUniqueInput! - ): Alphazap - updateTresom(data: TresomUpdateInput!, where: TresomWhereUniqueInput!): Tresom - updateKonklab( - data: KonklabUpdateInput! - where: KonklabWhereUniqueInput! - ): Konklab - updateStim(data: StimUpdateInput!, where: StimWhereUniqueInput!): Stim - updateVentosanzap( - data: VentosanzapUpdateInput! - where: VentosanzapWhereUniqueInput! - ): Ventosanzap - updateVoltsillam( - data: VoltsillamUpdateInput! - where: VoltsillamWhereUniqueInput! - ): Voltsillam - updateBigtax(data: BigtaxUpdateInput!, where: BigtaxWhereUniqueInput!): Bigtax - updateOtcom(data: OtcomUpdateInput!, where: OtcomWhereUniqueInput!): Otcom - updateLatlux(data: LatluxUpdateInput!, where: LatluxWhereUniqueInput!): Latlux - updateStringtough( - data: StringtoughUpdateInput! - where: StringtoughWhereUniqueInput! - ): Stringtough - updateTreeflex( - data: TreeflexUpdateInput! - where: TreeflexWhereUniqueInput! - ): Treeflex - updateZathin(data: ZathinUpdateInput!, where: ZathinWhereUniqueInput!): Zathin - updateOverhold( - data: OverholdUpdateInput! - where: OverholdWhereUniqueInput! - ): Overhold - updateRedhold( - data: RedholdUpdateInput! - where: RedholdWhereUniqueInput! - ): Redhold - updateHatity(data: HatityUpdateInput!, where: HatityWhereUniqueInput!): Hatity - updateRonstring( - data: RonstringUpdateInput! - where: RonstringWhereUniqueInput! - ): Ronstring - updateSonair(data: SonairUpdateInput!, where: SonairWhereUniqueInput!): Sonair - deleteAsset(where: AssetWhereUniqueInput!): Asset - deleteColor(where: ColorWhereUniqueInput!): Color - deleteLocation(where: LocationWhereUniqueInput!): Location - deleteKonklux(where: KonkluxWhereUniqueInput!): Konklux - deleteSubin(where: SubinWhereUniqueInput!): Subin - deleteTemp(where: TempWhereUniqueInput!): Temp - deleteVoyatouch(where: VoyatouchWhereUniqueInput!): Voyatouch - deleteBamity(where: BamityWhereUniqueInput!): Bamity - deleteZamit(where: ZamitWhereUniqueInput!): Zamit - deleteKeylex(where: KeylexWhereUniqueInput!): Keylex - deleteLotstring(where: LotstringWhereUniqueInput!): Lotstring - deleteViva(where: VivaWhereUniqueInput!): Viva - deleteTranscof(where: TranscofWhereUniqueInput!): Transcof - deleteDaltfresh(where: DaltfreshWhereUniqueInput!): Daltfresh - deleteLotlux(where: LotluxWhereUniqueInput!): Lotlux - deleteSonsing(where: SonsingWhereUniqueInput!): Sonsing - deleteToughjoyfax(where: ToughjoyfaxWhereUniqueInput!): Toughjoyfax - deleteStronghold(where: StrongholdWhereUniqueInput!): Stronghold - deleteZoolab(where: ZoolabWhereUniqueInput!): Zoolab - deleteJob(where: JobWhereUniqueInput!): Job - deleteAlphazap(where: AlphazapWhereUniqueInput!): Alphazap - deleteTresom(where: TresomWhereUniqueInput!): Tresom - deleteKonklab(where: KonklabWhereUniqueInput!): Konklab - deleteStim(where: StimWhereUniqueInput!): Stim - deleteVentosanzap(where: VentosanzapWhereUniqueInput!): Ventosanzap - deleteVoltsillam(where: VoltsillamWhereUniqueInput!): Voltsillam - deleteBigtax(where: BigtaxWhereUniqueInput!): Bigtax - deleteOtcom(where: OtcomWhereUniqueInput!): Otcom - deleteLatlux(where: LatluxWhereUniqueInput!): Latlux - deleteStringtough(where: StringtoughWhereUniqueInput!): Stringtough - deleteTreeflex(where: TreeflexWhereUniqueInput!): Treeflex - deleteZathin(where: ZathinWhereUniqueInput!): Zathin - deleteOverhold(where: OverholdWhereUniqueInput!): Overhold - deleteRedhold(where: RedholdWhereUniqueInput!): Redhold - deleteHatity(where: HatityWhereUniqueInput!): Hatity - deleteRonstring(where: RonstringWhereUniqueInput!): Ronstring - deleteSonair(where: SonairWhereUniqueInput!): Sonair - upsertAsset( - where: AssetWhereUniqueInput! - create: AssetCreateInput! - update: AssetUpdateInput! - ): Asset! - upsertKonklux( - where: KonkluxWhereUniqueInput! - create: KonkluxCreateInput! - update: KonkluxUpdateInput! - ): Konklux! - upsertSubin( - where: SubinWhereUniqueInput! - create: SubinCreateInput! - update: SubinUpdateInput! - ): Subin! - upsertTemp( - where: TempWhereUniqueInput! - create: TempCreateInput! - update: TempUpdateInput! - ): Temp! - upsertVoyatouch( - where: VoyatouchWhereUniqueInput! - create: VoyatouchCreateInput! - update: VoyatouchUpdateInput! - ): Voyatouch! - upsertBamity( - where: BamityWhereUniqueInput! - create: BamityCreateInput! - update: BamityUpdateInput! - ): Bamity! - upsertZamit( - where: ZamitWhereUniqueInput! - create: ZamitCreateInput! - update: ZamitUpdateInput! - ): Zamit! - upsertKeylex( - where: KeylexWhereUniqueInput! - create: KeylexCreateInput! - update: KeylexUpdateInput! - ): Keylex! - upsertLotstring( - where: LotstringWhereUniqueInput! - create: LotstringCreateInput! - update: LotstringUpdateInput! - ): Lotstring! - upsertViva( - where: VivaWhereUniqueInput! - create: VivaCreateInput! - update: VivaUpdateInput! - ): Viva! - upsertTranscof( - where: TranscofWhereUniqueInput! - create: TranscofCreateInput! - update: TranscofUpdateInput! - ): Transcof! - upsertDaltfresh( - where: DaltfreshWhereUniqueInput! - create: DaltfreshCreateInput! - update: DaltfreshUpdateInput! - ): Daltfresh! - upsertLotlux( - where: LotluxWhereUniqueInput! - create: LotluxCreateInput! - update: LotluxUpdateInput! - ): Lotlux! - upsertSonsing( - where: SonsingWhereUniqueInput! - create: SonsingCreateInput! - update: SonsingUpdateInput! - ): Sonsing! - upsertToughjoyfax( - where: ToughjoyfaxWhereUniqueInput! - create: ToughjoyfaxCreateInput! - update: ToughjoyfaxUpdateInput! - ): Toughjoyfax! - upsertStronghold( - where: StrongholdWhereUniqueInput! - create: StrongholdCreateInput! - update: StrongholdUpdateInput! - ): Stronghold! - upsertZoolab( - where: ZoolabWhereUniqueInput! - create: ZoolabCreateInput! - update: ZoolabUpdateInput! - ): Zoolab! - upsertJob( - where: JobWhereUniqueInput! - create: JobCreateInput! - update: JobUpdateInput! - ): Job! - upsertAlphazap( - where: AlphazapWhereUniqueInput! - create: AlphazapCreateInput! - update: AlphazapUpdateInput! - ): Alphazap! - upsertTresom( - where: TresomWhereUniqueInput! - create: TresomCreateInput! - update: TresomUpdateInput! - ): Tresom! - upsertKonklab( - where: KonklabWhereUniqueInput! - create: KonklabCreateInput! - update: KonklabUpdateInput! - ): Konklab! - upsertStim( - where: StimWhereUniqueInput! - create: StimCreateInput! - update: StimUpdateInput! - ): Stim! - upsertVentosanzap( - where: VentosanzapWhereUniqueInput! - create: VentosanzapCreateInput! - update: VentosanzapUpdateInput! - ): Ventosanzap! - upsertVoltsillam( - where: VoltsillamWhereUniqueInput! - create: VoltsillamCreateInput! - update: VoltsillamUpdateInput! - ): Voltsillam! - upsertBigtax( - where: BigtaxWhereUniqueInput! - create: BigtaxCreateInput! - update: BigtaxUpdateInput! - ): Bigtax! - upsertOtcom( - where: OtcomWhereUniqueInput! - create: OtcomCreateInput! - update: OtcomUpdateInput! - ): Otcom! - upsertLatlux( - where: LatluxWhereUniqueInput! - create: LatluxCreateInput! - update: LatluxUpdateInput! - ): Latlux! - upsertStringtough( - where: StringtoughWhereUniqueInput! - create: StringtoughCreateInput! - update: StringtoughUpdateInput! - ): Stringtough! - upsertTreeflex( - where: TreeflexWhereUniqueInput! - create: TreeflexCreateInput! - update: TreeflexUpdateInput! - ): Treeflex! - upsertZathin( - where: ZathinWhereUniqueInput! - create: ZathinCreateInput! - update: ZathinUpdateInput! - ): Zathin! - upsertOverhold( - where: OverholdWhereUniqueInput! - create: OverholdCreateInput! - update: OverholdUpdateInput! - ): Overhold! - upsertRedhold( - where: RedholdWhereUniqueInput! - create: RedholdCreateInput! - update: RedholdUpdateInput! - ): Redhold! - upsertHatity( - where: HatityWhereUniqueInput! - create: HatityCreateInput! - update: HatityUpdateInput! - ): Hatity! - upsertRonstring( - where: RonstringWhereUniqueInput! - create: RonstringCreateInput! - update: RonstringUpdateInput! - ): Ronstring! - upsertSonair( - where: SonairWhereUniqueInput! - create: SonairCreateInput! - update: SonairUpdateInput! - ): Sonair! - updateManyAssets( - data: AssetUpdateManyMutationInput! - where: AssetWhereInput - ): BatchPayload! - updateManyKonkluxes( - data: KonkluxUpdateManyMutationInput! - where: KonkluxWhereInput - ): BatchPayload! - updateManySubins( - data: SubinUpdateManyMutationInput! - where: SubinWhereInput - ): BatchPayload! - updateManyTemps( - data: TempUpdateManyMutationInput! - where: TempWhereInput - ): BatchPayload! - updateManyVoyatouches( - data: VoyatouchUpdateManyMutationInput! - where: VoyatouchWhereInput - ): BatchPayload! - updateManyBamities( - data: BamityUpdateManyMutationInput! - where: BamityWhereInput - ): BatchPayload! - updateManyZamits( - data: ZamitUpdateManyMutationInput! - where: ZamitWhereInput - ): BatchPayload! - updateManyKeylexes( - data: KeylexUpdateManyMutationInput! - where: KeylexWhereInput - ): BatchPayload! - updateManyLotstrings( - data: LotstringUpdateManyMutationInput! - where: LotstringWhereInput - ): BatchPayload! - updateManyVivas( - data: VivaUpdateManyMutationInput! - where: VivaWhereInput - ): BatchPayload! - updateManyTranscofs( - data: TranscofUpdateManyMutationInput! - where: TranscofWhereInput - ): BatchPayload! - updateManyDaltfreshes( - data: DaltfreshUpdateManyMutationInput! - where: DaltfreshWhereInput - ): BatchPayload! - updateManyLotluxes( - data: LotluxUpdateManyMutationInput! - where: LotluxWhereInput - ): BatchPayload! - updateManySonsings( - data: SonsingUpdateManyMutationInput! - where: SonsingWhereInput - ): BatchPayload! - updateManyToughjoyfaxes( - data: ToughjoyfaxUpdateManyMutationInput! - where: ToughjoyfaxWhereInput - ): BatchPayload! - updateManyStrongholds( - data: StrongholdUpdateManyMutationInput! - where: StrongholdWhereInput - ): BatchPayload! - updateManyZoolabs( - data: ZoolabUpdateManyMutationInput! - where: ZoolabWhereInput - ): BatchPayload! - updateManyJobs( - data: JobUpdateManyMutationInput! - where: JobWhereInput - ): BatchPayload! - updateManyAlphazaps( - data: AlphazapUpdateManyMutationInput! - where: AlphazapWhereInput - ): BatchPayload! - updateManyTresoms( - data: TresomUpdateManyMutationInput! - where: TresomWhereInput - ): BatchPayload! - updateManyKonklabs( - data: KonklabUpdateManyMutationInput! - where: KonklabWhereInput - ): BatchPayload! - updateManyStims( - data: StimUpdateManyMutationInput! - where: StimWhereInput - ): BatchPayload! - updateManyVentosanzaps( - data: VentosanzapUpdateManyMutationInput! - where: VentosanzapWhereInput - ): BatchPayload! - updateManyVoltsillams( - data: VoltsillamUpdateManyMutationInput! - where: VoltsillamWhereInput - ): BatchPayload! - updateManyBigtaxes( - data: BigtaxUpdateManyMutationInput! - where: BigtaxWhereInput - ): BatchPayload! - updateManyOtcoms( - data: OtcomUpdateManyMutationInput! - where: OtcomWhereInput - ): BatchPayload! - updateManyLatluxes( - data: LatluxUpdateManyMutationInput! - where: LatluxWhereInput - ): BatchPayload! - updateManyStringtoughs( - data: StringtoughUpdateManyMutationInput! - where: StringtoughWhereInput - ): BatchPayload! - updateManyTreeflexes( - data: TreeflexUpdateManyMutationInput! - where: TreeflexWhereInput - ): BatchPayload! - updateManyZathins( - data: ZathinUpdateManyMutationInput! - where: ZathinWhereInput - ): BatchPayload! - updateManyOverholds( - data: OverholdUpdateManyMutationInput! - where: OverholdWhereInput - ): BatchPayload! - updateManyRedholds( - data: RedholdUpdateManyMutationInput! - where: RedholdWhereInput - ): BatchPayload! - updateManyHatities( - data: HatityUpdateManyMutationInput! - where: HatityWhereInput - ): BatchPayload! - updateManyRonstrings( - data: RonstringUpdateManyMutationInput! - where: RonstringWhereInput - ): BatchPayload! - updateManySonairs( - data: SonairUpdateManyMutationInput! - where: SonairWhereInput - ): BatchPayload! - deleteManyAssets(where: AssetWhereInput): BatchPayload! - deleteManyColors(where: ColorWhereInput): BatchPayload! - deleteManyLocations(where: LocationWhereInput): BatchPayload! - deleteManyKonkluxes(where: KonkluxWhereInput): BatchPayload! - deleteManySubins(where: SubinWhereInput): BatchPayload! - deleteManyTemps(where: TempWhereInput): BatchPayload! - deleteManyVoyatouches(where: VoyatouchWhereInput): BatchPayload! - deleteManyBamities(where: BamityWhereInput): BatchPayload! - deleteManyZamits(where: ZamitWhereInput): BatchPayload! - deleteManyKeylexes(where: KeylexWhereInput): BatchPayload! - deleteManyLotstrings(where: LotstringWhereInput): BatchPayload! - deleteManyVivas(where: VivaWhereInput): BatchPayload! - deleteManyTranscofs(where: TranscofWhereInput): BatchPayload! - deleteManyDaltfreshes(where: DaltfreshWhereInput): BatchPayload! - deleteManyLotluxes(where: LotluxWhereInput): BatchPayload! - deleteManySonsings(where: SonsingWhereInput): BatchPayload! - deleteManyToughjoyfaxes(where: ToughjoyfaxWhereInput): BatchPayload! - deleteManyStrongholds(where: StrongholdWhereInput): BatchPayload! - deleteManyZoolabs(where: ZoolabWhereInput): BatchPayload! - deleteManyJobs(where: JobWhereInput): BatchPayload! - deleteManyAlphazaps(where: AlphazapWhereInput): BatchPayload! - deleteManyTresoms(where: TresomWhereInput): BatchPayload! - deleteManyKonklabs(where: KonklabWhereInput): BatchPayload! - deleteManyStims(where: StimWhereInput): BatchPayload! - deleteManyVentosanzaps(where: VentosanzapWhereInput): BatchPayload! - deleteManyVoltsillams(where: VoltsillamWhereInput): BatchPayload! - deleteManyBigtaxes(where: BigtaxWhereInput): BatchPayload! - deleteManyOtcoms(where: OtcomWhereInput): BatchPayload! - deleteManyLatluxes(where: LatluxWhereInput): BatchPayload! - deleteManyStringtoughs(where: StringtoughWhereInput): BatchPayload! - deleteManyTreeflexes(where: TreeflexWhereInput): BatchPayload! - deleteManyZathins(where: ZathinWhereInput): BatchPayload! - deleteManyOverholds(where: OverholdWhereInput): BatchPayload! - deleteManyRedholds(where: RedholdWhereInput): BatchPayload! - deleteManyHatities(where: HatityWhereInput): BatchPayload! - deleteManyRonstrings(where: RonstringWhereInput): BatchPayload! - deleteManySonairs(where: SonairWhereInput): BatchPayload! -} - -enum MutationType { - CREATED - UPDATED - DELETED -} - -# An object with an ID -interface Node { - # The id of the object. - id: ID! -} - -type Otcom implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - teal: Daugherty! - orange: String - maroon: String - purple: String - gold: Asset - violet: Boolean - pink: Int -} - -# A connection to a list of items. -type OtcomConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [OtcomEdge]! - aggregate: AggregateOtcom! -} - -input OtcomCreateInput { - status: Status - teal: Daugherty! - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int - gold: AssetCreateOneWithoutGoldOtcomInput -} - -input OtcomCreateManyWithoutGoldInput { - create: [OtcomCreateWithoutGoldInput!] - connect: [OtcomWhereUniqueInput!] -} - -input OtcomCreateWithoutGoldInput { - status: Status - teal: Daugherty! - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int -} - -# An edge in a connection. -type OtcomEdge { - # The item at the end of the edge. - node: Otcom! - # A cursor for use in pagination. - cursor: String! -} - -enum OtcomOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - teal_ASC - teal_DESC - orange_ASC - orange_DESC - maroon_ASC - maroon_DESC - purple_ASC - purple_DESC - violet_ASC - violet_DESC - pink_ASC - pink_DESC -} - -type OtcomPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - teal: Daugherty! - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int -} - -input OtcomScalarWhereInput { - # Logical AND on all given filters. - AND: [OtcomScalarWhereInput!] - # Logical OR on all given filters. - OR: [OtcomScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [OtcomScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - teal: Daugherty - # All values that are not equal to given value. - teal_not: Daugherty - # All values that are contained in given list. - teal_in: [Daugherty!] - # All values that are not contained in given list. - teal_not_in: [Daugherty!] - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - maroon: String - # All values that are not equal to given value. - maroon_not: String - # All values that are contained in given list. - maroon_in: [String!] - # All values that are not contained in given list. - maroon_not_in: [String!] - # All values less than the given value. - maroon_lt: String - # All values less than or equal the given value. - maroon_lte: String - # All values greater than the given value. - maroon_gt: String - # All values greater than or equal the given value. - maroon_gte: String - # All values containing the given string. - maroon_contains: String - # All values not containing the given string. - maroon_not_contains: String - # All values starting with the given string. - maroon_starts_with: String - # All values not starting with the given string. - maroon_not_starts_with: String - # All values ending with the given string. - maroon_ends_with: String - # All values not ending with the given string. - maroon_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - violet: Boolean - # All values that are not equal to given value. - violet_not: Boolean - pink: Int - # All values that are not equal to given value. - pink_not: Int - # All values that are contained in given list. - pink_in: [Int!] - # All values that are not contained in given list. - pink_not_in: [Int!] - # All values less than the given value. - pink_lt: Int - # All values less than or equal the given value. - pink_lte: Int - # All values greater than the given value. - pink_gt: Int - # All values greater than or equal the given value. - pink_gte: Int -} - -type OtcomSubscriptionPayload { - mutation: MutationType! - node: Otcom - updatedFields: [String!] - previousValues: OtcomPreviousValues -} - -input OtcomSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [OtcomSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [OtcomSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [OtcomSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: OtcomWhereInput -} - -input OtcomUpdateInput { - status: Status - teal: Daugherty - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int - gold: AssetUpdateOneWithoutGoldOtcomInput -} - -input OtcomUpdateManyDataInput { - status: Status - teal: Daugherty - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int -} - -input OtcomUpdateManyMutationInput { - status: Status - teal: Daugherty - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int -} - -input OtcomUpdateManyWithoutGoldInput { - create: [OtcomCreateWithoutGoldInput!] - connect: [OtcomWhereUniqueInput!] - set: [OtcomWhereUniqueInput!] - disconnect: [OtcomWhereUniqueInput!] - delete: [OtcomWhereUniqueInput!] - update: [OtcomUpdateWithWhereUniqueWithoutGoldInput!] - updateMany: [OtcomUpdateManyWithWhereNestedInput!] - deleteMany: [OtcomScalarWhereInput!] - upsert: [OtcomUpsertWithWhereUniqueWithoutGoldInput!] -} - -input OtcomUpdateManyWithWhereNestedInput { - where: OtcomScalarWhereInput! - data: OtcomUpdateManyDataInput! -} - -input OtcomUpdateWithoutGoldDataInput { - status: Status - teal: Daugherty - orange: String - maroon: String - purple: String - violet: Boolean - pink: Int -} - -input OtcomUpdateWithWhereUniqueWithoutGoldInput { - where: OtcomWhereUniqueInput! - data: OtcomUpdateWithoutGoldDataInput! -} - -input OtcomUpsertWithWhereUniqueWithoutGoldInput { - where: OtcomWhereUniqueInput! - update: OtcomUpdateWithoutGoldDataInput! - create: OtcomCreateWithoutGoldInput! -} - -input OtcomWhereInput { - # Logical AND on all given filters. - AND: [OtcomWhereInput!] - # Logical OR on all given filters. - OR: [OtcomWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [OtcomWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - teal: Daugherty - # All values that are not equal to given value. - teal_not: Daugherty - # All values that are contained in given list. - teal_in: [Daugherty!] - # All values that are not contained in given list. - teal_not_in: [Daugherty!] - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - maroon: String - # All values that are not equal to given value. - maroon_not: String - # All values that are contained in given list. - maroon_in: [String!] - # All values that are not contained in given list. - maroon_not_in: [String!] - # All values less than the given value. - maroon_lt: String - # All values less than or equal the given value. - maroon_lte: String - # All values greater than the given value. - maroon_gt: String - # All values greater than or equal the given value. - maroon_gte: String - # All values containing the given string. - maroon_contains: String - # All values not containing the given string. - maroon_not_contains: String - # All values starting with the given string. - maroon_starts_with: String - # All values not starting with the given string. - maroon_not_starts_with: String - # All values ending with the given string. - maroon_ends_with: String - # All values not ending with the given string. - maroon_not_ends_with: String - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - violet: Boolean - # All values that are not equal to given value. - violet_not: Boolean - pink: Int - # All values that are not equal to given value. - pink_not: Int - # All values that are contained in given list. - pink_in: [Int!] - # All values that are not contained in given list. - pink_not_in: [Int!] - # All values less than the given value. - pink_lt: Int - # All values less than or equal the given value. - pink_lte: Int - # All values greater than the given value. - pink_gt: Int - # All values greater than or equal the given value. - pink_gte: Int - gold: AssetWhereInput -} - -input OtcomWhereUniqueInput { - id: ID - teal: Daugherty -} - -type Overhold implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - azure: String! - orchid: [Daugherty!]! - magenta: String! -} - -# A connection to a list of items. -type OverholdConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [OverholdEdge]! - aggregate: AggregateOverhold! -} - -input OverholdCreateInput { - status: Status - azure: String! - magenta: String! - orchid: OverholdCreateorchidInput -} - -input OverholdCreateorchidInput { - set: [Daugherty!] -} - -# An edge in a connection. -type OverholdEdge { - # The item at the end of the edge. - node: Overhold! - # A cursor for use in pagination. - cursor: String! -} - -enum OverholdOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - azure_ASC - azure_DESC - magenta_ASC - magenta_DESC -} - -type OverholdPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - azure: String! - orchid: [Daugherty!]! - magenta: String! -} - -type OverholdSubscriptionPayload { - mutation: MutationType! - node: Overhold - updatedFields: [String!] - previousValues: OverholdPreviousValues -} - -input OverholdSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [OverholdSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [OverholdSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [OverholdSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: OverholdWhereInput -} - -input OverholdUpdateInput { - status: Status - azure: String - magenta: String - orchid: OverholdUpdateorchidInput -} - -input OverholdUpdateManyMutationInput { - status: Status - azure: String - magenta: String - orchid: OverholdUpdateorchidInput -} - -input OverholdUpdateorchidInput { - set: [Daugherty!] -} - -input OverholdWhereInput { - # Logical AND on all given filters. - AND: [OverholdWhereInput!] - # Logical OR on all given filters. - OR: [OverholdWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [OverholdWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - azure: String - # All values that are not equal to given value. - azure_not: String - # All values that are contained in given list. - azure_in: [String!] - # All values that are not contained in given list. - azure_not_in: [String!] - # All values less than the given value. - azure_lt: String - # All values less than or equal the given value. - azure_lte: String - # All values greater than the given value. - azure_gt: String - # All values greater than or equal the given value. - azure_gte: String - # All values containing the given string. - azure_contains: String - # All values not containing the given string. - azure_not_contains: String - # All values starting with the given string. - azure_starts_with: String - # All values not starting with the given string. - azure_not_starts_with: String - # All values ending with the given string. - azure_ends_with: String - # All values not ending with the given string. - azure_not_ends_with: String - magenta: String - # All values that are not equal to given value. - magenta_not: String - # All values that are contained in given list. - magenta_in: [String!] - # All values that are not contained in given list. - magenta_not_in: [String!] - # All values less than the given value. - magenta_lt: String - # All values less than or equal the given value. - magenta_lte: String - # All values greater than the given value. - magenta_gt: String - # All values greater than or equal the given value. - magenta_gte: String - # All values containing the given string. - magenta_contains: String - # All values not containing the given string. - magenta_not_contains: String - # All values starting with the given string. - magenta_starts_with: String - # All values not starting with the given string. - magenta_not_starts_with: String - # All values ending with the given string. - magenta_ends_with: String - # All values not ending with the given string. - magenta_not_ends_with: String -} - -input OverholdWhereUniqueInput { - id: ID - azure: String - magenta: String -} - -# Information about pagination in a connection. -type PageInfo { - # When paginating forwards, are there more items? - hasNextPage: Boolean! - # When paginating backwards, are there more items? - hasPreviousPage: Boolean! - # When paginating backwards, the cursor to continue. - startCursor: String - # When paginating forwards, the cursor to continue. - endCursor: String -} - -enum Parker { - EUM - ET - ASSUMENDA -} - -type Query { - assets( - where: AssetWhereInput - orderBy: AssetOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Asset]! - colors( - where: ColorWhereInput - orderBy: ColorOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Color]! - locations( - where: LocationWhereInput - orderBy: LocationOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Location]! - konkluxes( - where: KonkluxWhereInput - orderBy: KonkluxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Konklux]! - subins( - where: SubinWhereInput - orderBy: SubinOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Subin]! - temps( - where: TempWhereInput - orderBy: TempOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Temp]! - voyatouches( - where: VoyatouchWhereInput - orderBy: VoyatouchOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Voyatouch]! - bamities( - where: BamityWhereInput - orderBy: BamityOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Bamity]! - zamits( - where: ZamitWhereInput - orderBy: ZamitOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Zamit]! - keylexes( - where: KeylexWhereInput - orderBy: KeylexOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Keylex]! - lotstrings( - where: LotstringWhereInput - orderBy: LotstringOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Lotstring]! - vivas( - where: VivaWhereInput - orderBy: VivaOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Viva]! - transcofs( - where: TranscofWhereInput - orderBy: TranscofOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Transcof]! - daltfreshes( - where: DaltfreshWhereInput - orderBy: DaltfreshOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Daltfresh]! - lotluxes( - where: LotluxWhereInput - orderBy: LotluxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Lotlux]! - sonsings( - where: SonsingWhereInput - orderBy: SonsingOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Sonsing]! - toughjoyfaxes( - where: ToughjoyfaxWhereInput - orderBy: ToughjoyfaxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Toughjoyfax]! - strongholds( - where: StrongholdWhereInput - orderBy: StrongholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stronghold]! - zoolabs( - where: ZoolabWhereInput - orderBy: ZoolabOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Zoolab]! - jobs( - where: JobWhereInput - orderBy: JobOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Job]! - alphazaps( - where: AlphazapWhereInput - orderBy: AlphazapOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Alphazap]! - tresoms( - where: TresomWhereInput - orderBy: TresomOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Tresom]! - konklabs( - where: KonklabWhereInput - orderBy: KonklabOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Konklab]! - stims( - where: StimWhereInput - orderBy: StimOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stim]! - ventosanzaps( - where: VentosanzapWhereInput - orderBy: VentosanzapOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Ventosanzap]! - voltsillams( - where: VoltsillamWhereInput - orderBy: VoltsillamOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Voltsillam]! - bigtaxes( - where: BigtaxWhereInput - orderBy: BigtaxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Bigtax]! - otcoms( - where: OtcomWhereInput - orderBy: OtcomOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Otcom]! - latluxes( - where: LatluxWhereInput - orderBy: LatluxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Latlux]! - stringtoughs( - where: StringtoughWhereInput - orderBy: StringtoughOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Stringtough]! - treeflexes( - where: TreeflexWhereInput - orderBy: TreeflexOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Treeflex]! - zathins( - where: ZathinWhereInput - orderBy: ZathinOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Zathin]! - overholds( - where: OverholdWhereInput - orderBy: OverholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Overhold]! - redholds( - where: RedholdWhereInput - orderBy: RedholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Redhold]! - hatities( - where: HatityWhereInput - orderBy: HatityOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Hatity]! - ronstrings( - where: RonstringWhereInput - orderBy: RonstringOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Ronstring]! - sonairs( - where: SonairWhereInput - orderBy: SonairOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Sonair]! - asset(where: AssetWhereUniqueInput!): Asset - color(where: ColorWhereUniqueInput!): Color - location(where: LocationWhereUniqueInput!): Location - konklux(where: KonkluxWhereUniqueInput!): Konklux - subin(where: SubinWhereUniqueInput!): Subin - temp(where: TempWhereUniqueInput!): Temp - voyatouch(where: VoyatouchWhereUniqueInput!): Voyatouch - bamity(where: BamityWhereUniqueInput!): Bamity - zamit(where: ZamitWhereUniqueInput!): Zamit - keylex(where: KeylexWhereUniqueInput!): Keylex - lotstring(where: LotstringWhereUniqueInput!): Lotstring - viva(where: VivaWhereUniqueInput!): Viva - transcof(where: TranscofWhereUniqueInput!): Transcof - daltfresh(where: DaltfreshWhereUniqueInput!): Daltfresh - lotlux(where: LotluxWhereUniqueInput!): Lotlux - sonsing(where: SonsingWhereUniqueInput!): Sonsing - toughjoyfax(where: ToughjoyfaxWhereUniqueInput!): Toughjoyfax - stronghold(where: StrongholdWhereUniqueInput!): Stronghold - zoolab(where: ZoolabWhereUniqueInput!): Zoolab - job(where: JobWhereUniqueInput!): Job - alphazap(where: AlphazapWhereUniqueInput!): Alphazap - tresom(where: TresomWhereUniqueInput!): Tresom - konklab(where: KonklabWhereUniqueInput!): Konklab - stim(where: StimWhereUniqueInput!): Stim - ventosanzap(where: VentosanzapWhereUniqueInput!): Ventosanzap - voltsillam(where: VoltsillamWhereUniqueInput!): Voltsillam - bigtax(where: BigtaxWhereUniqueInput!): Bigtax - otcom(where: OtcomWhereUniqueInput!): Otcom - latlux(where: LatluxWhereUniqueInput!): Latlux - stringtough(where: StringtoughWhereUniqueInput!): Stringtough - treeflex(where: TreeflexWhereUniqueInput!): Treeflex - zathin(where: ZathinWhereUniqueInput!): Zathin - overhold(where: OverholdWhereUniqueInput!): Overhold - redhold(where: RedholdWhereUniqueInput!): Redhold - hatity(where: HatityWhereUniqueInput!): Hatity - ronstring(where: RonstringWhereUniqueInput!): Ronstring - sonair(where: SonairWhereUniqueInput!): Sonair - assetsConnection( - where: AssetWhereInput - orderBy: AssetOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): AssetConnection! - colorsConnection( - where: ColorWhereInput - orderBy: ColorOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): ColorConnection! - locationsConnection( - where: LocationWhereInput - orderBy: LocationOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): LocationConnection! - konkluxesConnection( - where: KonkluxWhereInput - orderBy: KonkluxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): KonkluxConnection! - subinsConnection( - where: SubinWhereInput - orderBy: SubinOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): SubinConnection! - tempsConnection( - where: TempWhereInput - orderBy: TempOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): TempConnection! - voyatouchesConnection( - where: VoyatouchWhereInput - orderBy: VoyatouchOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): VoyatouchConnection! - bamitiesConnection( - where: BamityWhereInput - orderBy: BamityOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): BamityConnection! - zamitsConnection( - where: ZamitWhereInput - orderBy: ZamitOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): ZamitConnection! - keylexesConnection( - where: KeylexWhereInput - orderBy: KeylexOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): KeylexConnection! - lotstringsConnection( - where: LotstringWhereInput - orderBy: LotstringOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): LotstringConnection! - vivasConnection( - where: VivaWhereInput - orderBy: VivaOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): VivaConnection! - transcofsConnection( - where: TranscofWhereInput - orderBy: TranscofOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): TranscofConnection! - daltfreshesConnection( - where: DaltfreshWhereInput - orderBy: DaltfreshOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): DaltfreshConnection! - lotluxesConnection( - where: LotluxWhereInput - orderBy: LotluxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): LotluxConnection! - sonsingsConnection( - where: SonsingWhereInput - orderBy: SonsingOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): SonsingConnection! - toughjoyfaxesConnection( - where: ToughjoyfaxWhereInput - orderBy: ToughjoyfaxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): ToughjoyfaxConnection! - strongholdsConnection( - where: StrongholdWhereInput - orderBy: StrongholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): StrongholdConnection! - zoolabsConnection( - where: ZoolabWhereInput - orderBy: ZoolabOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): ZoolabConnection! - jobsConnection( - where: JobWhereInput - orderBy: JobOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): JobConnection! - alphazapsConnection( - where: AlphazapWhereInput - orderBy: AlphazapOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): AlphazapConnection! - tresomsConnection( - where: TresomWhereInput - orderBy: TresomOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): TresomConnection! - konklabsConnection( - where: KonklabWhereInput - orderBy: KonklabOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): KonklabConnection! - stimsConnection( - where: StimWhereInput - orderBy: StimOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): StimConnection! - ventosanzapsConnection( - where: VentosanzapWhereInput - orderBy: VentosanzapOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): VentosanzapConnection! - voltsillamsConnection( - where: VoltsillamWhereInput - orderBy: VoltsillamOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): VoltsillamConnection! - bigtaxesConnection( - where: BigtaxWhereInput - orderBy: BigtaxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): BigtaxConnection! - otcomsConnection( - where: OtcomWhereInput - orderBy: OtcomOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): OtcomConnection! - latluxesConnection( - where: LatluxWhereInput - orderBy: LatluxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): LatluxConnection! - stringtoughsConnection( - where: StringtoughWhereInput - orderBy: StringtoughOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): StringtoughConnection! - treeflexesConnection( - where: TreeflexWhereInput - orderBy: TreeflexOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): TreeflexConnection! - zathinsConnection( - where: ZathinWhereInput - orderBy: ZathinOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): ZathinConnection! - overholdsConnection( - where: OverholdWhereInput - orderBy: OverholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): OverholdConnection! - redholdsConnection( - where: RedholdWhereInput - orderBy: RedholdOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): RedholdConnection! - hatitiesConnection( - where: HatityWhereInput - orderBy: HatityOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): HatityConnection! - ronstringsConnection( - where: RonstringWhereInput - orderBy: RonstringOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): RonstringConnection! - sonairsConnection( - where: SonairWhereInput - orderBy: SonairOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): SonairConnection! - # Fetches an object given its ID - node( - # The ID of an object - id: ID! - ): Node -} - -type Redhold implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - purple: Int - grey: String! - orchid: String - yellow: String! - white: String! - salmon: DateTime! - plum: DateTime! - olive: Hatity - tan: Mraz - black: Von -} - -# A connection to a list of items. -type RedholdConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [RedholdEdge]! - aggregate: AggregateRedhold! -} - -input RedholdCreateInput { - status: Status - purple: Int - grey: String! - orchid: String - yellow: String! - white: String! - salmon: DateTime! - plum: DateTime! - tan: Mraz - black: Von - olive: HatityCreateOneWithoutTurquoiseInput -} - -input RedholdCreateManyWithoutOliveInput { - create: [RedholdCreateWithoutOliveInput!] - connect: [RedholdWhereUniqueInput!] -} - -input RedholdCreateWithoutOliveInput { - status: Status - purple: Int - grey: String! - orchid: String - yellow: String! - white: String! - salmon: DateTime! - plum: DateTime! - tan: Mraz - black: Von -} - -# An edge in a connection. -type RedholdEdge { - # The item at the end of the edge. - node: Redhold! - # A cursor for use in pagination. - cursor: String! -} - -enum RedholdOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - purple_ASC - purple_DESC - grey_ASC - grey_DESC - orchid_ASC - orchid_DESC - yellow_ASC - yellow_DESC - white_ASC - white_DESC - salmon_ASC - salmon_DESC - plum_ASC - plum_DESC - tan_ASC - tan_DESC - black_ASC - black_DESC -} - -type RedholdPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - purple: Int - grey: String! - orchid: String - yellow: String! - white: String! - salmon: DateTime! - plum: DateTime! - tan: Mraz - black: Von -} - -input RedholdScalarWhereInput { - # Logical AND on all given filters. - AND: [RedholdScalarWhereInput!] - # Logical OR on all given filters. - OR: [RedholdScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [RedholdScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - purple: Int - # All values that are not equal to given value. - purple_not: Int - # All values that are contained in given list. - purple_in: [Int!] - # All values that are not contained in given list. - purple_not_in: [Int!] - # All values less than the given value. - purple_lt: Int - # All values less than or equal the given value. - purple_lte: Int - # All values greater than the given value. - purple_gt: Int - # All values greater than or equal the given value. - purple_gte: Int - grey: String - # All values that are not equal to given value. - grey_not: String - # All values that are contained in given list. - grey_in: [String!] - # All values that are not contained in given list. - grey_not_in: [String!] - # All values less than the given value. - grey_lt: String - # All values less than or equal the given value. - grey_lte: String - # All values greater than the given value. - grey_gt: String - # All values greater than or equal the given value. - grey_gte: String - # All values containing the given string. - grey_contains: String - # All values not containing the given string. - grey_not_contains: String - # All values starting with the given string. - grey_starts_with: String - # All values not starting with the given string. - grey_not_starts_with: String - # All values ending with the given string. - grey_ends_with: String - # All values not ending with the given string. - grey_not_ends_with: String - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - yellow: String - # All values that are not equal to given value. - yellow_not: String - # All values that are contained in given list. - yellow_in: [String!] - # All values that are not contained in given list. - yellow_not_in: [String!] - # All values less than the given value. - yellow_lt: String - # All values less than or equal the given value. - yellow_lte: String - # All values greater than the given value. - yellow_gt: String - # All values greater than or equal the given value. - yellow_gte: String - # All values containing the given string. - yellow_contains: String - # All values not containing the given string. - yellow_not_contains: String - # All values starting with the given string. - yellow_starts_with: String - # All values not starting with the given string. - yellow_not_starts_with: String - # All values ending with the given string. - yellow_ends_with: String - # All values not ending with the given string. - yellow_not_ends_with: String - white: String - # All values that are not equal to given value. - white_not: String - # All values that are contained in given list. - white_in: [String!] - # All values that are not contained in given list. - white_not_in: [String!] - # All values less than the given value. - white_lt: String - # All values less than or equal the given value. - white_lte: String - # All values greater than the given value. - white_gt: String - # All values greater than or equal the given value. - white_gte: String - # All values containing the given string. - white_contains: String - # All values not containing the given string. - white_not_contains: String - # All values starting with the given string. - white_starts_with: String - # All values not starting with the given string. - white_not_starts_with: String - # All values ending with the given string. - white_ends_with: String - # All values not ending with the given string. - white_not_ends_with: String - salmon: DateTime - # All values that are not equal to given value. - salmon_not: DateTime - # All values that are contained in given list. - salmon_in: [DateTime!] - # All values that are not contained in given list. - salmon_not_in: [DateTime!] - # All values less than the given value. - salmon_lt: DateTime - # All values less than or equal the given value. - salmon_lte: DateTime - # All values greater than the given value. - salmon_gt: DateTime - # All values greater than or equal the given value. - salmon_gte: DateTime - plum: DateTime - # All values that are not equal to given value. - plum_not: DateTime - # All values that are contained in given list. - plum_in: [DateTime!] - # All values that are not contained in given list. - plum_not_in: [DateTime!] - # All values less than the given value. - plum_lt: DateTime - # All values less than or equal the given value. - plum_lte: DateTime - # All values greater than the given value. - plum_gt: DateTime - # All values greater than or equal the given value. - plum_gte: DateTime - tan: Mraz - # All values that are not equal to given value. - tan_not: Mraz - # All values that are contained in given list. - tan_in: [Mraz!] - # All values that are not contained in given list. - tan_not_in: [Mraz!] - black: Von - # All values that are not equal to given value. - black_not: Von - # All values that are contained in given list. - black_in: [Von!] - # All values that are not contained in given list. - black_not_in: [Von!] -} - -type RedholdSubscriptionPayload { - mutation: MutationType! - node: Redhold - updatedFields: [String!] - previousValues: RedholdPreviousValues -} - -input RedholdSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [RedholdSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [RedholdSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [RedholdSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: RedholdWhereInput -} - -input RedholdUpdateInput { - status: Status - purple: Int - grey: String - orchid: String - yellow: String - white: String - salmon: DateTime - plum: DateTime - tan: Mraz - black: Von - olive: HatityUpdateOneWithoutTurquoiseInput -} - -input RedholdUpdateManyDataInput { - status: Status - purple: Int - grey: String - orchid: String - yellow: String - white: String - salmon: DateTime - plum: DateTime - tan: Mraz - black: Von -} - -input RedholdUpdateManyMutationInput { - status: Status - purple: Int - grey: String - orchid: String - yellow: String - white: String - salmon: DateTime - plum: DateTime - tan: Mraz - black: Von -} - -input RedholdUpdateManyWithoutOliveInput { - create: [RedholdCreateWithoutOliveInput!] - connect: [RedholdWhereUniqueInput!] - set: [RedholdWhereUniqueInput!] - disconnect: [RedholdWhereUniqueInput!] - delete: [RedholdWhereUniqueInput!] - update: [RedholdUpdateWithWhereUniqueWithoutOliveInput!] - updateMany: [RedholdUpdateManyWithWhereNestedInput!] - deleteMany: [RedholdScalarWhereInput!] - upsert: [RedholdUpsertWithWhereUniqueWithoutOliveInput!] -} - -input RedholdUpdateManyWithWhereNestedInput { - where: RedholdScalarWhereInput! - data: RedholdUpdateManyDataInput! -} - -input RedholdUpdateWithoutOliveDataInput { - status: Status - purple: Int - grey: String - orchid: String - yellow: String - white: String - salmon: DateTime - plum: DateTime - tan: Mraz - black: Von -} - -input RedholdUpdateWithWhereUniqueWithoutOliveInput { - where: RedholdWhereUniqueInput! - data: RedholdUpdateWithoutOliveDataInput! -} - -input RedholdUpsertWithWhereUniqueWithoutOliveInput { - where: RedholdWhereUniqueInput! - update: RedholdUpdateWithoutOliveDataInput! - create: RedholdCreateWithoutOliveInput! -} - -input RedholdWhereInput { - # Logical AND on all given filters. - AND: [RedholdWhereInput!] - # Logical OR on all given filters. - OR: [RedholdWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [RedholdWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - purple: Int - # All values that are not equal to given value. - purple_not: Int - # All values that are contained in given list. - purple_in: [Int!] - # All values that are not contained in given list. - purple_not_in: [Int!] - # All values less than the given value. - purple_lt: Int - # All values less than or equal the given value. - purple_lte: Int - # All values greater than the given value. - purple_gt: Int - # All values greater than or equal the given value. - purple_gte: Int - grey: String - # All values that are not equal to given value. - grey_not: String - # All values that are contained in given list. - grey_in: [String!] - # All values that are not contained in given list. - grey_not_in: [String!] - # All values less than the given value. - grey_lt: String - # All values less than or equal the given value. - grey_lte: String - # All values greater than the given value. - grey_gt: String - # All values greater than or equal the given value. - grey_gte: String - # All values containing the given string. - grey_contains: String - # All values not containing the given string. - grey_not_contains: String - # All values starting with the given string. - grey_starts_with: String - # All values not starting with the given string. - grey_not_starts_with: String - # All values ending with the given string. - grey_ends_with: String - # All values not ending with the given string. - grey_not_ends_with: String - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - yellow: String - # All values that are not equal to given value. - yellow_not: String - # All values that are contained in given list. - yellow_in: [String!] - # All values that are not contained in given list. - yellow_not_in: [String!] - # All values less than the given value. - yellow_lt: String - # All values less than or equal the given value. - yellow_lte: String - # All values greater than the given value. - yellow_gt: String - # All values greater than or equal the given value. - yellow_gte: String - # All values containing the given string. - yellow_contains: String - # All values not containing the given string. - yellow_not_contains: String - # All values starting with the given string. - yellow_starts_with: String - # All values not starting with the given string. - yellow_not_starts_with: String - # All values ending with the given string. - yellow_ends_with: String - # All values not ending with the given string. - yellow_not_ends_with: String - white: String - # All values that are not equal to given value. - white_not: String - # All values that are contained in given list. - white_in: [String!] - # All values that are not contained in given list. - white_not_in: [String!] - # All values less than the given value. - white_lt: String - # All values less than or equal the given value. - white_lte: String - # All values greater than the given value. - white_gt: String - # All values greater than or equal the given value. - white_gte: String - # All values containing the given string. - white_contains: String - # All values not containing the given string. - white_not_contains: String - # All values starting with the given string. - white_starts_with: String - # All values not starting with the given string. - white_not_starts_with: String - # All values ending with the given string. - white_ends_with: String - # All values not ending with the given string. - white_not_ends_with: String - salmon: DateTime - # All values that are not equal to given value. - salmon_not: DateTime - # All values that are contained in given list. - salmon_in: [DateTime!] - # All values that are not contained in given list. - salmon_not_in: [DateTime!] - # All values less than the given value. - salmon_lt: DateTime - # All values less than or equal the given value. - salmon_lte: DateTime - # All values greater than the given value. - salmon_gt: DateTime - # All values greater than or equal the given value. - salmon_gte: DateTime - plum: DateTime - # All values that are not equal to given value. - plum_not: DateTime - # All values that are contained in given list. - plum_in: [DateTime!] - # All values that are not contained in given list. - plum_not_in: [DateTime!] - # All values less than the given value. - plum_lt: DateTime - # All values less than or equal the given value. - plum_lte: DateTime - # All values greater than the given value. - plum_gt: DateTime - # All values greater than or equal the given value. - plum_gte: DateTime - tan: Mraz - # All values that are not equal to given value. - tan_not: Mraz - # All values that are contained in given list. - tan_in: [Mraz!] - # All values that are not contained in given list. - tan_not_in: [Mraz!] - black: Von - # All values that are not equal to given value. - black_not: Von - # All values that are contained in given list. - black_in: [Von!] - # All values that are not contained in given list. - black_not_in: [Von!] - olive: HatityWhereInput -} - -input RedholdWhereUniqueInput { - id: ID - purple: Int -} - -enum Rice { - UT - DELECTUS - CORRUPTI -} - -type RichText { - raw: RichTextAST - html: String - markdown: String - text: String -} - -scalar RichTextAST - -type Ronstring implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - indigo: [String!]! - plum: String! - blue( - where: TempWhereInput - orderBy: TempOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Temp!] -} - -# A connection to a list of items. -type RonstringConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [RonstringEdge]! - aggregate: AggregateRonstring! -} - -input RonstringCreateindigoInput { - set: [String!] -} - -input RonstringCreateInput { - status: Status - plum: String! - indigo: RonstringCreateindigoInput - blue: TempCreateManyWithoutTurquoiseInput -} - -input RonstringCreateManyWithoutBlueInput { - create: [RonstringCreateWithoutBlueInput!] - connect: [RonstringWhereUniqueInput!] -} - -input RonstringCreateWithoutBlueInput { - status: Status - plum: String! - indigo: RonstringCreateindigoInput -} - -# An edge in a connection. -type RonstringEdge { - # The item at the end of the edge. - node: Ronstring! - # A cursor for use in pagination. - cursor: String! -} - -enum RonstringOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - plum_ASC - plum_DESC -} - -type RonstringPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - indigo: [String!]! - plum: String! -} - -input RonstringScalarWhereInput { - # Logical AND on all given filters. - AND: [RonstringScalarWhereInput!] - # Logical OR on all given filters. - OR: [RonstringScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [RonstringScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String -} - -type RonstringSubscriptionPayload { - mutation: MutationType! - node: Ronstring - updatedFields: [String!] - previousValues: RonstringPreviousValues -} - -input RonstringSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [RonstringSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [RonstringSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [RonstringSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: RonstringWhereInput -} - -input RonstringUpdateindigoInput { - set: [String!] -} - -input RonstringUpdateInput { - status: Status - plum: String - indigo: RonstringUpdateindigoInput - blue: TempUpdateManyWithoutTurquoiseInput -} - -input RonstringUpdateManyDataInput { - status: Status - plum: String - indigo: RonstringUpdateindigoInput -} - -input RonstringUpdateManyMutationInput { - status: Status - plum: String - indigo: RonstringUpdateindigoInput -} - -input RonstringUpdateManyWithoutBlueInput { - create: [RonstringCreateWithoutBlueInput!] - connect: [RonstringWhereUniqueInput!] - set: [RonstringWhereUniqueInput!] - disconnect: [RonstringWhereUniqueInput!] - delete: [RonstringWhereUniqueInput!] - update: [RonstringUpdateWithWhereUniqueWithoutBlueInput!] - updateMany: [RonstringUpdateManyWithWhereNestedInput!] - deleteMany: [RonstringScalarWhereInput!] - upsert: [RonstringUpsertWithWhereUniqueWithoutBlueInput!] -} - -input RonstringUpdateManyWithWhereNestedInput { - where: RonstringScalarWhereInput! - data: RonstringUpdateManyDataInput! -} - -input RonstringUpdateWithoutBlueDataInput { - status: Status - plum: String - indigo: RonstringUpdateindigoInput -} - -input RonstringUpdateWithWhereUniqueWithoutBlueInput { - where: RonstringWhereUniqueInput! - data: RonstringUpdateWithoutBlueDataInput! -} - -input RonstringUpsertWithWhereUniqueWithoutBlueInput { - where: RonstringWhereUniqueInput! - update: RonstringUpdateWithoutBlueDataInput! - create: RonstringCreateWithoutBlueInput! -} - -input RonstringWhereInput { - # Logical AND on all given filters. - AND: [RonstringWhereInput!] - # Logical OR on all given filters. - OR: [RonstringWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [RonstringWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - blue_every: TempWhereInput - blue_some: TempWhereInput - blue_none: TempWhereInput -} - -input RonstringWhereUniqueInput { - id: ID - plum: String -} - -type Sonair implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! -} - -# A connection to a list of items. -type SonairConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [SonairEdge]! - aggregate: AggregateSonair! -} - -input SonairCreateInput { - status: Status -} - -# An edge in a connection. -type SonairEdge { - # The item at the end of the edge. - node: Sonair! - # A cursor for use in pagination. - cursor: String! -} - -enum SonairOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC -} - -type SonairPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! -} - -type SonairSubscriptionPayload { - mutation: MutationType! - node: Sonair - updatedFields: [String!] - previousValues: SonairPreviousValues -} - -input SonairSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [SonairSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [SonairSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [SonairSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: SonairWhereInput -} - -input SonairUpdateInput { - status: Status -} - -input SonairUpdateManyMutationInput { - status: Status -} - -input SonairWhereInput { - # Logical AND on all given filters. - AND: [SonairWhereInput!] - # Logical OR on all given filters. - OR: [SonairWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [SonairWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID -} - -input SonairWhereUniqueInput { - id: ID -} - -type Sonsing implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - maroon: [Daugherty!]! - azure: [Harris!]! - ivory: [Muller!]! - fuchsia: String - gold: Lotlux - white: Stronghold - orchid: Lotlux - grey: Stronghold -} - -# A connection to a list of items. -type SonsingConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [SonsingEdge]! - aggregate: AggregateSonsing! -} - -input SonsingCreateazureInput { - set: [Harris!] -} - -input SonsingCreateInput { - status: Status - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - fuchsia: String - maroon: SonsingCreatemaroonInput - azure: SonsingCreateazureInput - ivory: SonsingCreateivoryInput - gold: LotluxCreateOneWithoutAzureInput - white: StrongholdCreateOneWithoutIndigoInput - orchid: LotluxCreateOneWithoutPlumInput - grey: StrongholdCreateOneWithoutMagentaInput -} - -input SonsingCreateivoryInput { - set: [Muller!] -} - -input SonsingCreatemaroonInput { - set: [Daugherty!] -} - -input SonsingCreateOneWithoutGoldInput { - create: SonsingCreateWithoutGoldInput - connect: SonsingWhereUniqueInput -} - -input SonsingCreateOneWithoutGreyInput { - create: SonsingCreateWithoutGreyInput - connect: SonsingWhereUniqueInput -} - -input SonsingCreateOneWithoutOrchidInput { - create: SonsingCreateWithoutOrchidInput - connect: SonsingWhereUniqueInput -} - -input SonsingCreateOneWithoutWhiteInput { - create: SonsingCreateWithoutWhiteInput - connect: SonsingWhereUniqueInput -} - -input SonsingCreateWithoutGoldInput { - status: Status - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - fuchsia: String - maroon: SonsingCreatemaroonInput - azure: SonsingCreateazureInput - ivory: SonsingCreateivoryInput - white: StrongholdCreateOneWithoutIndigoInput - orchid: LotluxCreateOneWithoutPlumInput - grey: StrongholdCreateOneWithoutMagentaInput -} - -input SonsingCreateWithoutGreyInput { - status: Status - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - fuchsia: String - maroon: SonsingCreatemaroonInput - azure: SonsingCreateazureInput - ivory: SonsingCreateivoryInput - gold: LotluxCreateOneWithoutAzureInput - white: StrongholdCreateOneWithoutIndigoInput - orchid: LotluxCreateOneWithoutPlumInput -} - -input SonsingCreateWithoutOrchidInput { - status: Status - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - fuchsia: String - maroon: SonsingCreatemaroonInput - azure: SonsingCreateazureInput - ivory: SonsingCreateivoryInput - gold: LotluxCreateOneWithoutAzureInput - white: StrongholdCreateOneWithoutIndigoInput - grey: StrongholdCreateOneWithoutMagentaInput -} - -input SonsingCreateWithoutWhiteInput { - status: Status - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - fuchsia: String - maroon: SonsingCreatemaroonInput - azure: SonsingCreateazureInput - ivory: SonsingCreateivoryInput - gold: LotluxCreateOneWithoutAzureInput - orchid: LotluxCreateOneWithoutPlumInput - grey: StrongholdCreateOneWithoutMagentaInput -} - -# An edge in a connection. -type SonsingEdge { - # The item at the end of the edge. - node: Sonsing! - # A cursor for use in pagination. - cursor: String! -} - -enum SonsingOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - red_ASC - red_DESC - black_ASC - black_DESC - lavender_ASC - lavender_DESC - olive_ASC - olive_DESC - silver_ASC - silver_DESC - green_ASC - green_DESC - fuchsia_ASC - fuchsia_DESC -} - -type SonsingPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - red: Boolean! - black: Boolean! - lavender: Boolean! - olive: String! - silver: String - green: String - maroon: [Daugherty!]! - azure: [Harris!]! - ivory: [Muller!]! - fuchsia: String -} - -type SonsingSubscriptionPayload { - mutation: MutationType! - node: Sonsing - updatedFields: [String!] - previousValues: SonsingPreviousValues -} - -input SonsingSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [SonsingSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [SonsingSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [SonsingSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: SonsingWhereInput -} - -input SonsingUpdateazureInput { - set: [Harris!] -} - -input SonsingUpdateInput { - status: Status - red: Boolean - black: Boolean - lavender: Boolean - olive: String - silver: String - green: String - fuchsia: String - maroon: SonsingUpdatemaroonInput - azure: SonsingUpdateazureInput - ivory: SonsingUpdateivoryInput - gold: LotluxUpdateOneWithoutAzureInput - white: StrongholdUpdateOneWithoutIndigoInput - orchid: LotluxUpdateOneWithoutPlumInput - grey: StrongholdUpdateOneWithoutMagentaInput -} - -input SonsingUpdateivoryInput { - set: [Muller!] -} - -input SonsingUpdateManyMutationInput { - status: Status - red: Boolean - black: Boolean - lavender: Boolean - olive: String - silver: String - green: String - fuchsia: String - maroon: SonsingUpdatemaroonInput - azure: SonsingUpdateazureInput - ivory: SonsingUpdateivoryInput -} - -input SonsingUpdatemaroonInput { - set: [Daugherty!] -} - -input SonsingUpdateOneWithoutGoldInput { - create: SonsingCreateWithoutGoldInput - connect: SonsingWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: SonsingUpdateWithoutGoldDataInput - upsert: SonsingUpsertWithoutGoldInput -} - -input SonsingUpdateOneWithoutGreyInput { - create: SonsingCreateWithoutGreyInput - connect: SonsingWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: SonsingUpdateWithoutGreyDataInput - upsert: SonsingUpsertWithoutGreyInput -} - -input SonsingUpdateOneWithoutOrchidInput { - create: SonsingCreateWithoutOrchidInput - connect: SonsingWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: SonsingUpdateWithoutOrchidDataInput - upsert: SonsingUpsertWithoutOrchidInput -} - -input SonsingUpdateOneWithoutWhiteInput { - create: SonsingCreateWithoutWhiteInput - connect: SonsingWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: SonsingUpdateWithoutWhiteDataInput - upsert: SonsingUpsertWithoutWhiteInput -} - -input SonsingUpdateWithoutGoldDataInput { - status: Status - red: Boolean - black: Boolean - lavender: Boolean - olive: String - silver: String - green: String - fuchsia: String - maroon: SonsingUpdatemaroonInput - azure: SonsingUpdateazureInput - ivory: SonsingUpdateivoryInput - white: StrongholdUpdateOneWithoutIndigoInput - orchid: LotluxUpdateOneWithoutPlumInput - grey: StrongholdUpdateOneWithoutMagentaInput -} - -input SonsingUpdateWithoutGreyDataInput { - status: Status - red: Boolean - black: Boolean - lavender: Boolean - olive: String - silver: String - green: String - fuchsia: String - maroon: SonsingUpdatemaroonInput - azure: SonsingUpdateazureInput - ivory: SonsingUpdateivoryInput - gold: LotluxUpdateOneWithoutAzureInput - white: StrongholdUpdateOneWithoutIndigoInput - orchid: LotluxUpdateOneWithoutPlumInput -} - -input SonsingUpdateWithoutOrchidDataInput { - status: Status - red: Boolean - black: Boolean - lavender: Boolean - olive: String - silver: String - green: String - fuchsia: String - maroon: SonsingUpdatemaroonInput - azure: SonsingUpdateazureInput - ivory: SonsingUpdateivoryInput - gold: LotluxUpdateOneWithoutAzureInput - white: StrongholdUpdateOneWithoutIndigoInput - grey: StrongholdUpdateOneWithoutMagentaInput -} - -input SonsingUpdateWithoutWhiteDataInput { - status: Status - red: Boolean - black: Boolean - lavender: Boolean - olive: String - silver: String - green: String - fuchsia: String - maroon: SonsingUpdatemaroonInput - azure: SonsingUpdateazureInput - ivory: SonsingUpdateivoryInput - gold: LotluxUpdateOneWithoutAzureInput - orchid: LotluxUpdateOneWithoutPlumInput - grey: StrongholdUpdateOneWithoutMagentaInput -} - -input SonsingUpsertWithoutGoldInput { - update: SonsingUpdateWithoutGoldDataInput! - create: SonsingCreateWithoutGoldInput! -} - -input SonsingUpsertWithoutGreyInput { - update: SonsingUpdateWithoutGreyDataInput! - create: SonsingCreateWithoutGreyInput! -} - -input SonsingUpsertWithoutOrchidInput { - update: SonsingUpdateWithoutOrchidDataInput! - create: SonsingCreateWithoutOrchidInput! -} - -input SonsingUpsertWithoutWhiteInput { - update: SonsingUpdateWithoutWhiteDataInput! - create: SonsingCreateWithoutWhiteInput! -} - -input SonsingWhereInput { - # Logical AND on all given filters. - AND: [SonsingWhereInput!] - # Logical OR on all given filters. - OR: [SonsingWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [SonsingWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - red: Boolean - # All values that are not equal to given value. - red_not: Boolean - black: Boolean - # All values that are not equal to given value. - black_not: Boolean - lavender: Boolean - # All values that are not equal to given value. - lavender_not: Boolean - olive: String - # All values that are not equal to given value. - olive_not: String - # All values that are contained in given list. - olive_in: [String!] - # All values that are not contained in given list. - olive_not_in: [String!] - # All values less than the given value. - olive_lt: String - # All values less than or equal the given value. - olive_lte: String - # All values greater than the given value. - olive_gt: String - # All values greater than or equal the given value. - olive_gte: String - # All values containing the given string. - olive_contains: String - # All values not containing the given string. - olive_not_contains: String - # All values starting with the given string. - olive_starts_with: String - # All values not starting with the given string. - olive_not_starts_with: String - # All values ending with the given string. - olive_ends_with: String - # All values not ending with the given string. - olive_not_ends_with: String - silver: String - # All values that are not equal to given value. - silver_not: String - # All values that are contained in given list. - silver_in: [String!] - # All values that are not contained in given list. - silver_not_in: [String!] - # All values less than the given value. - silver_lt: String - # All values less than or equal the given value. - silver_lte: String - # All values greater than the given value. - silver_gt: String - # All values greater than or equal the given value. - silver_gte: String - # All values containing the given string. - silver_contains: String - # All values not containing the given string. - silver_not_contains: String - # All values starting with the given string. - silver_starts_with: String - # All values not starting with the given string. - silver_not_starts_with: String - # All values ending with the given string. - silver_ends_with: String - # All values not ending with the given string. - silver_not_ends_with: String - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String - fuchsia: String - # All values that are not equal to given value. - fuchsia_not: String - # All values that are contained in given list. - fuchsia_in: [String!] - # All values that are not contained in given list. - fuchsia_not_in: [String!] - # All values less than the given value. - fuchsia_lt: String - # All values less than or equal the given value. - fuchsia_lte: String - # All values greater than the given value. - fuchsia_gt: String - # All values greater than or equal the given value. - fuchsia_gte: String - # All values containing the given string. - fuchsia_contains: String - # All values not containing the given string. - fuchsia_not_contains: String - # All values starting with the given string. - fuchsia_starts_with: String - # All values not starting with the given string. - fuchsia_not_starts_with: String - # All values ending with the given string. - fuchsia_ends_with: String - # All values not ending with the given string. - fuchsia_not_ends_with: String - gold: LotluxWhereInput - white: StrongholdWhereInput - orchid: LotluxWhereInput - grey: StrongholdWhereInput -} - -input SonsingWhereUniqueInput { - id: ID -} - -enum Status { - DRAFT - PUBLISHED - ARCHIVED -} - -type Stim implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - silver: String! - lavender: String! - red: [Daugherty!]! - yellow: String -} - -# A connection to a list of items. -type StimConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [StimEdge]! - aggregate: AggregateStim! -} - -input StimCreateInput { - status: Status - silver: String! - lavender: String! - yellow: String - red: StimCreateredInput -} - -input StimCreateredInput { - set: [Daugherty!] -} - -# An edge in a connection. -type StimEdge { - # The item at the end of the edge. - node: Stim! - # A cursor for use in pagination. - cursor: String! -} - -enum StimOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - silver_ASC - silver_DESC - lavender_ASC - lavender_DESC - yellow_ASC - yellow_DESC -} - -type StimPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - silver: String! - lavender: String! - red: [Daugherty!]! - yellow: String -} - -type StimSubscriptionPayload { - mutation: MutationType! - node: Stim - updatedFields: [String!] - previousValues: StimPreviousValues -} - -input StimSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [StimSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [StimSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StimSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: StimWhereInput -} - -input StimUpdateInput { - status: Status - silver: String - lavender: String - yellow: String - red: StimUpdateredInput -} - -input StimUpdateManyMutationInput { - status: Status - silver: String - lavender: String - yellow: String - red: StimUpdateredInput -} - -input StimUpdateredInput { - set: [Daugherty!] -} - -input StimWhereInput { - # Logical AND on all given filters. - AND: [StimWhereInput!] - # Logical OR on all given filters. - OR: [StimWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StimWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - silver: String - # All values that are not equal to given value. - silver_not: String - # All values that are contained in given list. - silver_in: [String!] - # All values that are not contained in given list. - silver_not_in: [String!] - # All values less than the given value. - silver_lt: String - # All values less than or equal the given value. - silver_lte: String - # All values greater than the given value. - silver_gt: String - # All values greater than or equal the given value. - silver_gte: String - # All values containing the given string. - silver_contains: String - # All values not containing the given string. - silver_not_contains: String - # All values starting with the given string. - silver_starts_with: String - # All values not starting with the given string. - silver_not_starts_with: String - # All values ending with the given string. - silver_ends_with: String - # All values not ending with the given string. - silver_not_ends_with: String - lavender: String - # All values that are not equal to given value. - lavender_not: String - # All values that are contained in given list. - lavender_in: [String!] - # All values that are not contained in given list. - lavender_not_in: [String!] - # All values less than the given value. - lavender_lt: String - # All values less than or equal the given value. - lavender_lte: String - # All values greater than the given value. - lavender_gt: String - # All values greater than or equal the given value. - lavender_gte: String - # All values containing the given string. - lavender_contains: String - # All values not containing the given string. - lavender_not_contains: String - # All values starting with the given string. - lavender_starts_with: String - # All values not starting with the given string. - lavender_not_starts_with: String - # All values ending with the given string. - lavender_ends_with: String - # All values not ending with the given string. - lavender_not_ends_with: String - yellow: String - # All values that are not equal to given value. - yellow_not: String - # All values that are contained in given list. - yellow_in: [String!] - # All values that are not contained in given list. - yellow_not_in: [String!] - # All values less than the given value. - yellow_lt: String - # All values less than or equal the given value. - yellow_lte: String - # All values greater than the given value. - yellow_gt: String - # All values greater than or equal the given value. - yellow_gte: String - # All values containing the given string. - yellow_contains: String - # All values not containing the given string. - yellow_not_contains: String - # All values starting with the given string. - yellow_starts_with: String - # All values not starting with the given string. - yellow_not_starts_with: String - # All values ending with the given string. - yellow_ends_with: String - # All values not ending with the given string. - yellow_not_ends_with: String -} - -input StimWhereUniqueInput { - id: ID -} - -type Stringtough implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - violet: String! - purple: [Harris!]! - green: String! -} - -# A connection to a list of items. -type StringtoughConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [StringtoughEdge]! - aggregate: AggregateStringtough! -} - -input StringtoughCreateInput { - status: Status - violet: String! - green: String! - purple: StringtoughCreatepurpleInput -} - -input StringtoughCreatepurpleInput { - set: [Harris!] -} - -# An edge in a connection. -type StringtoughEdge { - # The item at the end of the edge. - node: Stringtough! - # A cursor for use in pagination. - cursor: String! -} - -enum StringtoughOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - violet_ASC - violet_DESC - green_ASC - green_DESC -} - -type StringtoughPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - violet: String! - purple: [Harris!]! - green: String! -} - -type StringtoughSubscriptionPayload { - mutation: MutationType! - node: Stringtough - updatedFields: [String!] - previousValues: StringtoughPreviousValues -} - -input StringtoughSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [StringtoughSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [StringtoughSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StringtoughSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: StringtoughWhereInput -} - -input StringtoughUpdateInput { - status: Status - violet: String - green: String - purple: StringtoughUpdatepurpleInput -} - -input StringtoughUpdateManyMutationInput { - status: Status - violet: String - green: String - purple: StringtoughUpdatepurpleInput -} - -input StringtoughUpdatepurpleInput { - set: [Harris!] -} - -input StringtoughWhereInput { - # Logical AND on all given filters. - AND: [StringtoughWhereInput!] - # Logical OR on all given filters. - OR: [StringtoughWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StringtoughWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - violet: String - # All values that are not equal to given value. - violet_not: String - # All values that are contained in given list. - violet_in: [String!] - # All values that are not contained in given list. - violet_not_in: [String!] - # All values less than the given value. - violet_lt: String - # All values less than or equal the given value. - violet_lte: String - # All values greater than the given value. - violet_gt: String - # All values greater than or equal the given value. - violet_gte: String - # All values containing the given string. - violet_contains: String - # All values not containing the given string. - violet_not_contains: String - # All values starting with the given string. - violet_starts_with: String - # All values not starting with the given string. - violet_not_starts_with: String - # All values ending with the given string. - violet_ends_with: String - # All values not ending with the given string. - violet_not_ends_with: String - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String -} - -input StringtoughWhereUniqueInput { - id: ID - green: String -} - -type Stronghold implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - azure: String - turquoise: Boolean - indigo: Sonsing - orchid( - where: BamityWhereInput - orderBy: BamityOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Bamity!] - purple( - where: ToughjoyfaxWhereInput - orderBy: ToughjoyfaxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Toughjoyfax!] - green: Asset - teal: Asset - silver: Asset - lavender: Asset - magenta: Sonsing -} - -# A connection to a list of items. -type StrongholdConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [StrongholdEdge]! - aggregate: AggregateStronghold! -} - -input StrongholdCreateInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateManyWithoutGreenInput { - create: [StrongholdCreateWithoutGreenInput!] - connect: [StrongholdWhereUniqueInput!] -} - -input StrongholdCreateManyWithoutLavenderInput { - create: [StrongholdCreateWithoutLavenderInput!] - connect: [StrongholdWhereUniqueInput!] -} - -input StrongholdCreateManyWithoutSilverInput { - create: [StrongholdCreateWithoutSilverInput!] - connect: [StrongholdWhereUniqueInput!] -} - -input StrongholdCreateManyWithoutTealInput { - create: [StrongholdCreateWithoutTealInput!] - connect: [StrongholdWhereUniqueInput!] -} - -input StrongholdCreateOneWithoutIndigoInput { - create: StrongholdCreateWithoutIndigoInput - connect: StrongholdWhereUniqueInput -} - -input StrongholdCreateOneWithoutMagentaInput { - create: StrongholdCreateWithoutMagentaInput - connect: StrongholdWhereUniqueInput -} - -input StrongholdCreateOneWithoutOrchidInput { - create: StrongholdCreateWithoutOrchidInput - connect: StrongholdWhereUniqueInput -} - -input StrongholdCreateOneWithoutPurpleInput { - create: StrongholdCreateWithoutPurpleInput - connect: StrongholdWhereUniqueInput -} - -input StrongholdCreateWithoutGreenInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateWithoutIndigoInput { - status: Status - azure: String - turquoise: Boolean - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateWithoutLavenderInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateWithoutMagentaInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput -} - -input StrongholdCreateWithoutOrchidInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateWithoutPurpleInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateWithoutSilverInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - teal: AssetCreateOneWithoutTealStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -input StrongholdCreateWithoutTealInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingCreateOneWithoutWhiteInput - orchid: BamityCreateManyWithoutMaroonInput - purple: ToughjoyfaxCreateManyWithoutSalmonInput - green: AssetCreateOneWithoutGreenStrongholdInput - silver: AssetCreateOneWithoutSilverStrongholdInput - lavender: AssetCreateOneWithoutLavenderStrongholdInput - magenta: SonsingCreateOneWithoutGreyInput -} - -# An edge in a connection. -type StrongholdEdge { - # The item at the end of the edge. - node: Stronghold! - # A cursor for use in pagination. - cursor: String! -} - -enum StrongholdOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - azure_ASC - azure_DESC - turquoise_ASC - turquoise_DESC -} - -type StrongholdPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - azure: String - turquoise: Boolean -} - -input StrongholdScalarWhereInput { - # Logical AND on all given filters. - AND: [StrongholdScalarWhereInput!] - # Logical OR on all given filters. - OR: [StrongholdScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StrongholdScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - azure: String - # All values that are not equal to given value. - azure_not: String - # All values that are contained in given list. - azure_in: [String!] - # All values that are not contained in given list. - azure_not_in: [String!] - # All values less than the given value. - azure_lt: String - # All values less than or equal the given value. - azure_lte: String - # All values greater than the given value. - azure_gt: String - # All values greater than or equal the given value. - azure_gte: String - # All values containing the given string. - azure_contains: String - # All values not containing the given string. - azure_not_contains: String - # All values starting with the given string. - azure_starts_with: String - # All values not starting with the given string. - azure_not_starts_with: String - # All values ending with the given string. - azure_ends_with: String - # All values not ending with the given string. - azure_not_ends_with: String - turquoise: Boolean - # All values that are not equal to given value. - turquoise_not: Boolean -} - -type StrongholdSubscriptionPayload { - mutation: MutationType! - node: Stronghold - updatedFields: [String!] - previousValues: StrongholdPreviousValues -} - -input StrongholdSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [StrongholdSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [StrongholdSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StrongholdSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: StrongholdWhereInput -} - -input StrongholdUpdateInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateManyDataInput { - status: Status - azure: String - turquoise: Boolean -} - -input StrongholdUpdateManyMutationInput { - status: Status - azure: String - turquoise: Boolean -} - -input StrongholdUpdateManyWithoutGreenInput { - create: [StrongholdCreateWithoutGreenInput!] - connect: [StrongholdWhereUniqueInput!] - set: [StrongholdWhereUniqueInput!] - disconnect: [StrongholdWhereUniqueInput!] - delete: [StrongholdWhereUniqueInput!] - update: [StrongholdUpdateWithWhereUniqueWithoutGreenInput!] - updateMany: [StrongholdUpdateManyWithWhereNestedInput!] - deleteMany: [StrongholdScalarWhereInput!] - upsert: [StrongholdUpsertWithWhereUniqueWithoutGreenInput!] -} - -input StrongholdUpdateManyWithoutLavenderInput { - create: [StrongholdCreateWithoutLavenderInput!] - connect: [StrongholdWhereUniqueInput!] - set: [StrongholdWhereUniqueInput!] - disconnect: [StrongholdWhereUniqueInput!] - delete: [StrongholdWhereUniqueInput!] - update: [StrongholdUpdateWithWhereUniqueWithoutLavenderInput!] - updateMany: [StrongholdUpdateManyWithWhereNestedInput!] - deleteMany: [StrongholdScalarWhereInput!] - upsert: [StrongholdUpsertWithWhereUniqueWithoutLavenderInput!] -} - -input StrongholdUpdateManyWithoutSilverInput { - create: [StrongholdCreateWithoutSilverInput!] - connect: [StrongholdWhereUniqueInput!] - set: [StrongholdWhereUniqueInput!] - disconnect: [StrongholdWhereUniqueInput!] - delete: [StrongholdWhereUniqueInput!] - update: [StrongholdUpdateWithWhereUniqueWithoutSilverInput!] - updateMany: [StrongholdUpdateManyWithWhereNestedInput!] - deleteMany: [StrongholdScalarWhereInput!] - upsert: [StrongholdUpsertWithWhereUniqueWithoutSilverInput!] -} - -input StrongholdUpdateManyWithoutTealInput { - create: [StrongholdCreateWithoutTealInput!] - connect: [StrongholdWhereUniqueInput!] - set: [StrongholdWhereUniqueInput!] - disconnect: [StrongholdWhereUniqueInput!] - delete: [StrongholdWhereUniqueInput!] - update: [StrongholdUpdateWithWhereUniqueWithoutTealInput!] - updateMany: [StrongholdUpdateManyWithWhereNestedInput!] - deleteMany: [StrongholdScalarWhereInput!] - upsert: [StrongholdUpsertWithWhereUniqueWithoutTealInput!] -} - -input StrongholdUpdateManyWithWhereNestedInput { - where: StrongholdScalarWhereInput! - data: StrongholdUpdateManyDataInput! -} - -input StrongholdUpdateOneWithoutIndigoInput { - create: StrongholdCreateWithoutIndigoInput - connect: StrongholdWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: StrongholdUpdateWithoutIndigoDataInput - upsert: StrongholdUpsertWithoutIndigoInput -} - -input StrongholdUpdateOneWithoutMagentaInput { - create: StrongholdCreateWithoutMagentaInput - connect: StrongholdWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: StrongholdUpdateWithoutMagentaDataInput - upsert: StrongholdUpsertWithoutMagentaInput -} - -input StrongholdUpdateOneWithoutOrchidInput { - create: StrongholdCreateWithoutOrchidInput - connect: StrongholdWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: StrongholdUpdateWithoutOrchidDataInput - upsert: StrongholdUpsertWithoutOrchidInput -} - -input StrongholdUpdateOneWithoutPurpleInput { - create: StrongholdCreateWithoutPurpleInput - connect: StrongholdWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: StrongholdUpdateWithoutPurpleDataInput - upsert: StrongholdUpsertWithoutPurpleInput -} - -input StrongholdUpdateWithoutGreenDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithoutIndigoDataInput { - status: Status - azure: String - turquoise: Boolean - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithoutLavenderDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithoutMagentaDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput -} - -input StrongholdUpdateWithoutOrchidDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithoutPurpleDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithoutSilverDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - teal: AssetUpdateOneWithoutTealStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithoutTealDataInput { - status: Status - azure: String - turquoise: Boolean - indigo: SonsingUpdateOneWithoutWhiteInput - orchid: BamityUpdateManyWithoutMaroonInput - purple: ToughjoyfaxUpdateManyWithoutSalmonInput - green: AssetUpdateOneWithoutGreenStrongholdInput - silver: AssetUpdateOneWithoutSilverStrongholdInput - lavender: AssetUpdateOneWithoutLavenderStrongholdInput - magenta: SonsingUpdateOneWithoutGreyInput -} - -input StrongholdUpdateWithWhereUniqueWithoutGreenInput { - where: StrongholdWhereUniqueInput! - data: StrongholdUpdateWithoutGreenDataInput! -} - -input StrongholdUpdateWithWhereUniqueWithoutLavenderInput { - where: StrongholdWhereUniqueInput! - data: StrongholdUpdateWithoutLavenderDataInput! -} - -input StrongholdUpdateWithWhereUniqueWithoutSilverInput { - where: StrongholdWhereUniqueInput! - data: StrongholdUpdateWithoutSilverDataInput! -} - -input StrongholdUpdateWithWhereUniqueWithoutTealInput { - where: StrongholdWhereUniqueInput! - data: StrongholdUpdateWithoutTealDataInput! -} - -input StrongholdUpsertWithoutIndigoInput { - update: StrongholdUpdateWithoutIndigoDataInput! - create: StrongholdCreateWithoutIndigoInput! -} - -input StrongholdUpsertWithoutMagentaInput { - update: StrongholdUpdateWithoutMagentaDataInput! - create: StrongholdCreateWithoutMagentaInput! -} - -input StrongholdUpsertWithoutOrchidInput { - update: StrongholdUpdateWithoutOrchidDataInput! - create: StrongholdCreateWithoutOrchidInput! -} - -input StrongholdUpsertWithoutPurpleInput { - update: StrongholdUpdateWithoutPurpleDataInput! - create: StrongholdCreateWithoutPurpleInput! -} - -input StrongholdUpsertWithWhereUniqueWithoutGreenInput { - where: StrongholdWhereUniqueInput! - update: StrongholdUpdateWithoutGreenDataInput! - create: StrongholdCreateWithoutGreenInput! -} - -input StrongholdUpsertWithWhereUniqueWithoutLavenderInput { - where: StrongholdWhereUniqueInput! - update: StrongholdUpdateWithoutLavenderDataInput! - create: StrongholdCreateWithoutLavenderInput! -} - -input StrongholdUpsertWithWhereUniqueWithoutSilverInput { - where: StrongholdWhereUniqueInput! - update: StrongholdUpdateWithoutSilverDataInput! - create: StrongholdCreateWithoutSilverInput! -} - -input StrongholdUpsertWithWhereUniqueWithoutTealInput { - where: StrongholdWhereUniqueInput! - update: StrongholdUpdateWithoutTealDataInput! - create: StrongholdCreateWithoutTealInput! -} - -input StrongholdWhereInput { - # Logical AND on all given filters. - AND: [StrongholdWhereInput!] - # Logical OR on all given filters. - OR: [StrongholdWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [StrongholdWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - azure: String - # All values that are not equal to given value. - azure_not: String - # All values that are contained in given list. - azure_in: [String!] - # All values that are not contained in given list. - azure_not_in: [String!] - # All values less than the given value. - azure_lt: String - # All values less than or equal the given value. - azure_lte: String - # All values greater than the given value. - azure_gt: String - # All values greater than or equal the given value. - azure_gte: String - # All values containing the given string. - azure_contains: String - # All values not containing the given string. - azure_not_contains: String - # All values starting with the given string. - azure_starts_with: String - # All values not starting with the given string. - azure_not_starts_with: String - # All values ending with the given string. - azure_ends_with: String - # All values not ending with the given string. - azure_not_ends_with: String - turquoise: Boolean - # All values that are not equal to given value. - turquoise_not: Boolean - indigo: SonsingWhereInput - orchid_every: BamityWhereInput - orchid_some: BamityWhereInput - orchid_none: BamityWhereInput - purple_every: ToughjoyfaxWhereInput - purple_some: ToughjoyfaxWhereInput - purple_none: ToughjoyfaxWhereInput - green: AssetWhereInput - teal: AssetWhereInput - silver: AssetWhereInput - lavender: AssetWhereInput - magenta: SonsingWhereInput -} - -input StrongholdWhereUniqueInput { - id: ID -} - -type Subin implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - orange: String - ivory: Blick! - red: String - maroon: String! -} - -# A connection to a list of items. -type SubinConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [SubinEdge]! - aggregate: AggregateSubin! -} - -input SubinCreateInput { - status: Status - orange: String - ivory: Blick! - red: String - maroon: String! -} - -# An edge in a connection. -type SubinEdge { - # The item at the end of the edge. - node: Subin! - # A cursor for use in pagination. - cursor: String! -} - -enum SubinOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - orange_ASC - orange_DESC - ivory_ASC - ivory_DESC - red_ASC - red_DESC - maroon_ASC - maroon_DESC -} - -type SubinPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - orange: String - ivory: Blick! - red: String - maroon: String! -} - -type SubinSubscriptionPayload { - mutation: MutationType! - node: Subin - updatedFields: [String!] - previousValues: SubinPreviousValues -} - -input SubinSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [SubinSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [SubinSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [SubinSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: SubinWhereInput -} - -input SubinUpdateInput { - status: Status - orange: String - ivory: Blick - red: String - maroon: String -} - -input SubinUpdateManyMutationInput { - status: Status - orange: String - ivory: Blick - red: String - maroon: String -} - -input SubinWhereInput { - # Logical AND on all given filters. - AND: [SubinWhereInput!] - # Logical OR on all given filters. - OR: [SubinWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [SubinWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - ivory: Blick - # All values that are not equal to given value. - ivory_not: Blick - # All values that are contained in given list. - ivory_in: [Blick!] - # All values that are not contained in given list. - ivory_not_in: [Blick!] - red: String - # All values that are not equal to given value. - red_not: String - # All values that are contained in given list. - red_in: [String!] - # All values that are not contained in given list. - red_not_in: [String!] - # All values less than the given value. - red_lt: String - # All values less than or equal the given value. - red_lte: String - # All values greater than the given value. - red_gt: String - # All values greater than or equal the given value. - red_gte: String - # All values containing the given string. - red_contains: String - # All values not containing the given string. - red_not_contains: String - # All values starting with the given string. - red_starts_with: String - # All values not starting with the given string. - red_not_starts_with: String - # All values ending with the given string. - red_ends_with: String - # All values not ending with the given string. - red_not_ends_with: String - maroon: String - # All values that are not equal to given value. - maroon_not: String - # All values that are contained in given list. - maroon_in: [String!] - # All values that are not contained in given list. - maroon_not_in: [String!] - # All values less than the given value. - maroon_lt: String - # All values less than or equal the given value. - maroon_lte: String - # All values greater than the given value. - maroon_gt: String - # All values greater than or equal the given value. - maroon_gte: String - # All values containing the given string. - maroon_contains: String - # All values not containing the given string. - maroon_not_contains: String - # All values starting with the given string. - maroon_starts_with: String - # All values not starting with the given string. - maroon_not_starts_with: String - # All values ending with the given string. - maroon_ends_with: String - # All values not ending with the given string. - maroon_not_ends_with: String -} - -input SubinWhereUniqueInput { - id: ID - orange: String -} - -type Temp implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - black: DateTime - magenta: String! - orange: String! - tan: String - teal: Blick! - purple: String! - grey: String - olive: Asset - blue: String! - turquoise( - where: RonstringWhereInput - orderBy: RonstringOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Ronstring!] -} - -# A connection to a list of items. -type TempConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [TempEdge]! - aggregate: AggregateTemp! -} - -input TempCreateInput { - status: Status - black: DateTime - magenta: String! - orange: String! - tan: String - teal: Blick! - purple: String! - grey: String - blue: String! - olive: AssetCreateOneWithoutOliveTempInput - turquoise: RonstringCreateManyWithoutBlueInput -} - -input TempCreateManyWithoutOliveInput { - create: [TempCreateWithoutOliveInput!] - connect: [TempWhereUniqueInput!] -} - -input TempCreateManyWithoutTurquoiseInput { - create: [TempCreateWithoutTurquoiseInput!] - connect: [TempWhereUniqueInput!] -} - -input TempCreateWithoutOliveInput { - status: Status - black: DateTime - magenta: String! - orange: String! - tan: String - teal: Blick! - purple: String! - grey: String - blue: String! - turquoise: RonstringCreateManyWithoutBlueInput -} - -input TempCreateWithoutTurquoiseInput { - status: Status - black: DateTime - magenta: String! - orange: String! - tan: String - teal: Blick! - purple: String! - grey: String - blue: String! - olive: AssetCreateOneWithoutOliveTempInput -} - -# An edge in a connection. -type TempEdge { - # The item at the end of the edge. - node: Temp! - # A cursor for use in pagination. - cursor: String! -} - -enum TempOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - black_ASC - black_DESC - magenta_ASC - magenta_DESC - orange_ASC - orange_DESC - tan_ASC - tan_DESC - teal_ASC - teal_DESC - purple_ASC - purple_DESC - grey_ASC - grey_DESC - blue_ASC - blue_DESC -} - -type TempPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - black: DateTime - magenta: String! - orange: String! - tan: String - teal: Blick! - purple: String! - grey: String - blue: String! -} - -input TempScalarWhereInput { - # Logical AND on all given filters. - AND: [TempScalarWhereInput!] - # Logical OR on all given filters. - OR: [TempScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TempScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - black: DateTime - # All values that are not equal to given value. - black_not: DateTime - # All values that are contained in given list. - black_in: [DateTime!] - # All values that are not contained in given list. - black_not_in: [DateTime!] - # All values less than the given value. - black_lt: DateTime - # All values less than or equal the given value. - black_lte: DateTime - # All values greater than the given value. - black_gt: DateTime - # All values greater than or equal the given value. - black_gte: DateTime - magenta: String - # All values that are not equal to given value. - magenta_not: String - # All values that are contained in given list. - magenta_in: [String!] - # All values that are not contained in given list. - magenta_not_in: [String!] - # All values less than the given value. - magenta_lt: String - # All values less than or equal the given value. - magenta_lte: String - # All values greater than the given value. - magenta_gt: String - # All values greater than or equal the given value. - magenta_gte: String - # All values containing the given string. - magenta_contains: String - # All values not containing the given string. - magenta_not_contains: String - # All values starting with the given string. - magenta_starts_with: String - # All values not starting with the given string. - magenta_not_starts_with: String - # All values ending with the given string. - magenta_ends_with: String - # All values not ending with the given string. - magenta_not_ends_with: String - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - teal: Blick - # All values that are not equal to given value. - teal_not: Blick - # All values that are contained in given list. - teal_in: [Blick!] - # All values that are not contained in given list. - teal_not_in: [Blick!] - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - grey: String - # All values that are not equal to given value. - grey_not: String - # All values that are contained in given list. - grey_in: [String!] - # All values that are not contained in given list. - grey_not_in: [String!] - # All values less than the given value. - grey_lt: String - # All values less than or equal the given value. - grey_lte: String - # All values greater than the given value. - grey_gt: String - # All values greater than or equal the given value. - grey_gte: String - # All values containing the given string. - grey_contains: String - # All values not containing the given string. - grey_not_contains: String - # All values starting with the given string. - grey_starts_with: String - # All values not starting with the given string. - grey_not_starts_with: String - # All values ending with the given string. - grey_ends_with: String - # All values not ending with the given string. - grey_not_ends_with: String - blue: String - # All values that are not equal to given value. - blue_not: String - # All values that are contained in given list. - blue_in: [String!] - # All values that are not contained in given list. - blue_not_in: [String!] - # All values less than the given value. - blue_lt: String - # All values less than or equal the given value. - blue_lte: String - # All values greater than the given value. - blue_gt: String - # All values greater than or equal the given value. - blue_gte: String - # All values containing the given string. - blue_contains: String - # All values not containing the given string. - blue_not_contains: String - # All values starting with the given string. - blue_starts_with: String - # All values not starting with the given string. - blue_not_starts_with: String - # All values ending with the given string. - blue_ends_with: String - # All values not ending with the given string. - blue_not_ends_with: String -} - -type TempSubscriptionPayload { - mutation: MutationType! - node: Temp - updatedFields: [String!] - previousValues: TempPreviousValues -} - -input TempSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [TempSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [TempSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TempSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: TempWhereInput -} - -input TempUpdateInput { - status: Status - black: DateTime - magenta: String - orange: String - tan: String - teal: Blick - purple: String - grey: String - blue: String - olive: AssetUpdateOneWithoutOliveTempInput - turquoise: RonstringUpdateManyWithoutBlueInput -} - -input TempUpdateManyDataInput { - status: Status - black: DateTime - magenta: String - orange: String - tan: String - teal: Blick - purple: String - grey: String - blue: String -} - -input TempUpdateManyMutationInput { - status: Status - black: DateTime - magenta: String - orange: String - tan: String - teal: Blick - purple: String - grey: String - blue: String -} - -input TempUpdateManyWithoutOliveInput { - create: [TempCreateWithoutOliveInput!] - connect: [TempWhereUniqueInput!] - set: [TempWhereUniqueInput!] - disconnect: [TempWhereUniqueInput!] - delete: [TempWhereUniqueInput!] - update: [TempUpdateWithWhereUniqueWithoutOliveInput!] - updateMany: [TempUpdateManyWithWhereNestedInput!] - deleteMany: [TempScalarWhereInput!] - upsert: [TempUpsertWithWhereUniqueWithoutOliveInput!] -} - -input TempUpdateManyWithoutTurquoiseInput { - create: [TempCreateWithoutTurquoiseInput!] - connect: [TempWhereUniqueInput!] - set: [TempWhereUniqueInput!] - disconnect: [TempWhereUniqueInput!] - delete: [TempWhereUniqueInput!] - update: [TempUpdateWithWhereUniqueWithoutTurquoiseInput!] - updateMany: [TempUpdateManyWithWhereNestedInput!] - deleteMany: [TempScalarWhereInput!] - upsert: [TempUpsertWithWhereUniqueWithoutTurquoiseInput!] -} - -input TempUpdateManyWithWhereNestedInput { - where: TempScalarWhereInput! - data: TempUpdateManyDataInput! -} - -input TempUpdateWithoutOliveDataInput { - status: Status - black: DateTime - magenta: String - orange: String - tan: String - teal: Blick - purple: String - grey: String - blue: String - turquoise: RonstringUpdateManyWithoutBlueInput -} - -input TempUpdateWithoutTurquoiseDataInput { - status: Status - black: DateTime - magenta: String - orange: String - tan: String - teal: Blick - purple: String - grey: String - blue: String - olive: AssetUpdateOneWithoutOliveTempInput -} - -input TempUpdateWithWhereUniqueWithoutOliveInput { - where: TempWhereUniqueInput! - data: TempUpdateWithoutOliveDataInput! -} - -input TempUpdateWithWhereUniqueWithoutTurquoiseInput { - where: TempWhereUniqueInput! - data: TempUpdateWithoutTurquoiseDataInput! -} - -input TempUpsertWithWhereUniqueWithoutOliveInput { - where: TempWhereUniqueInput! - update: TempUpdateWithoutOliveDataInput! - create: TempCreateWithoutOliveInput! -} - -input TempUpsertWithWhereUniqueWithoutTurquoiseInput { - where: TempWhereUniqueInput! - update: TempUpdateWithoutTurquoiseDataInput! - create: TempCreateWithoutTurquoiseInput! -} - -input TempWhereInput { - # Logical AND on all given filters. - AND: [TempWhereInput!] - # Logical OR on all given filters. - OR: [TempWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TempWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - black: DateTime - # All values that are not equal to given value. - black_not: DateTime - # All values that are contained in given list. - black_in: [DateTime!] - # All values that are not contained in given list. - black_not_in: [DateTime!] - # All values less than the given value. - black_lt: DateTime - # All values less than or equal the given value. - black_lte: DateTime - # All values greater than the given value. - black_gt: DateTime - # All values greater than or equal the given value. - black_gte: DateTime - magenta: String - # All values that are not equal to given value. - magenta_not: String - # All values that are contained in given list. - magenta_in: [String!] - # All values that are not contained in given list. - magenta_not_in: [String!] - # All values less than the given value. - magenta_lt: String - # All values less than or equal the given value. - magenta_lte: String - # All values greater than the given value. - magenta_gt: String - # All values greater than or equal the given value. - magenta_gte: String - # All values containing the given string. - magenta_contains: String - # All values not containing the given string. - magenta_not_contains: String - # All values starting with the given string. - magenta_starts_with: String - # All values not starting with the given string. - magenta_not_starts_with: String - # All values ending with the given string. - magenta_ends_with: String - # All values not ending with the given string. - magenta_not_ends_with: String - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - tan: String - # All values that are not equal to given value. - tan_not: String - # All values that are contained in given list. - tan_in: [String!] - # All values that are not contained in given list. - tan_not_in: [String!] - # All values less than the given value. - tan_lt: String - # All values less than or equal the given value. - tan_lte: String - # All values greater than the given value. - tan_gt: String - # All values greater than or equal the given value. - tan_gte: String - # All values containing the given string. - tan_contains: String - # All values not containing the given string. - tan_not_contains: String - # All values starting with the given string. - tan_starts_with: String - # All values not starting with the given string. - tan_not_starts_with: String - # All values ending with the given string. - tan_ends_with: String - # All values not ending with the given string. - tan_not_ends_with: String - teal: Blick - # All values that are not equal to given value. - teal_not: Blick - # All values that are contained in given list. - teal_in: [Blick!] - # All values that are not contained in given list. - teal_not_in: [Blick!] - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - grey: String - # All values that are not equal to given value. - grey_not: String - # All values that are contained in given list. - grey_in: [String!] - # All values that are not contained in given list. - grey_not_in: [String!] - # All values less than the given value. - grey_lt: String - # All values less than or equal the given value. - grey_lte: String - # All values greater than the given value. - grey_gt: String - # All values greater than or equal the given value. - grey_gte: String - # All values containing the given string. - grey_contains: String - # All values not containing the given string. - grey_not_contains: String - # All values starting with the given string. - grey_starts_with: String - # All values not starting with the given string. - grey_not_starts_with: String - # All values ending with the given string. - grey_ends_with: String - # All values not ending with the given string. - grey_not_ends_with: String - blue: String - # All values that are not equal to given value. - blue_not: String - # All values that are contained in given list. - blue_in: [String!] - # All values that are not contained in given list. - blue_not_in: [String!] - # All values less than the given value. - blue_lt: String - # All values less than or equal the given value. - blue_lte: String - # All values greater than the given value. - blue_gt: String - # All values greater than or equal the given value. - blue_gte: String - # All values containing the given string. - blue_contains: String - # All values not containing the given string. - blue_not_contains: String - # All values starting with the given string. - blue_starts_with: String - # All values not starting with the given string. - blue_not_starts_with: String - # All values ending with the given string. - blue_ends_with: String - # All values not ending with the given string. - blue_not_ends_with: String - olive: AssetWhereInput - turquoise_every: RonstringWhereInput - turquoise_some: RonstringWhereInput - turquoise_none: RonstringWhereInput -} - -input TempWhereUniqueInput { - id: ID - tan: String -} - -type Toughjoyfax implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - red: DateTime! - maroon: DateTime! - silver: Boolean - black: Morissette! - salmon: Stronghold - lime: String - fuchsia: Boolean -} - -# A connection to a list of items. -type ToughjoyfaxConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [ToughjoyfaxEdge]! - aggregate: AggregateToughjoyfax! -} - -input ToughjoyfaxCreateInput { - status: Status - red: DateTime! - maroon: DateTime! - silver: Boolean - black: Morissette! - lime: String - fuchsia: Boolean - salmon: StrongholdCreateOneWithoutPurpleInput -} - -input ToughjoyfaxCreateManyWithoutSalmonInput { - create: [ToughjoyfaxCreateWithoutSalmonInput!] - connect: [ToughjoyfaxWhereUniqueInput!] -} - -input ToughjoyfaxCreateWithoutSalmonInput { - status: Status - red: DateTime! - maroon: DateTime! - silver: Boolean - black: Morissette! - lime: String - fuchsia: Boolean -} - -# An edge in a connection. -type ToughjoyfaxEdge { - # The item at the end of the edge. - node: Toughjoyfax! - # A cursor for use in pagination. - cursor: String! -} - -enum ToughjoyfaxOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - red_ASC - red_DESC - maroon_ASC - maroon_DESC - silver_ASC - silver_DESC - black_ASC - black_DESC - lime_ASC - lime_DESC - fuchsia_ASC - fuchsia_DESC -} - -type ToughjoyfaxPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - red: DateTime! - maroon: DateTime! - silver: Boolean - black: Morissette! - lime: String - fuchsia: Boolean -} - -input ToughjoyfaxScalarWhereInput { - # Logical AND on all given filters. - AND: [ToughjoyfaxScalarWhereInput!] - # Logical OR on all given filters. - OR: [ToughjoyfaxScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ToughjoyfaxScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - red: DateTime - # All values that are not equal to given value. - red_not: DateTime - # All values that are contained in given list. - red_in: [DateTime!] - # All values that are not contained in given list. - red_not_in: [DateTime!] - # All values less than the given value. - red_lt: DateTime - # All values less than or equal the given value. - red_lte: DateTime - # All values greater than the given value. - red_gt: DateTime - # All values greater than or equal the given value. - red_gte: DateTime - maroon: DateTime - # All values that are not equal to given value. - maroon_not: DateTime - # All values that are contained in given list. - maroon_in: [DateTime!] - # All values that are not contained in given list. - maroon_not_in: [DateTime!] - # All values less than the given value. - maroon_lt: DateTime - # All values less than or equal the given value. - maroon_lte: DateTime - # All values greater than the given value. - maroon_gt: DateTime - # All values greater than or equal the given value. - maroon_gte: DateTime - silver: Boolean - # All values that are not equal to given value. - silver_not: Boolean - black: Morissette - # All values that are not equal to given value. - black_not: Morissette - # All values that are contained in given list. - black_in: [Morissette!] - # All values that are not contained in given list. - black_not_in: [Morissette!] - lime: String - # All values that are not equal to given value. - lime_not: String - # All values that are contained in given list. - lime_in: [String!] - # All values that are not contained in given list. - lime_not_in: [String!] - # All values less than the given value. - lime_lt: String - # All values less than or equal the given value. - lime_lte: String - # All values greater than the given value. - lime_gt: String - # All values greater than or equal the given value. - lime_gte: String - # All values containing the given string. - lime_contains: String - # All values not containing the given string. - lime_not_contains: String - # All values starting with the given string. - lime_starts_with: String - # All values not starting with the given string. - lime_not_starts_with: String - # All values ending with the given string. - lime_ends_with: String - # All values not ending with the given string. - lime_not_ends_with: String - fuchsia: Boolean - # All values that are not equal to given value. - fuchsia_not: Boolean -} - -type ToughjoyfaxSubscriptionPayload { - mutation: MutationType! - node: Toughjoyfax - updatedFields: [String!] - previousValues: ToughjoyfaxPreviousValues -} - -input ToughjoyfaxSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [ToughjoyfaxSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [ToughjoyfaxSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ToughjoyfaxSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: ToughjoyfaxWhereInput -} - -input ToughjoyfaxUpdateInput { - status: Status - red: DateTime - maroon: DateTime - silver: Boolean - black: Morissette - lime: String - fuchsia: Boolean - salmon: StrongholdUpdateOneWithoutPurpleInput -} - -input ToughjoyfaxUpdateManyDataInput { - status: Status - red: DateTime - maroon: DateTime - silver: Boolean - black: Morissette - lime: String - fuchsia: Boolean -} - -input ToughjoyfaxUpdateManyMutationInput { - status: Status - red: DateTime - maroon: DateTime - silver: Boolean - black: Morissette - lime: String - fuchsia: Boolean -} - -input ToughjoyfaxUpdateManyWithoutSalmonInput { - create: [ToughjoyfaxCreateWithoutSalmonInput!] - connect: [ToughjoyfaxWhereUniqueInput!] - set: [ToughjoyfaxWhereUniqueInput!] - disconnect: [ToughjoyfaxWhereUniqueInput!] - delete: [ToughjoyfaxWhereUniqueInput!] - update: [ToughjoyfaxUpdateWithWhereUniqueWithoutSalmonInput!] - updateMany: [ToughjoyfaxUpdateManyWithWhereNestedInput!] - deleteMany: [ToughjoyfaxScalarWhereInput!] - upsert: [ToughjoyfaxUpsertWithWhereUniqueWithoutSalmonInput!] -} - -input ToughjoyfaxUpdateManyWithWhereNestedInput { - where: ToughjoyfaxScalarWhereInput! - data: ToughjoyfaxUpdateManyDataInput! -} - -input ToughjoyfaxUpdateWithoutSalmonDataInput { - status: Status - red: DateTime - maroon: DateTime - silver: Boolean - black: Morissette - lime: String - fuchsia: Boolean -} - -input ToughjoyfaxUpdateWithWhereUniqueWithoutSalmonInput { - where: ToughjoyfaxWhereUniqueInput! - data: ToughjoyfaxUpdateWithoutSalmonDataInput! -} - -input ToughjoyfaxUpsertWithWhereUniqueWithoutSalmonInput { - where: ToughjoyfaxWhereUniqueInput! - update: ToughjoyfaxUpdateWithoutSalmonDataInput! - create: ToughjoyfaxCreateWithoutSalmonInput! -} - -input ToughjoyfaxWhereInput { - # Logical AND on all given filters. - AND: [ToughjoyfaxWhereInput!] - # Logical OR on all given filters. - OR: [ToughjoyfaxWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ToughjoyfaxWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - red: DateTime - # All values that are not equal to given value. - red_not: DateTime - # All values that are contained in given list. - red_in: [DateTime!] - # All values that are not contained in given list. - red_not_in: [DateTime!] - # All values less than the given value. - red_lt: DateTime - # All values less than or equal the given value. - red_lte: DateTime - # All values greater than the given value. - red_gt: DateTime - # All values greater than or equal the given value. - red_gte: DateTime - maroon: DateTime - # All values that are not equal to given value. - maroon_not: DateTime - # All values that are contained in given list. - maroon_in: [DateTime!] - # All values that are not contained in given list. - maroon_not_in: [DateTime!] - # All values less than the given value. - maroon_lt: DateTime - # All values less than or equal the given value. - maroon_lte: DateTime - # All values greater than the given value. - maroon_gt: DateTime - # All values greater than or equal the given value. - maroon_gte: DateTime - silver: Boolean - # All values that are not equal to given value. - silver_not: Boolean - black: Morissette - # All values that are not equal to given value. - black_not: Morissette - # All values that are contained in given list. - black_in: [Morissette!] - # All values that are not contained in given list. - black_not_in: [Morissette!] - lime: String - # All values that are not equal to given value. - lime_not: String - # All values that are contained in given list. - lime_in: [String!] - # All values that are not contained in given list. - lime_not_in: [String!] - # All values less than the given value. - lime_lt: String - # All values less than or equal the given value. - lime_lte: String - # All values greater than the given value. - lime_gt: String - # All values greater than or equal the given value. - lime_gte: String - # All values containing the given string. - lime_contains: String - # All values not containing the given string. - lime_not_contains: String - # All values starting with the given string. - lime_starts_with: String - # All values not starting with the given string. - lime_not_starts_with: String - # All values ending with the given string. - lime_ends_with: String - # All values not ending with the given string. - lime_not_ends_with: String - fuchsia: Boolean - # All values that are not equal to given value. - fuchsia_not: Boolean - salmon: StrongholdWhereInput -} - -input ToughjoyfaxWhereUniqueInput { - id: ID -} - -type Transcof implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - maroon: String! -} - -# A connection to a list of items. -type TranscofConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [TranscofEdge]! - aggregate: AggregateTranscof! -} - -input TranscofCreateInput { - status: Status - maroon: String! -} - -# An edge in a connection. -type TranscofEdge { - # The item at the end of the edge. - node: Transcof! - # A cursor for use in pagination. - cursor: String! -} - -enum TranscofOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - maroon_ASC - maroon_DESC -} - -type TranscofPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - maroon: String! -} - -type TranscofSubscriptionPayload { - mutation: MutationType! - node: Transcof - updatedFields: [String!] - previousValues: TranscofPreviousValues -} - -input TranscofSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [TranscofSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [TranscofSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TranscofSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: TranscofWhereInput -} - -input TranscofUpdateInput { - status: Status - maroon: String -} - -input TranscofUpdateManyMutationInput { - status: Status - maroon: String -} - -input TranscofWhereInput { - # Logical AND on all given filters. - AND: [TranscofWhereInput!] - # Logical OR on all given filters. - OR: [TranscofWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TranscofWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - maroon: String - # All values that are not equal to given value. - maroon_not: String - # All values that are contained in given list. - maroon_in: [String!] - # All values that are not contained in given list. - maroon_not_in: [String!] - # All values less than the given value. - maroon_lt: String - # All values less than or equal the given value. - maroon_lte: String - # All values greater than the given value. - maroon_gt: String - # All values greater than or equal the given value. - maroon_gte: String - # All values containing the given string. - maroon_contains: String - # All values not containing the given string. - maroon_not_contains: String - # All values starting with the given string. - maroon_starts_with: String - # All values not starting with the given string. - maroon_not_starts_with: String - # All values ending with the given string. - maroon_ends_with: String - # All values not ending with the given string. - maroon_not_ends_with: String -} - -input TranscofWhereUniqueInput { - id: ID - maroon: String -} - -type Treeflex implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - cyan: Daugherty! - fuchsia: String! - orchid: Int -} - -# A connection to a list of items. -type TreeflexConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [TreeflexEdge]! - aggregate: AggregateTreeflex! -} - -input TreeflexCreateInput { - status: Status - cyan: Daugherty! - fuchsia: String! - orchid: Int -} - -# An edge in a connection. -type TreeflexEdge { - # The item at the end of the edge. - node: Treeflex! - # A cursor for use in pagination. - cursor: String! -} - -enum TreeflexOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - cyan_ASC - cyan_DESC - fuchsia_ASC - fuchsia_DESC - orchid_ASC - orchid_DESC -} - -type TreeflexPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - cyan: Daugherty! - fuchsia: String! - orchid: Int -} - -type TreeflexSubscriptionPayload { - mutation: MutationType! - node: Treeflex - updatedFields: [String!] - previousValues: TreeflexPreviousValues -} - -input TreeflexSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [TreeflexSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [TreeflexSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TreeflexSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: TreeflexWhereInput -} - -input TreeflexUpdateInput { - status: Status - cyan: Daugherty - fuchsia: String - orchid: Int -} - -input TreeflexUpdateManyMutationInput { - status: Status - cyan: Daugherty - fuchsia: String - orchid: Int -} - -input TreeflexWhereInput { - # Logical AND on all given filters. - AND: [TreeflexWhereInput!] - # Logical OR on all given filters. - OR: [TreeflexWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TreeflexWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - cyan: Daugherty - # All values that are not equal to given value. - cyan_not: Daugherty - # All values that are contained in given list. - cyan_in: [Daugherty!] - # All values that are not contained in given list. - cyan_not_in: [Daugherty!] - fuchsia: String - # All values that are not equal to given value. - fuchsia_not: String - # All values that are contained in given list. - fuchsia_in: [String!] - # All values that are not contained in given list. - fuchsia_not_in: [String!] - # All values less than the given value. - fuchsia_lt: String - # All values less than or equal the given value. - fuchsia_lte: String - # All values greater than the given value. - fuchsia_gt: String - # All values greater than or equal the given value. - fuchsia_gte: String - # All values containing the given string. - fuchsia_contains: String - # All values not containing the given string. - fuchsia_not_contains: String - # All values starting with the given string. - fuchsia_starts_with: String - # All values not starting with the given string. - fuchsia_not_starts_with: String - # All values ending with the given string. - fuchsia_ends_with: String - # All values not ending with the given string. - fuchsia_not_ends_with: String - orchid: Int - # All values that are not equal to given value. - orchid_not: Int - # All values that are contained in given list. - orchid_in: [Int!] - # All values that are not contained in given list. - orchid_not_in: [Int!] - # All values less than the given value. - orchid_lt: Int - # All values less than or equal the given value. - orchid_lte: Int - # All values greater than the given value. - orchid_gt: Int - # All values greater than or equal the given value. - orchid_gte: Int -} - -input TreeflexWhereUniqueInput { - id: ID -} - -type Tresom implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - blue: String - white: Daugherty - cyan: String - olive: Wisoky! - plum: String - turquoise: Int - teal: Alphazap -} - -# A connection to a list of items. -type TresomConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [TresomEdge]! - aggregate: AggregateTresom! -} - -input TresomCreateInput { - status: Status - blue: String - white: Daugherty - cyan: String - olive: Wisoky! - plum: String - turquoise: Int - teal: AlphazapCreateOneWithoutAzureInput -} - -input TresomCreateManyWithoutTealInput { - create: [TresomCreateWithoutTealInput!] - connect: [TresomWhereUniqueInput!] -} - -input TresomCreateWithoutTealInput { - status: Status - blue: String - white: Daugherty - cyan: String - olive: Wisoky! - plum: String - turquoise: Int -} - -# An edge in a connection. -type TresomEdge { - # The item at the end of the edge. - node: Tresom! - # A cursor for use in pagination. - cursor: String! -} - -enum TresomOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - blue_ASC - blue_DESC - white_ASC - white_DESC - cyan_ASC - cyan_DESC - olive_ASC - olive_DESC - plum_ASC - plum_DESC - turquoise_ASC - turquoise_DESC -} - -type TresomPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - blue: String - white: Daugherty - cyan: String - olive: Wisoky! - plum: String - turquoise: Int -} - -input TresomScalarWhereInput { - # Logical AND on all given filters. - AND: [TresomScalarWhereInput!] - # Logical OR on all given filters. - OR: [TresomScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TresomScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - blue: String - # All values that are not equal to given value. - blue_not: String - # All values that are contained in given list. - blue_in: [String!] - # All values that are not contained in given list. - blue_not_in: [String!] - # All values less than the given value. - blue_lt: String - # All values less than or equal the given value. - blue_lte: String - # All values greater than the given value. - blue_gt: String - # All values greater than or equal the given value. - blue_gte: String - # All values containing the given string. - blue_contains: String - # All values not containing the given string. - blue_not_contains: String - # All values starting with the given string. - blue_starts_with: String - # All values not starting with the given string. - blue_not_starts_with: String - # All values ending with the given string. - blue_ends_with: String - # All values not ending with the given string. - blue_not_ends_with: String - white: Daugherty - # All values that are not equal to given value. - white_not: Daugherty - # All values that are contained in given list. - white_in: [Daugherty!] - # All values that are not contained in given list. - white_not_in: [Daugherty!] - cyan: String - # All values that are not equal to given value. - cyan_not: String - # All values that are contained in given list. - cyan_in: [String!] - # All values that are not contained in given list. - cyan_not_in: [String!] - # All values less than the given value. - cyan_lt: String - # All values less than or equal the given value. - cyan_lte: String - # All values greater than the given value. - cyan_gt: String - # All values greater than or equal the given value. - cyan_gte: String - # All values containing the given string. - cyan_contains: String - # All values not containing the given string. - cyan_not_contains: String - # All values starting with the given string. - cyan_starts_with: String - # All values not starting with the given string. - cyan_not_starts_with: String - # All values ending with the given string. - cyan_ends_with: String - # All values not ending with the given string. - cyan_not_ends_with: String - olive: Wisoky - # All values that are not equal to given value. - olive_not: Wisoky - # All values that are contained in given list. - olive_in: [Wisoky!] - # All values that are not contained in given list. - olive_not_in: [Wisoky!] - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - turquoise: Int - # All values that are not equal to given value. - turquoise_not: Int - # All values that are contained in given list. - turquoise_in: [Int!] - # All values that are not contained in given list. - turquoise_not_in: [Int!] - # All values less than the given value. - turquoise_lt: Int - # All values less than or equal the given value. - turquoise_lte: Int - # All values greater than the given value. - turquoise_gt: Int - # All values greater than or equal the given value. - turquoise_gte: Int -} - -type TresomSubscriptionPayload { - mutation: MutationType! - node: Tresom - updatedFields: [String!] - previousValues: TresomPreviousValues -} - -input TresomSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [TresomSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [TresomSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TresomSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: TresomWhereInput -} - -input TresomUpdateInput { - status: Status - blue: String - white: Daugherty - cyan: String - olive: Wisoky - plum: String - turquoise: Int - teal: AlphazapUpdateOneWithoutAzureInput -} - -input TresomUpdateManyDataInput { - status: Status - blue: String - white: Daugherty - cyan: String - olive: Wisoky - plum: String - turquoise: Int -} - -input TresomUpdateManyMutationInput { - status: Status - blue: String - white: Daugherty - cyan: String - olive: Wisoky - plum: String - turquoise: Int -} - -input TresomUpdateManyWithoutTealInput { - create: [TresomCreateWithoutTealInput!] - connect: [TresomWhereUniqueInput!] - set: [TresomWhereUniqueInput!] - disconnect: [TresomWhereUniqueInput!] - delete: [TresomWhereUniqueInput!] - update: [TresomUpdateWithWhereUniqueWithoutTealInput!] - updateMany: [TresomUpdateManyWithWhereNestedInput!] - deleteMany: [TresomScalarWhereInput!] - upsert: [TresomUpsertWithWhereUniqueWithoutTealInput!] -} - -input TresomUpdateManyWithWhereNestedInput { - where: TresomScalarWhereInput! - data: TresomUpdateManyDataInput! -} - -input TresomUpdateWithoutTealDataInput { - status: Status - blue: String - white: Daugherty - cyan: String - olive: Wisoky - plum: String - turquoise: Int -} - -input TresomUpdateWithWhereUniqueWithoutTealInput { - where: TresomWhereUniqueInput! - data: TresomUpdateWithoutTealDataInput! -} - -input TresomUpsertWithWhereUniqueWithoutTealInput { - where: TresomWhereUniqueInput! - update: TresomUpdateWithoutTealDataInput! - create: TresomCreateWithoutTealInput! -} - -input TresomWhereInput { - # Logical AND on all given filters. - AND: [TresomWhereInput!] - # Logical OR on all given filters. - OR: [TresomWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [TresomWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - blue: String - # All values that are not equal to given value. - blue_not: String - # All values that are contained in given list. - blue_in: [String!] - # All values that are not contained in given list. - blue_not_in: [String!] - # All values less than the given value. - blue_lt: String - # All values less than or equal the given value. - blue_lte: String - # All values greater than the given value. - blue_gt: String - # All values greater than or equal the given value. - blue_gte: String - # All values containing the given string. - blue_contains: String - # All values not containing the given string. - blue_not_contains: String - # All values starting with the given string. - blue_starts_with: String - # All values not starting with the given string. - blue_not_starts_with: String - # All values ending with the given string. - blue_ends_with: String - # All values not ending with the given string. - blue_not_ends_with: String - white: Daugherty - # All values that are not equal to given value. - white_not: Daugherty - # All values that are contained in given list. - white_in: [Daugherty!] - # All values that are not contained in given list. - white_not_in: [Daugherty!] - cyan: String - # All values that are not equal to given value. - cyan_not: String - # All values that are contained in given list. - cyan_in: [String!] - # All values that are not contained in given list. - cyan_not_in: [String!] - # All values less than the given value. - cyan_lt: String - # All values less than or equal the given value. - cyan_lte: String - # All values greater than the given value. - cyan_gt: String - # All values greater than or equal the given value. - cyan_gte: String - # All values containing the given string. - cyan_contains: String - # All values not containing the given string. - cyan_not_contains: String - # All values starting with the given string. - cyan_starts_with: String - # All values not starting with the given string. - cyan_not_starts_with: String - # All values ending with the given string. - cyan_ends_with: String - # All values not ending with the given string. - cyan_not_ends_with: String - olive: Wisoky - # All values that are not equal to given value. - olive_not: Wisoky - # All values that are contained in given list. - olive_in: [Wisoky!] - # All values that are not contained in given list. - olive_not_in: [Wisoky!] - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - turquoise: Int - # All values that are not equal to given value. - turquoise_not: Int - # All values that are contained in given list. - turquoise_in: [Int!] - # All values that are not contained in given list. - turquoise_not_in: [Int!] - # All values less than the given value. - turquoise_lt: Int - # All values less than or equal the given value. - turquoise_lte: Int - # All values greater than the given value. - turquoise_gt: Int - # All values greater than or equal the given value. - turquoise_gte: Int - teal: AlphazapWhereInput -} - -input TresomWhereUniqueInput { - id: ID -} - -type Ventosanzap implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - grey: String! - lime: [Muller!]! - turquoise: String! -} - -# A connection to a list of items. -type VentosanzapConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [VentosanzapEdge]! - aggregate: AggregateVentosanzap! -} - -input VentosanzapCreateInput { - status: Status - grey: String! - turquoise: String! - lime: VentosanzapCreatelimeInput -} - -input VentosanzapCreatelimeInput { - set: [Muller!] -} - -# An edge in a connection. -type VentosanzapEdge { - # The item at the end of the edge. - node: Ventosanzap! - # A cursor for use in pagination. - cursor: String! -} - -enum VentosanzapOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - grey_ASC - grey_DESC - turquoise_ASC - turquoise_DESC -} - -type VentosanzapPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - grey: String! - lime: [Muller!]! - turquoise: String! -} - -type VentosanzapSubscriptionPayload { - mutation: MutationType! - node: Ventosanzap - updatedFields: [String!] - previousValues: VentosanzapPreviousValues -} - -input VentosanzapSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [VentosanzapSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [VentosanzapSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VentosanzapSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: VentosanzapWhereInput -} - -input VentosanzapUpdateInput { - status: Status - grey: String - turquoise: String - lime: VentosanzapUpdatelimeInput -} - -input VentosanzapUpdatelimeInput { - set: [Muller!] -} - -input VentosanzapUpdateManyMutationInput { - status: Status - grey: String - turquoise: String - lime: VentosanzapUpdatelimeInput -} - -input VentosanzapWhereInput { - # Logical AND on all given filters. - AND: [VentosanzapWhereInput!] - # Logical OR on all given filters. - OR: [VentosanzapWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VentosanzapWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - grey: String - # All values that are not equal to given value. - grey_not: String - # All values that are contained in given list. - grey_in: [String!] - # All values that are not contained in given list. - grey_not_in: [String!] - # All values less than the given value. - grey_lt: String - # All values less than or equal the given value. - grey_lte: String - # All values greater than the given value. - grey_gt: String - # All values greater than or equal the given value. - grey_gte: String - # All values containing the given string. - grey_contains: String - # All values not containing the given string. - grey_not_contains: String - # All values starting with the given string. - grey_starts_with: String - # All values not starting with the given string. - grey_not_starts_with: String - # All values ending with the given string. - grey_ends_with: String - # All values not ending with the given string. - grey_not_ends_with: String - turquoise: String - # All values that are not equal to given value. - turquoise_not: String - # All values that are contained in given list. - turquoise_in: [String!] - # All values that are not contained in given list. - turquoise_not_in: [String!] - # All values less than the given value. - turquoise_lt: String - # All values less than or equal the given value. - turquoise_lte: String - # All values greater than the given value. - turquoise_gt: String - # All values greater than or equal the given value. - turquoise_gte: String - # All values containing the given string. - turquoise_contains: String - # All values not containing the given string. - turquoise_not_contains: String - # All values starting with the given string. - turquoise_starts_with: String - # All values not starting with the given string. - turquoise_not_starts_with: String - # All values ending with the given string. - turquoise_ends_with: String - # All values not ending with the given string. - turquoise_not_ends_with: String -} - -input VentosanzapWhereUniqueInput { - id: ID -} - -type Viva implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - yellow: String - green: String - azure: String - magenta: String - lavender: String! - olive: Daugherty - gold: String - black: String -} - -# A connection to a list of items. -type VivaConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [VivaEdge]! - aggregate: AggregateViva! -} - -input VivaCreateInput { - status: Status - yellow: String - green: String - azure: String - magenta: String - lavender: String! - olive: Daugherty - gold: String - black: String -} - -# An edge in a connection. -type VivaEdge { - # The item at the end of the edge. - node: Viva! - # A cursor for use in pagination. - cursor: String! -} - -enum VivaOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - yellow_ASC - yellow_DESC - green_ASC - green_DESC - azure_ASC - azure_DESC - magenta_ASC - magenta_DESC - lavender_ASC - lavender_DESC - olive_ASC - olive_DESC - gold_ASC - gold_DESC - black_ASC - black_DESC -} - -type VivaPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - yellow: String - green: String - azure: String - magenta: String - lavender: String! - olive: Daugherty - gold: String - black: String -} - -type VivaSubscriptionPayload { - mutation: MutationType! - node: Viva - updatedFields: [String!] - previousValues: VivaPreviousValues -} - -input VivaSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [VivaSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [VivaSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VivaSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: VivaWhereInput -} - -input VivaUpdateInput { - status: Status - yellow: String - green: String - azure: String - magenta: String - lavender: String - olive: Daugherty - gold: String - black: String -} - -input VivaUpdateManyMutationInput { - status: Status - yellow: String - green: String - azure: String - magenta: String - lavender: String - olive: Daugherty - gold: String - black: String -} - -input VivaWhereInput { - # Logical AND on all given filters. - AND: [VivaWhereInput!] - # Logical OR on all given filters. - OR: [VivaWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VivaWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - yellow: String - # All values that are not equal to given value. - yellow_not: String - # All values that are contained in given list. - yellow_in: [String!] - # All values that are not contained in given list. - yellow_not_in: [String!] - # All values less than the given value. - yellow_lt: String - # All values less than or equal the given value. - yellow_lte: String - # All values greater than the given value. - yellow_gt: String - # All values greater than or equal the given value. - yellow_gte: String - # All values containing the given string. - yellow_contains: String - # All values not containing the given string. - yellow_not_contains: String - # All values starting with the given string. - yellow_starts_with: String - # All values not starting with the given string. - yellow_not_starts_with: String - # All values ending with the given string. - yellow_ends_with: String - # All values not ending with the given string. - yellow_not_ends_with: String - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String - azure: String - # All values that are not equal to given value. - azure_not: String - # All values that are contained in given list. - azure_in: [String!] - # All values that are not contained in given list. - azure_not_in: [String!] - # All values less than the given value. - azure_lt: String - # All values less than or equal the given value. - azure_lte: String - # All values greater than the given value. - azure_gt: String - # All values greater than or equal the given value. - azure_gte: String - # All values containing the given string. - azure_contains: String - # All values not containing the given string. - azure_not_contains: String - # All values starting with the given string. - azure_starts_with: String - # All values not starting with the given string. - azure_not_starts_with: String - # All values ending with the given string. - azure_ends_with: String - # All values not ending with the given string. - azure_not_ends_with: String - magenta: String - # All values that are not equal to given value. - magenta_not: String - # All values that are contained in given list. - magenta_in: [String!] - # All values that are not contained in given list. - magenta_not_in: [String!] - # All values less than the given value. - magenta_lt: String - # All values less than or equal the given value. - magenta_lte: String - # All values greater than the given value. - magenta_gt: String - # All values greater than or equal the given value. - magenta_gte: String - # All values containing the given string. - magenta_contains: String - # All values not containing the given string. - magenta_not_contains: String - # All values starting with the given string. - magenta_starts_with: String - # All values not starting with the given string. - magenta_not_starts_with: String - # All values ending with the given string. - magenta_ends_with: String - # All values not ending with the given string. - magenta_not_ends_with: String - lavender: String - # All values that are not equal to given value. - lavender_not: String - # All values that are contained in given list. - lavender_in: [String!] - # All values that are not contained in given list. - lavender_not_in: [String!] - # All values less than the given value. - lavender_lt: String - # All values less than or equal the given value. - lavender_lte: String - # All values greater than the given value. - lavender_gt: String - # All values greater than or equal the given value. - lavender_gte: String - # All values containing the given string. - lavender_contains: String - # All values not containing the given string. - lavender_not_contains: String - # All values starting with the given string. - lavender_starts_with: String - # All values not starting with the given string. - lavender_not_starts_with: String - # All values ending with the given string. - lavender_ends_with: String - # All values not ending with the given string. - lavender_not_ends_with: String - olive: Daugherty - # All values that are not equal to given value. - olive_not: Daugherty - # All values that are contained in given list. - olive_in: [Daugherty!] - # All values that are not contained in given list. - olive_not_in: [Daugherty!] - gold: String - # All values that are not equal to given value. - gold_not: String - # All values that are contained in given list. - gold_in: [String!] - # All values that are not contained in given list. - gold_not_in: [String!] - # All values less than the given value. - gold_lt: String - # All values less than or equal the given value. - gold_lte: String - # All values greater than the given value. - gold_gt: String - # All values greater than or equal the given value. - gold_gte: String - # All values containing the given string. - gold_contains: String - # All values not containing the given string. - gold_not_contains: String - # All values starting with the given string. - gold_starts_with: String - # All values not starting with the given string. - gold_not_starts_with: String - # All values ending with the given string. - gold_ends_with: String - # All values not ending with the given string. - gold_not_ends_with: String - black: String - # All values that are not equal to given value. - black_not: String - # All values that are contained in given list. - black_in: [String!] - # All values that are not contained in given list. - black_not_in: [String!] - # All values less than the given value. - black_lt: String - # All values less than or equal the given value. - black_lte: String - # All values greater than the given value. - black_gt: String - # All values greater than or equal the given value. - black_gte: String - # All values containing the given string. - black_contains: String - # All values not containing the given string. - black_not_contains: String - # All values starting with the given string. - black_starts_with: String - # All values not starting with the given string. - black_not_starts_with: String - # All values ending with the given string. - black_ends_with: String - # All values not ending with the given string. - black_not_ends_with: String -} - -input VivaWhereUniqueInput { - id: ID - olive: Daugherty -} - -type Voltsillam implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - ivory: String - black: String - olive: String - cyan: Daugherty! -} - -# A connection to a list of items. -type VoltsillamConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [VoltsillamEdge]! - aggregate: AggregateVoltsillam! -} - -input VoltsillamCreateInput { - status: Status - ivory: String - black: String - olive: String - cyan: Daugherty! -} - -# An edge in a connection. -type VoltsillamEdge { - # The item at the end of the edge. - node: Voltsillam! - # A cursor for use in pagination. - cursor: String! -} - -enum VoltsillamOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - ivory_ASC - ivory_DESC - black_ASC - black_DESC - olive_ASC - olive_DESC - cyan_ASC - cyan_DESC -} - -type VoltsillamPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - ivory: String - black: String - olive: String - cyan: Daugherty! -} - -type VoltsillamSubscriptionPayload { - mutation: MutationType! - node: Voltsillam - updatedFields: [String!] - previousValues: VoltsillamPreviousValues -} - -input VoltsillamSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [VoltsillamSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [VoltsillamSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VoltsillamSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: VoltsillamWhereInput -} - -input VoltsillamUpdateInput { - status: Status - ivory: String - black: String - olive: String - cyan: Daugherty -} - -input VoltsillamUpdateManyMutationInput { - status: Status - ivory: String - black: String - olive: String - cyan: Daugherty -} - -input VoltsillamWhereInput { - # Logical AND on all given filters. - AND: [VoltsillamWhereInput!] - # Logical OR on all given filters. - OR: [VoltsillamWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VoltsillamWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - ivory: String - # All values that are not equal to given value. - ivory_not: String - # All values that are contained in given list. - ivory_in: [String!] - # All values that are not contained in given list. - ivory_not_in: [String!] - # All values less than the given value. - ivory_lt: String - # All values less than or equal the given value. - ivory_lte: String - # All values greater than the given value. - ivory_gt: String - # All values greater than or equal the given value. - ivory_gte: String - # All values containing the given string. - ivory_contains: String - # All values not containing the given string. - ivory_not_contains: String - # All values starting with the given string. - ivory_starts_with: String - # All values not starting with the given string. - ivory_not_starts_with: String - # All values ending with the given string. - ivory_ends_with: String - # All values not ending with the given string. - ivory_not_ends_with: String - black: String - # All values that are not equal to given value. - black_not: String - # All values that are contained in given list. - black_in: [String!] - # All values that are not contained in given list. - black_not_in: [String!] - # All values less than the given value. - black_lt: String - # All values less than or equal the given value. - black_lte: String - # All values greater than the given value. - black_gt: String - # All values greater than or equal the given value. - black_gte: String - # All values containing the given string. - black_contains: String - # All values not containing the given string. - black_not_contains: String - # All values starting with the given string. - black_starts_with: String - # All values not starting with the given string. - black_not_starts_with: String - # All values ending with the given string. - black_ends_with: String - # All values not ending with the given string. - black_not_ends_with: String - olive: String - # All values that are not equal to given value. - olive_not: String - # All values that are contained in given list. - olive_in: [String!] - # All values that are not contained in given list. - olive_not_in: [String!] - # All values less than the given value. - olive_lt: String - # All values less than or equal the given value. - olive_lte: String - # All values greater than the given value. - olive_gt: String - # All values greater than or equal the given value. - olive_gte: String - # All values containing the given string. - olive_contains: String - # All values not containing the given string. - olive_not_contains: String - # All values starting with the given string. - olive_starts_with: String - # All values not starting with the given string. - olive_not_starts_with: String - # All values ending with the given string. - olive_ends_with: String - # All values not ending with the given string. - olive_not_ends_with: String - cyan: Daugherty - # All values that are not equal to given value. - cyan_not: Daugherty - # All values that are contained in given list. - cyan_in: [Daugherty!] - # All values that are not contained in given list. - cyan_not_in: [Daugherty!] -} - -input VoltsillamWhereUniqueInput { - id: ID - cyan: Daugherty -} - -enum Von { - ZERO - ONE - TWO - THREE -} - -type Voyatouch implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - purple: String! - white: String! - tan( - where: BigtaxWhereInput - orderBy: BigtaxOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Bigtax!] - orange: Int - silver: String -} - -# A connection to a list of items. -type VoyatouchConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [VoyatouchEdge]! - aggregate: AggregateVoyatouch! -} - -input VoyatouchCreateInput { - status: Status - purple: String! - white: String! - orange: Int - silver: String - tan: BigtaxCreateManyWithoutYellowInput -} - -input VoyatouchCreateManyWithoutTanInput { - create: [VoyatouchCreateWithoutTanInput!] - connect: [VoyatouchWhereUniqueInput!] -} - -input VoyatouchCreateWithoutTanInput { - status: Status - purple: String! - white: String! - orange: Int - silver: String -} - -# An edge in a connection. -type VoyatouchEdge { - # The item at the end of the edge. - node: Voyatouch! - # A cursor for use in pagination. - cursor: String! -} - -enum VoyatouchOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - purple_ASC - purple_DESC - white_ASC - white_DESC - orange_ASC - orange_DESC - silver_ASC - silver_DESC -} - -type VoyatouchPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - purple: String! - white: String! - orange: Int - silver: String -} - -input VoyatouchScalarWhereInput { - # Logical AND on all given filters. - AND: [VoyatouchScalarWhereInput!] - # Logical OR on all given filters. - OR: [VoyatouchScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VoyatouchScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - white: String - # All values that are not equal to given value. - white_not: String - # All values that are contained in given list. - white_in: [String!] - # All values that are not contained in given list. - white_not_in: [String!] - # All values less than the given value. - white_lt: String - # All values less than or equal the given value. - white_lte: String - # All values greater than the given value. - white_gt: String - # All values greater than or equal the given value. - white_gte: String - # All values containing the given string. - white_contains: String - # All values not containing the given string. - white_not_contains: String - # All values starting with the given string. - white_starts_with: String - # All values not starting with the given string. - white_not_starts_with: String - # All values ending with the given string. - white_ends_with: String - # All values not ending with the given string. - white_not_ends_with: String - orange: Int - # All values that are not equal to given value. - orange_not: Int - # All values that are contained in given list. - orange_in: [Int!] - # All values that are not contained in given list. - orange_not_in: [Int!] - # All values less than the given value. - orange_lt: Int - # All values less than or equal the given value. - orange_lte: Int - # All values greater than the given value. - orange_gt: Int - # All values greater than or equal the given value. - orange_gte: Int - silver: String - # All values that are not equal to given value. - silver_not: String - # All values that are contained in given list. - silver_in: [String!] - # All values that are not contained in given list. - silver_not_in: [String!] - # All values less than the given value. - silver_lt: String - # All values less than or equal the given value. - silver_lte: String - # All values greater than the given value. - silver_gt: String - # All values greater than or equal the given value. - silver_gte: String - # All values containing the given string. - silver_contains: String - # All values not containing the given string. - silver_not_contains: String - # All values starting with the given string. - silver_starts_with: String - # All values not starting with the given string. - silver_not_starts_with: String - # All values ending with the given string. - silver_ends_with: String - # All values not ending with the given string. - silver_not_ends_with: String -} - -type VoyatouchSubscriptionPayload { - mutation: MutationType! - node: Voyatouch - updatedFields: [String!] - previousValues: VoyatouchPreviousValues -} - -input VoyatouchSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [VoyatouchSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [VoyatouchSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VoyatouchSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: VoyatouchWhereInput -} - -input VoyatouchUpdateInput { - status: Status - purple: String - white: String - orange: Int - silver: String - tan: BigtaxUpdateManyWithoutYellowInput -} - -input VoyatouchUpdateManyDataInput { - status: Status - purple: String - white: String - orange: Int - silver: String -} - -input VoyatouchUpdateManyMutationInput { - status: Status - purple: String - white: String - orange: Int - silver: String -} - -input VoyatouchUpdateManyWithoutTanInput { - create: [VoyatouchCreateWithoutTanInput!] - connect: [VoyatouchWhereUniqueInput!] - set: [VoyatouchWhereUniqueInput!] - disconnect: [VoyatouchWhereUniqueInput!] - delete: [VoyatouchWhereUniqueInput!] - update: [VoyatouchUpdateWithWhereUniqueWithoutTanInput!] - updateMany: [VoyatouchUpdateManyWithWhereNestedInput!] - deleteMany: [VoyatouchScalarWhereInput!] - upsert: [VoyatouchUpsertWithWhereUniqueWithoutTanInput!] -} - -input VoyatouchUpdateManyWithWhereNestedInput { - where: VoyatouchScalarWhereInput! - data: VoyatouchUpdateManyDataInput! -} - -input VoyatouchUpdateWithoutTanDataInput { - status: Status - purple: String - white: String - orange: Int - silver: String -} - -input VoyatouchUpdateWithWhereUniqueWithoutTanInput { - where: VoyatouchWhereUniqueInput! - data: VoyatouchUpdateWithoutTanDataInput! -} - -input VoyatouchUpsertWithWhereUniqueWithoutTanInput { - where: VoyatouchWhereUniqueInput! - update: VoyatouchUpdateWithoutTanDataInput! - create: VoyatouchCreateWithoutTanInput! -} - -input VoyatouchWhereInput { - # Logical AND on all given filters. - AND: [VoyatouchWhereInput!] - # Logical OR on all given filters. - OR: [VoyatouchWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [VoyatouchWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - purple: String - # All values that are not equal to given value. - purple_not: String - # All values that are contained in given list. - purple_in: [String!] - # All values that are not contained in given list. - purple_not_in: [String!] - # All values less than the given value. - purple_lt: String - # All values less than or equal the given value. - purple_lte: String - # All values greater than the given value. - purple_gt: String - # All values greater than or equal the given value. - purple_gte: String - # All values containing the given string. - purple_contains: String - # All values not containing the given string. - purple_not_contains: String - # All values starting with the given string. - purple_starts_with: String - # All values not starting with the given string. - purple_not_starts_with: String - # All values ending with the given string. - purple_ends_with: String - # All values not ending with the given string. - purple_not_ends_with: String - white: String - # All values that are not equal to given value. - white_not: String - # All values that are contained in given list. - white_in: [String!] - # All values that are not contained in given list. - white_not_in: [String!] - # All values less than the given value. - white_lt: String - # All values less than or equal the given value. - white_lte: String - # All values greater than the given value. - white_gt: String - # All values greater than or equal the given value. - white_gte: String - # All values containing the given string. - white_contains: String - # All values not containing the given string. - white_not_contains: String - # All values starting with the given string. - white_starts_with: String - # All values not starting with the given string. - white_not_starts_with: String - # All values ending with the given string. - white_ends_with: String - # All values not ending with the given string. - white_not_ends_with: String - orange: Int - # All values that are not equal to given value. - orange_not: Int - # All values that are contained in given list. - orange_in: [Int!] - # All values that are not contained in given list. - orange_not_in: [Int!] - # All values less than the given value. - orange_lt: Int - # All values less than or equal the given value. - orange_lte: Int - # All values greater than the given value. - orange_gt: Int - # All values greater than or equal the given value. - orange_gte: Int - silver: String - # All values that are not equal to given value. - silver_not: String - # All values that are contained in given list. - silver_in: [String!] - # All values that are not contained in given list. - silver_not_in: [String!] - # All values less than the given value. - silver_lt: String - # All values less than or equal the given value. - silver_lte: String - # All values greater than the given value. - silver_gt: String - # All values greater than or equal the given value. - silver_gte: String - # All values containing the given string. - silver_contains: String - # All values not containing the given string. - silver_not_contains: String - # All values starting with the given string. - silver_starts_with: String - # All values not starting with the given string. - silver_not_starts_with: String - # All values ending with the given string. - silver_ends_with: String - # All values not ending with the given string. - silver_not_ends_with: String - tan_every: BigtaxWhereInput - tan_some: BigtaxWhereInput - tan_none: BigtaxWhereInput -} - -input VoyatouchWhereUniqueInput { - id: ID -} - -enum Wisoky { - ET - AT - BLANDITIIS - REICIENDIS -} - -type Zamit implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - green: String - ivory: String! - orchid: String! - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String - grey: Asset -} - -# A connection to a list of items. -type ZamitConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [ZamitEdge]! - aggregate: AggregateZamit! -} - -input ZamitCreateInput { - status: Status - green: String - ivory: String! - orchid: String! - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String - grey: AssetCreateOneWithoutGreyZamitInput -} - -input ZamitCreateManyWithoutGreyInput { - create: [ZamitCreateWithoutGreyInput!] - connect: [ZamitWhereUniqueInput!] -} - -input ZamitCreateWithoutGreyInput { - status: Status - green: String - ivory: String! - orchid: String! - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String -} - -# An edge in a connection. -type ZamitEdge { - # The item at the end of the edge. - node: Zamit! - # A cursor for use in pagination. - cursor: String! -} - -enum ZamitOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - green_ASC - green_DESC - ivory_ASC - ivory_DESC - orchid_ASC - orchid_DESC - fuchsia_ASC - fuchsia_DESC - violet_ASC - violet_DESC - yellow_ASC - yellow_DESC - orange_ASC - orange_DESC - plum_ASC - plum_DESC -} - -type ZamitPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - green: String - ivory: String! - orchid: String! - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String -} - -input ZamitScalarWhereInput { - # Logical AND on all given filters. - AND: [ZamitScalarWhereInput!] - # Logical OR on all given filters. - OR: [ZamitScalarWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZamitScalarWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String - ivory: String - # All values that are not equal to given value. - ivory_not: String - # All values that are contained in given list. - ivory_in: [String!] - # All values that are not contained in given list. - ivory_not_in: [String!] - # All values less than the given value. - ivory_lt: String - # All values less than or equal the given value. - ivory_lte: String - # All values greater than the given value. - ivory_gt: String - # All values greater than or equal the given value. - ivory_gte: String - # All values containing the given string. - ivory_contains: String - # All values not containing the given string. - ivory_not_contains: String - # All values starting with the given string. - ivory_starts_with: String - # All values not starting with the given string. - ivory_not_starts_with: String - # All values ending with the given string. - ivory_ends_with: String - # All values not ending with the given string. - ivory_not_ends_with: String - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - fuchsia: String - # All values that are not equal to given value. - fuchsia_not: String - # All values that are contained in given list. - fuchsia_in: [String!] - # All values that are not contained in given list. - fuchsia_not_in: [String!] - # All values less than the given value. - fuchsia_lt: String - # All values less than or equal the given value. - fuchsia_lte: String - # All values greater than the given value. - fuchsia_gt: String - # All values greater than or equal the given value. - fuchsia_gte: String - # All values containing the given string. - fuchsia_contains: String - # All values not containing the given string. - fuchsia_not_contains: String - # All values starting with the given string. - fuchsia_starts_with: String - # All values not starting with the given string. - fuchsia_not_starts_with: String - # All values ending with the given string. - fuchsia_ends_with: String - # All values not ending with the given string. - fuchsia_not_ends_with: String - violet: Parker - # All values that are not equal to given value. - violet_not: Parker - # All values that are contained in given list. - violet_in: [Parker!] - # All values that are not contained in given list. - violet_not_in: [Parker!] - yellow: Boolean - # All values that are not equal to given value. - yellow_not: Boolean - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String -} - -type ZamitSubscriptionPayload { - mutation: MutationType! - node: Zamit - updatedFields: [String!] - previousValues: ZamitPreviousValues -} - -input ZamitSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [ZamitSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [ZamitSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZamitSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: ZamitWhereInput -} - -input ZamitUpdateInput { - status: Status - green: String - ivory: String - orchid: String - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String - grey: AssetUpdateOneWithoutGreyZamitInput -} - -input ZamitUpdateManyDataInput { - status: Status - green: String - ivory: String - orchid: String - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String -} - -input ZamitUpdateManyMutationInput { - status: Status - green: String - ivory: String - orchid: String - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String -} - -input ZamitUpdateManyWithoutGreyInput { - create: [ZamitCreateWithoutGreyInput!] - connect: [ZamitWhereUniqueInput!] - set: [ZamitWhereUniqueInput!] - disconnect: [ZamitWhereUniqueInput!] - delete: [ZamitWhereUniqueInput!] - update: [ZamitUpdateWithWhereUniqueWithoutGreyInput!] - updateMany: [ZamitUpdateManyWithWhereNestedInput!] - deleteMany: [ZamitScalarWhereInput!] - upsert: [ZamitUpsertWithWhereUniqueWithoutGreyInput!] -} - -input ZamitUpdateManyWithWhereNestedInput { - where: ZamitScalarWhereInput! - data: ZamitUpdateManyDataInput! -} - -input ZamitUpdateWithoutGreyDataInput { - status: Status - green: String - ivory: String - orchid: String - fuchsia: String - violet: Parker - yellow: Boolean - orange: String - plum: String -} - -input ZamitUpdateWithWhereUniqueWithoutGreyInput { - where: ZamitWhereUniqueInput! - data: ZamitUpdateWithoutGreyDataInput! -} - -input ZamitUpsertWithWhereUniqueWithoutGreyInput { - where: ZamitWhereUniqueInput! - update: ZamitUpdateWithoutGreyDataInput! - create: ZamitCreateWithoutGreyInput! -} - -input ZamitWhereInput { - # Logical AND on all given filters. - AND: [ZamitWhereInput!] - # Logical OR on all given filters. - OR: [ZamitWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZamitWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - green: String - # All values that are not equal to given value. - green_not: String - # All values that are contained in given list. - green_in: [String!] - # All values that are not contained in given list. - green_not_in: [String!] - # All values less than the given value. - green_lt: String - # All values less than or equal the given value. - green_lte: String - # All values greater than the given value. - green_gt: String - # All values greater than or equal the given value. - green_gte: String - # All values containing the given string. - green_contains: String - # All values not containing the given string. - green_not_contains: String - # All values starting with the given string. - green_starts_with: String - # All values not starting with the given string. - green_not_starts_with: String - # All values ending with the given string. - green_ends_with: String - # All values not ending with the given string. - green_not_ends_with: String - ivory: String - # All values that are not equal to given value. - ivory_not: String - # All values that are contained in given list. - ivory_in: [String!] - # All values that are not contained in given list. - ivory_not_in: [String!] - # All values less than the given value. - ivory_lt: String - # All values less than or equal the given value. - ivory_lte: String - # All values greater than the given value. - ivory_gt: String - # All values greater than or equal the given value. - ivory_gte: String - # All values containing the given string. - ivory_contains: String - # All values not containing the given string. - ivory_not_contains: String - # All values starting with the given string. - ivory_starts_with: String - # All values not starting with the given string. - ivory_not_starts_with: String - # All values ending with the given string. - ivory_ends_with: String - # All values not ending with the given string. - ivory_not_ends_with: String - orchid: String - # All values that are not equal to given value. - orchid_not: String - # All values that are contained in given list. - orchid_in: [String!] - # All values that are not contained in given list. - orchid_not_in: [String!] - # All values less than the given value. - orchid_lt: String - # All values less than or equal the given value. - orchid_lte: String - # All values greater than the given value. - orchid_gt: String - # All values greater than or equal the given value. - orchid_gte: String - # All values containing the given string. - orchid_contains: String - # All values not containing the given string. - orchid_not_contains: String - # All values starting with the given string. - orchid_starts_with: String - # All values not starting with the given string. - orchid_not_starts_with: String - # All values ending with the given string. - orchid_ends_with: String - # All values not ending with the given string. - orchid_not_ends_with: String - fuchsia: String - # All values that are not equal to given value. - fuchsia_not: String - # All values that are contained in given list. - fuchsia_in: [String!] - # All values that are not contained in given list. - fuchsia_not_in: [String!] - # All values less than the given value. - fuchsia_lt: String - # All values less than or equal the given value. - fuchsia_lte: String - # All values greater than the given value. - fuchsia_gt: String - # All values greater than or equal the given value. - fuchsia_gte: String - # All values containing the given string. - fuchsia_contains: String - # All values not containing the given string. - fuchsia_not_contains: String - # All values starting with the given string. - fuchsia_starts_with: String - # All values not starting with the given string. - fuchsia_not_starts_with: String - # All values ending with the given string. - fuchsia_ends_with: String - # All values not ending with the given string. - fuchsia_not_ends_with: String - violet: Parker - # All values that are not equal to given value. - violet_not: Parker - # All values that are contained in given list. - violet_in: [Parker!] - # All values that are not contained in given list. - violet_not_in: [Parker!] - yellow: Boolean - # All values that are not equal to given value. - yellow_not: Boolean - orange: String - # All values that are not equal to given value. - orange_not: String - # All values that are contained in given list. - orange_in: [String!] - # All values that are not contained in given list. - orange_not_in: [String!] - # All values less than the given value. - orange_lt: String - # All values less than or equal the given value. - orange_lte: String - # All values greater than the given value. - orange_gt: String - # All values greater than or equal the given value. - orange_gte: String - # All values containing the given string. - orange_contains: String - # All values not containing the given string. - orange_not_contains: String - # All values starting with the given string. - orange_starts_with: String - # All values not starting with the given string. - orange_not_starts_with: String - # All values ending with the given string. - orange_ends_with: String - # All values not ending with the given string. - orange_not_ends_with: String - plum: String - # All values that are not equal to given value. - plum_not: String - # All values that are contained in given list. - plum_in: [String!] - # All values that are not contained in given list. - plum_not_in: [String!] - # All values less than the given value. - plum_lt: String - # All values less than or equal the given value. - plum_lte: String - # All values greater than the given value. - plum_gt: String - # All values greater than or equal the given value. - plum_gte: String - # All values containing the given string. - plum_contains: String - # All values not containing the given string. - plum_not_contains: String - # All values starting with the given string. - plum_starts_with: String - # All values not starting with the given string. - plum_not_starts_with: String - # All values ending with the given string. - plum_ends_with: String - # All values not ending with the given string. - plum_not_ends_with: String - grey: AssetWhereInput -} - -input ZamitWhereUniqueInput { - id: ID - orchid: String -} - -type Zathin implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - pink: String - cyan: [King!]! -} - -# A connection to a list of items. -type ZathinConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [ZathinEdge]! - aggregate: AggregateZathin! -} - -input ZathinCreatecyanInput { - set: [King!] -} - -input ZathinCreateInput { - status: Status - pink: String - cyan: ZathinCreatecyanInput -} - -# An edge in a connection. -type ZathinEdge { - # The item at the end of the edge. - node: Zathin! - # A cursor for use in pagination. - cursor: String! -} - -enum ZathinOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - pink_ASC - pink_DESC -} - -type ZathinPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - pink: String - cyan: [King!]! -} - -type ZathinSubscriptionPayload { - mutation: MutationType! - node: Zathin - updatedFields: [String!] - previousValues: ZathinPreviousValues -} - -input ZathinSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [ZathinSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [ZathinSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZathinSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: ZathinWhereInput -} - -input ZathinUpdatecyanInput { - set: [King!] -} - -input ZathinUpdateInput { - status: Status - pink: String - cyan: ZathinUpdatecyanInput -} - -input ZathinUpdateManyMutationInput { - status: Status - pink: String - cyan: ZathinUpdatecyanInput -} - -input ZathinWhereInput { - # Logical AND on all given filters. - AND: [ZathinWhereInput!] - # Logical OR on all given filters. - OR: [ZathinWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZathinWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - pink: String - # All values that are not equal to given value. - pink_not: String - # All values that are contained in given list. - pink_in: [String!] - # All values that are not contained in given list. - pink_not_in: [String!] - # All values less than the given value. - pink_lt: String - # All values less than or equal the given value. - pink_lte: String - # All values greater than the given value. - pink_gt: String - # All values greater than or equal the given value. - pink_gte: String - # All values containing the given string. - pink_contains: String - # All values not containing the given string. - pink_not_contains: String - # All values starting with the given string. - pink_starts_with: String - # All values not starting with the given string. - pink_not_starts_with: String - # All values ending with the given string. - pink_ends_with: String - # All values not ending with the given string. - pink_not_ends_with: String -} - -input ZathinWhereUniqueInput { - id: ID -} - -type Zoolab implements Node { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - indigo: String! - azure: Int - tan( - where: JobWhereInput - orderBy: JobOrderByInput - skip: Int - after: String - before: String - first: Int - last: Int - ): [Job!] -} - -# A connection to a list of items. -type ZoolabConnection { - # Information to aid in pagination. - pageInfo: PageInfo! - # A list of edges. - edges: [ZoolabEdge]! - aggregate: AggregateZoolab! -} - -input ZoolabCreateInput { - status: Status - indigo: String! - azure: Int - tan: JobCreateManyWithoutTanInput -} - -input ZoolabCreateOneWithoutTanInput { - create: ZoolabCreateWithoutTanInput - connect: ZoolabWhereUniqueInput -} - -input ZoolabCreateWithoutTanInput { - status: Status - indigo: String! - azure: Int -} - -# An edge in a connection. -type ZoolabEdge { - # The item at the end of the edge. - node: Zoolab! - # A cursor for use in pagination. - cursor: String! -} - -enum ZoolabOrderByInput { - status_ASC - status_DESC - updatedAt_ASC - updatedAt_DESC - createdAt_ASC - createdAt_DESC - id_ASC - id_DESC - indigo_ASC - indigo_DESC - azure_ASC - azure_DESC -} - -type ZoolabPreviousValues { - status: Status! - updatedAt: DateTime! - createdAt: DateTime! - id: ID! - indigo: String! - azure: Int -} - -type ZoolabSubscriptionPayload { - mutation: MutationType! - node: Zoolab - updatedFields: [String!] - previousValues: ZoolabPreviousValues -} - -input ZoolabSubscriptionWhereInput { - # Logical AND on all given filters. - AND: [ZoolabSubscriptionWhereInput!] - # Logical OR on all given filters. - OR: [ZoolabSubscriptionWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZoolabSubscriptionWhereInput!] - # The subscription event gets dispatched when it's listed in mutation_in - mutation_in: [MutationType!] - # The subscription event gets only dispatched when one of the updated fields names is included in this list - updatedFields_contains: String - # The subscription event gets only dispatched when all of the field names included in this list have been updated - updatedFields_contains_every: [String!] - # The subscription event gets only dispatched when some of the field names included in this list have been updated - updatedFields_contains_some: [String!] - node: ZoolabWhereInput -} - -input ZoolabUpdateInput { - status: Status - indigo: String - azure: Int - tan: JobUpdateManyWithoutTanInput -} - -input ZoolabUpdateManyMutationInput { - status: Status - indigo: String - azure: Int -} - -input ZoolabUpdateOneWithoutTanInput { - create: ZoolabCreateWithoutTanInput - connect: ZoolabWhereUniqueInput - disconnect: Boolean - delete: Boolean - update: ZoolabUpdateWithoutTanDataInput - upsert: ZoolabUpsertWithoutTanInput -} - -input ZoolabUpdateWithoutTanDataInput { - status: Status - indigo: String - azure: Int -} - -input ZoolabUpsertWithoutTanInput { - update: ZoolabUpdateWithoutTanDataInput! - create: ZoolabCreateWithoutTanInput! -} - -input ZoolabWhereInput { - # Logical AND on all given filters. - AND: [ZoolabWhereInput!] - # Logical OR on all given filters. - OR: [ZoolabWhereInput!] - # Logical NOT on all given filters combined by AND. - NOT: [ZoolabWhereInput!] - status: Status - # All values that are not equal to given value. - status_not: Status - # All values that are contained in given list. - status_in: [Status!] - # All values that are not contained in given list. - status_not_in: [Status!] - updatedAt: DateTime - # All values that are not equal to given value. - updatedAt_not: DateTime - # All values that are contained in given list. - updatedAt_in: [DateTime!] - # All values that are not contained in given list. - updatedAt_not_in: [DateTime!] - # All values less than the given value. - updatedAt_lt: DateTime - # All values less than or equal the given value. - updatedAt_lte: DateTime - # All values greater than the given value. - updatedAt_gt: DateTime - # All values greater than or equal the given value. - updatedAt_gte: DateTime - createdAt: DateTime - # All values that are not equal to given value. - createdAt_not: DateTime - # All values that are contained in given list. - createdAt_in: [DateTime!] - # All values that are not contained in given list. - createdAt_not_in: [DateTime!] - # All values less than the given value. - createdAt_lt: DateTime - # All values less than or equal the given value. - createdAt_lte: DateTime - # All values greater than the given value. - createdAt_gt: DateTime - # All values greater than or equal the given value. - createdAt_gte: DateTime - id: ID - # All values that are not equal to given value. - id_not: ID - # All values that are contained in given list. - id_in: [ID!] - # All values that are not contained in given list. - id_not_in: [ID!] - # All values less than the given value. - id_lt: ID - # All values less than or equal the given value. - id_lte: ID - # All values greater than the given value. - id_gt: ID - # All values greater than or equal the given value. - id_gte: ID - # All values containing the given string. - id_contains: ID - # All values not containing the given string. - id_not_contains: ID - # All values starting with the given string. - id_starts_with: ID - # All values not starting with the given string. - id_not_starts_with: ID - # All values ending with the given string. - id_ends_with: ID - # All values not ending with the given string. - id_not_ends_with: ID - indigo: String - # All values that are not equal to given value. - indigo_not: String - # All values that are contained in given list. - indigo_in: [String!] - # All values that are not contained in given list. - indigo_not_in: [String!] - # All values less than the given value. - indigo_lt: String - # All values less than or equal the given value. - indigo_lte: String - # All values greater than the given value. - indigo_gt: String - # All values greater than or equal the given value. - indigo_gte: String - # All values containing the given string. - indigo_contains: String - # All values not containing the given string. - indigo_not_contains: String - # All values starting with the given string. - indigo_starts_with: String - # All values not starting with the given string. - indigo_not_starts_with: String - # All values ending with the given string. - indigo_ends_with: String - # All values not ending with the given string. - indigo_not_ends_with: String - azure: Int - # All values that are not equal to given value. - azure_not: Int - # All values that are contained in given list. - azure_in: [Int!] - # All values that are not contained in given list. - azure_not_in: [Int!] - # All values less than the given value. - azure_lt: Int - # All values less than or equal the given value. - azure_lte: Int - # All values greater than the given value. - azure_gt: Int - # All values greater than or equal the given value. - azure_gte: Int - tan_every: JobWhereInput - tan_some: JobWhereInput - tan_none: JobWhereInput -} - -input ZoolabWhereUniqueInput { - id: ID -} - diff --git a/pkg/astparser/testdata/github.schema.graphql b/pkg/astparser/testdata/github.schema.graphql deleted file mode 100644 index 84c6bd60a..000000000 --- a/pkg/astparser/testdata/github.schema.graphql +++ /dev/null @@ -1,29914 +0,0 @@ -""" -Autogenerated input type of AcceptEnterpriseAdministratorInvitation -""" -input AcceptEnterpriseAdministratorInvitationInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the invitation being accepted - """ - invitationId: ID! -} - -""" -Autogenerated input type of AcceptTopicSuggestion -""" -input AcceptTopicSuggestionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the suggested topic. - """ - name: String! - - """ - The Node ID of the repository. - """ - repositoryId: ID! -} - -""" -Autogenerated return type of AcceptTopicSuggestion -""" -type AcceptTopicSuggestionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The accepted topic. - """ - topic: Topic -} - -""" -Represents an object which can take actions on GitHub. Typically a User or Bot. -""" -interface Actor { - """ - A URL pointing to the actor's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - The username of the actor. - """ - login: String! - - """ - The HTTP path for this actor. - """ - resourcePath: URI! - - """ - The HTTP URL for this actor. - """ - url: URI! -} - -""" -Location information for an actor -""" -type ActorLocation { - """ - City - """ - city: String - - """ - Country name - """ - country: String - - """ - Country code - """ - countryCode: String - - """ - Region name - """ - region: String - - """ - Region or state code - """ - regionCode: String -} - -""" -Autogenerated input type of AddAssigneesToAssignable -""" -input AddAssigneesToAssignableInput { - """ - The id of the assignable object to add assignees to. - """ - assignableId: ID! - - """ - The id of users to add as assignees. - """ - assigneeIds: [ID!]! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of AddAssigneesToAssignable -""" -type AddAssigneesToAssignablePayload { - """ - The item that was assigned. - """ - assignable: Assignable - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of AddComment -""" -input AddCommentInput { - """ - The contents of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! -} - -""" -Autogenerated return type of AddComment -""" -type AddCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The edge from the subject's comment connection. - """ - commentEdge: IssueCommentEdge - - """ - The subject - """ - subject: Node - - """ - The edge from the subject's timeline connection. - """ - timelineEdge: IssueTimelineItemEdge -} - -""" -Autogenerated input type of AddLabelsToLabelable -""" -input AddLabelsToLabelableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ids of the labels to add. - """ - labelIds: [ID!]! - - """ - The id of the labelable object to add labels to. - """ - labelableId: ID! -} - -""" -Autogenerated return type of AddLabelsToLabelable -""" -type AddLabelsToLabelablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was labeled. - """ - labelable: Labelable -} - -""" -Autogenerated input type of AddProjectCard -""" -input AddProjectCardInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The content of the card. Must be a member of the ProjectCardItem union - """ - contentId: ID - - """ - The note on the card. - """ - note: String - - """ - The Node ID of the ProjectColumn. - """ - projectColumnId: ID! -} - -""" -Autogenerated return type of AddProjectCard -""" -type AddProjectCardPayload { - """ - The edge from the ProjectColumn's card connection. - """ - cardEdge: ProjectCardEdge - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ProjectColumn - """ - projectColumn: ProjectColumn -} - -""" -Autogenerated input type of AddProjectColumn -""" -input AddProjectColumnInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the column. - """ - name: String! - - """ - The Node ID of the project. - """ - projectId: ID! -} - -""" -Autogenerated return type of AddProjectColumn -""" -type AddProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The edge from the project's column connection. - """ - columnEdge: ProjectColumnEdge - - """ - The project - """ - project: Project -} - -""" -Autogenerated input type of AddPullRequestReviewComment -""" -input AddPullRequestReviewCommentInput { - """ - The text of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The SHA of the commit to comment on. - """ - commitOID: GitObjectID - - """ - The comment id to reply to. - """ - inReplyTo: ID - - """ - The relative path of the file to comment on. - """ - path: String - - """ - The line index in the diff to comment on. - """ - position: Int - - """ - The Node ID of the review to modify. - """ - pullRequestReviewId: ID! -} - -""" -Autogenerated return type of AddPullRequestReviewComment -""" -type AddPullRequestReviewCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created comment. - """ - comment: PullRequestReviewComment - - """ - The edge from the review's comment connection. - """ - commentEdge: PullRequestReviewCommentEdge -} - -""" -Autogenerated input type of AddPullRequestReview -""" -input AddPullRequestReviewInput { - """ - The contents of the review body comment. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The review line comments. - """ - comments: [DraftPullRequestReviewComment] - - """ - The commit OID the review pertains to. - """ - commitOID: GitObjectID - - """ - The event to perform on the pull request review. - """ - event: PullRequestReviewEvent - - """ - The Node ID of the pull request to modify. - """ - pullRequestId: ID! -} - -""" -Autogenerated return type of AddPullRequestReview -""" -type AddPullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created pull request review. - """ - pullRequestReview: PullRequestReview - - """ - The edge from the pull request's review connection. - """ - reviewEdge: PullRequestReviewEdge -} - -""" -Autogenerated input type of AddReaction -""" -input AddReactionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the emoji to react with. - """ - content: ReactionContent! - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! -} - -""" -Autogenerated return type of AddReaction -""" -type AddReactionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The reaction object. - """ - reaction: Reaction - - """ - The reactable subject. - """ - subject: Reactable -} - -""" -Autogenerated input type of AddStar -""" -input AddStarInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Starrable ID to star. - """ - starrableId: ID! -} - -""" -Autogenerated return type of AddStar -""" -type AddStarPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The starrable. - """ - starrable: Starrable -} - -""" -Represents a 'added_to_project' event on a given issue or pull request. -""" -type AddedToProjectEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -A GitHub App. -""" -type App implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The description of the app. - """ - description: String - id: ID! - - """ - The hex color code, without the leading '#', for the logo background. - """ - logoBackgroundColor: String! - - """ - A URL pointing to the app's logo. - """ - logoUrl( - """ - The size of the resulting image. - """ - size: Int - ): URI! - - """ - The name of the app. - """ - name: String! - - """ - A slug based on the name of the app for use in URLs. - """ - slug: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The URL to the app's homepage. - """ - url: URI! -} - -""" -An edge in a connection. -""" -type AppEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: App -} - -""" -An object that can have users assigned to it. -""" -interface Assignable { - """ - A list of Users assigned to this object. - """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! -} - -""" -Represents an 'assigned' event on any assignable object. -""" -type AssignedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the assignable associated with the event. - """ - assignable: Assignable! - - """ - Identifies the user or mannequin that was assigned. - """ - assignee: Assignee - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the user who was assigned. - """ - user: User @deprecated(reason: "Assignees can now be mannequins. Use the `assignee` field instead. Removal on 2020-01-01 UTC.") -} - -""" -Types that can be assigned to issues. -""" -union Assignee = Bot | Mannequin | Organization | User - -""" -An entry in the audit log. -""" -interface AuditEntry { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Types that can initiate an audit log event. -""" -union AuditEntryActor = Bot | Organization | User - -""" -Ordering options for Audit Log connections. -""" -input AuditLogOrder { - """ - The ordering direction. - """ - direction: OrderDirection - - """ - The field to order Audit Logs by. - """ - field: AuditLogOrderField -} - -""" -Properties by which Audit Log connections can be ordered. -""" -enum AuditLogOrderField { - """ - Order audit log entries by timestamp - """ - CREATED_AT -} - -""" -Represents a 'base_ref_changed' event on a given issue or pull request. -""" -type BaseRefChangedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Represents a 'base_ref_force_pushed' event on a given pull request. -""" -type BaseRefForcePushedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the after commit SHA for the 'base_ref_force_pushed' event. - """ - afterCommit: Commit - - """ - Identifies the before commit SHA for the 'base_ref_force_pushed' event. - """ - beforeCommit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the fully qualified ref name for the 'base_ref_force_pushed' event. - """ - ref: Ref -} - -""" -Represents a Git blame. -""" -type Blame { - """ - The list of ranges from a Git blame. - """ - ranges: [BlameRange!]! -} - -""" -Represents a range of information from a Git blame. -""" -type BlameRange { - """ - Identifies the recency of the change, from 1 (new) to 10 (old). This is - calculated as a 2-quantile and determines the length of distance between the - median age of all the changes in the file and the recency of the current - range's change. - """ - age: Int! - - """ - Identifies the line author - """ - commit: Commit! - - """ - The ending line for the range - """ - endingLine: Int! - - """ - The starting line for the range - """ - startingLine: Int! -} - -""" -Represents a Git blob. -""" -type Blob implements GitObject & Node { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - Byte size of Blob object - """ - byteSize: Int! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - id: ID! - - """ - Indicates whether the Blob is binary or text - """ - isBinary: Boolean! - - """ - Indicates whether the contents is truncated - """ - isTruncated: Boolean! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! - - """ - UTF8 text data or null if the Blob is binary - """ - text: String -} - -""" -A special type of user which takes actions on behalf of GitHub Apps. -""" -type Bot implements Actor & Node & UniformResourceLocatable { - """ - A URL pointing to the GitHub App's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The username of the actor. - """ - login: String! - - """ - The HTTP path for this bot - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this bot - """ - url: URI! -} - -""" -A branch protection rule. -""" -type BranchProtectionRule implements Node { - """ - A list of conflicts matching branches protection rule and other branch protection rules - """ - branchProtectionRuleConflicts( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): BranchProtectionRuleConflictConnection! - - """ - The actor who created this branch protection rule. - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - Will new commits pushed to matching branches dismiss pull request review approvals. - """ - dismissesStaleReviews: Boolean! - id: ID! - - """ - Can admins overwrite branch protection. - """ - isAdminEnforced: Boolean! - - """ - Repository refs that are protected by this rule - """ - matchingRefs( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RefConnection! - - """ - Identifies the protection rule pattern. - """ - pattern: String! - - """ - A list push allowances for this branch protection rule. - """ - pushAllowances( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PushAllowanceConnection! - - """ - The repository associated with this branch protection rule. - """ - repository: Repository - - """ - Number of approving reviews required to update matching branches. - """ - requiredApprovingReviewCount: Int - - """ - List of required status check contexts that must pass for commits to be accepted to matching branches. - """ - requiredStatusCheckContexts: [String] - - """ - Are approving reviews required to update matching branches. - """ - requiresApprovingReviews: Boolean! - - """ - Are reviews from code owners required to update matching branches. - """ - requiresCodeOwnerReviews: Boolean! - - """ - Are commits required to be signed. - """ - requiresCommitSignatures: Boolean! - - """ - Are status checks required to update matching branches. - """ - requiresStatusChecks: Boolean! - - """ - Are branches required to be up to date before merging. - """ - requiresStrictStatusChecks: Boolean! - - """ - Is pushing to matching branches restricted. - """ - restrictsPushes: Boolean! - - """ - Is dismissal of pull request reviews restricted. - """ - restrictsReviewDismissals: Boolean! - - """ - A list review dismissal allowances for this branch protection rule. - """ - reviewDismissalAllowances( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ReviewDismissalAllowanceConnection! -} - -""" -A conflict between two branch protection rules. -""" -type BranchProtectionRuleConflict { - """ - Identifies the branch protection rule. - """ - branchProtectionRule: BranchProtectionRule - - """ - Identifies the conflicting branch protection rule. - """ - conflictingBranchProtectionRule: BranchProtectionRule - - """ - Identifies the branch ref that has conflicting rules - """ - ref: Ref -} - -""" -The connection type for BranchProtectionRuleConflict. -""" -type BranchProtectionRuleConflictConnection { - """ - A list of edges. - """ - edges: [BranchProtectionRuleConflictEdge] - - """ - A list of nodes. - """ - nodes: [BranchProtectionRuleConflict] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type BranchProtectionRuleConflictEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: BranchProtectionRuleConflict -} - -""" -The connection type for BranchProtectionRule. -""" -type BranchProtectionRuleConnection { - """ - A list of edges. - """ - edges: [BranchProtectionRuleEdge] - - """ - A list of nodes. - """ - nodes: [BranchProtectionRule] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type BranchProtectionRuleEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: BranchProtectionRule -} - -""" -Autogenerated input type of CancelEnterpriseAdminInvitation -""" -input CancelEnterpriseAdminInvitationInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pending enterprise administrator invitation. - """ - invitationId: ID! -} - -""" -Autogenerated input type of ChangeUserStatus -""" -input ChangeUserStatusInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The emoji to represent your status. Can either be a native Unicode emoji or an emoji name with colons, e.g., :grinning:. - """ - emoji: String - - """ - If set, the user status will not be shown after this date. - """ - expiresAt: DateTime - - """ - Whether this status should indicate you are not fully available on GitHub, e.g., you are away. - """ - limitedAvailability: Boolean = false - - """ - A short description of your current status. - """ - message: String - - """ - The ID of the organization whose members will be allowed to see the status. If - omitted, the status will be publicly visible. - """ - organizationId: ID -} - -""" -Autogenerated return type of ChangeUserStatus -""" -type ChangeUserStatusPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Your updated status. - """ - status: UserStatus -} - -""" -Autogenerated input type of ClearLabelsFromLabelable -""" -input ClearLabelsFromLabelableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the labelable object to clear the labels from. - """ - labelableId: ID! -} - -""" -Autogenerated return type of ClearLabelsFromLabelable -""" -type ClearLabelsFromLabelablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was unlabeled. - """ - labelable: Labelable -} - -""" -Autogenerated input type of CloneProject -""" -input CloneProjectInput { - """ - The description of the project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Whether or not to clone the source project's workflows. - """ - includeWorkflows: Boolean! - - """ - The name of the project. - """ - name: String! - - """ - The visibility of the project, defaults to false (private). - """ - public: Boolean - - """ - The source project to clone. - """ - sourceId: ID! - - """ - The owner ID to create the project under. - """ - targetOwnerId: ID! -} - -""" -Autogenerated return type of CloneProject -""" -type CloneProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the JobStatus for populating cloned fields. - """ - jobStatusId: String - - """ - The new cloned project. - """ - project: Project -} - -""" -Autogenerated input type of CloneTemplateRepository -""" -input CloneTemplateRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A short description of the new repository. - """ - description: String - - """ - The name of the new repository. - """ - name: String! - - """ - The ID of the owner for the new repository. - """ - ownerId: ID! - - """ - The Node ID of the template repository. - """ - repositoryId: ID! - - """ - Indicates the repository's visibility level. - """ - visibility: RepositoryVisibility! -} - -""" -Autogenerated return type of CloneTemplateRepository -""" -type CloneTemplateRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new repository. - """ - repository: Repository -} - -""" -An object that can be closed -""" -interface Closable { - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime -} - -""" -Autogenerated input type of CloseIssue -""" -input CloseIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue to be closed. - """ - issueId: ID! -} - -""" -Autogenerated return type of CloseIssue -""" -type CloseIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was closed. - """ - issue: Issue -} - -""" -Autogenerated input type of ClosePullRequest -""" -input ClosePullRequestInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the pull request to be closed. - """ - pullRequestId: ID! -} - -""" -Autogenerated return type of ClosePullRequest -""" -type ClosePullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that was closed. - """ - pullRequest: PullRequest -} - -""" -Represents a 'closed' event on any `Closable`. -""" -type ClosedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Object that was closed. - """ - closable: Closable! - - """ - Object which triggered the creation of this event. - """ - closer: Closer - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The HTTP path for this closed event. - """ - resourcePath: URI! - - """ - The HTTP URL for this closed event. - """ - url: URI! -} - -""" -The object which triggered a `ClosedEvent`. -""" -union Closer = Commit | PullRequest - -""" -The Code of Conduct for a repository -""" -type CodeOfConduct implements Node { - """ - The body of the Code of Conduct - """ - body: String - id: ID! - - """ - The key for the Code of Conduct - """ - key: String! - - """ - The formal name of the Code of Conduct - """ - name: String! - - """ - The HTTP path for this Code of Conduct - """ - resourcePath: URI - - """ - The HTTP URL for this Code of Conduct - """ - url: URI -} - -""" -Collaborators affiliation level with a subject. -""" -enum CollaboratorAffiliation { - """ - All collaborators the authenticated user can see. - """ - ALL - - """ - All collaborators with permissions to an organization-owned subject, regardless of organization membership status. - """ - DIRECT - - """ - All outside collaborators of an organization-owned subject. - """ - OUTSIDE -} - -""" -Types that can be inside Collection Items. -""" -union CollectionItemContent = Organization | Repository | User - -""" -Represents a comment. -""" -interface Comment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -A comment author association with repository. -""" -enum CommentAuthorAssociation { - """ - Author has been invited to collaborate on the repository. - """ - COLLABORATOR - - """ - Author has previously committed to the repository. - """ - CONTRIBUTOR - - """ - Author has not previously committed to GitHub. - """ - FIRST_TIMER - - """ - Author has not previously committed to the repository. - """ - FIRST_TIME_CONTRIBUTOR - - """ - Author is a member of the organization that owns the repository. - """ - MEMBER - - """ - Author has no association with the repository. - """ - NONE - - """ - Author is the owner of the repository. - """ - OWNER -} - -""" -The possible errors that will prevent a user from updating a comment. -""" -enum CommentCannotUpdateReason { - """ - Unable to create comment because repository is archived. - """ - ARCHIVED - - """ - You cannot update this comment - """ - DENIED - - """ - You must be the author or have write access to this repository to update this comment. - """ - INSUFFICIENT_ACCESS - - """ - Unable to create comment because issue is locked. - """ - LOCKED - - """ - You must be logged in to update this comment. - """ - LOGIN_REQUIRED - - """ - Repository is under maintenance. - """ - MAINTENANCE - - """ - At least one email address must be verified to update this comment. - """ - VERIFIED_EMAIL_REQUIRED -} - -""" -Represents a 'comment_deleted' event on a given issue or pull request. -""" -type CommentDeletedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Represents a Git commit. -""" -type Commit implements GitObject & Node & Subscribable & UniformResourceLocatable { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The number of additions in this commit. - """ - additions: Int! - - """ - The pull requests associated with a commit - """ - associatedPullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests. - """ - orderBy: PullRequestOrder = {field: CREATED_AT, direction: ASC} - ): PullRequestConnection - - """ - Authorship details of the commit. - """ - author: GitActor - - """ - Check if the committer and the author match. - """ - authoredByCommitter: Boolean! - - """ - The datetime when this commit was authored. - """ - authoredDate: DateTime! - - """ - Fetches `git blame` information. - """ - blame( - """ - The file whose Git blame information you want. - """ - path: String! - ): Blame! - - """ - The number of changed files in this commit. - """ - changedFiles: Int! - - """ - Comments made on the commit. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - - """ - The datetime when this commit was committed. - """ - committedDate: DateTime! - - """ - Check if commited via GitHub web UI. - """ - committedViaWeb: Boolean! - - """ - Committership details of the commit. - """ - committer: GitActor - - """ - The number of deletions in this commit. - """ - deletions: Int! - - """ - The deployments associated with a commit. - """ - deployments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Environments to list deployments for - """ - environments: [String!] - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for deployments returned from the connection. - """ - orderBy: DeploymentOrder = {field: CREATED_AT, direction: ASC} - ): DeploymentConnection - - """ - The linear commit history starting from (and including) this commit, in the same order as `git log`. - """ - history( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - If non-null, filters history to only show commits with matching authorship. - """ - author: CommitAuthor - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - If non-null, filters history to only show commits touching files under this path. - """ - path: String - - """ - Allows specifying a beginning time or date for fetching commits. - """ - since: GitTimestamp - - """ - Allows specifying an ending time or date for fetching commits. - """ - until: GitTimestamp - ): CommitHistoryConnection! - id: ID! - - """ - The Git commit message - """ - message: String! - - """ - The Git commit message body - """ - messageBody: String! - - """ - The commit message body rendered to HTML. - """ - messageBodyHTML: HTML! - - """ - The Git commit message headline - """ - messageHeadline: String! - - """ - The commit message headline rendered to HTML. - """ - messageHeadlineHTML: HTML! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The parents of a commit. - """ - parents( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitConnection! - - """ - The datetime when this commit was pushed. - """ - pushedDate: DateTime - - """ - The Repository this commit belongs to - """ - repository: Repository! - - """ - The HTTP path for this commit - """ - resourcePath: URI! - - """ - Commit signing information, if present. - """ - signature: GitSignature - - """ - Status information for this commit - """ - status: Status - - """ - Returns a URL to download a tarball archive for a repository. - Note: For private repositories, these links are temporary and expire after five minutes. - """ - tarballUrl: URI! - - """ - Commit's root Tree - """ - tree: Tree! - - """ - The HTTP path for the tree of this commit - """ - treeResourcePath: URI! - - """ - The HTTP URL for the tree of this commit - """ - treeUrl: URI! - - """ - The HTTP URL for this commit - """ - url: URI! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState - - """ - Returns a URL to download a zipball archive for a repository. - Note: For private repositories, these links are temporary and expire after five minutes. - """ - zipballUrl: URI! -} - -""" -Specifies an author for filtering Git commits. -""" -input CommitAuthor { - """ - Email addresses to filter by. Commits authored by any of the specified email addresses will be returned. - """ - emails: [String!] - - """ - ID of a User to filter by. If non-null, only commits authored by this user - will be returned. This field takes precedence over emails. - """ - id: ID -} - -""" -Represents a comment on a given Commit. -""" -type CommitComment implements Comment & Deletable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the comment body. - """ - body: String! - - """ - Identifies the comment body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the commit associated with the comment, if the commit exists. - """ - commit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies the file path associated with the comment. - """ - path: String - - """ - Identifies the line position associated with the comment. - """ - position: Int - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path permalink for this commit comment. - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL permalink for this commit comment. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for CommitComment. -""" -type CommitCommentConnection { - """ - A list of edges. - """ - edges: [CommitCommentEdge] - - """ - A list of nodes. - """ - nodes: [CommitComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CommitCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CommitComment -} - -""" -A thread of comments on a commit. -""" -type CommitCommentThread implements Node & RepositoryNode { - """ - The comments that exist in this thread. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The commit the comments were made on. - """ - commit: Commit! - id: ID! - - """ - The file the comments were made on. - """ - path: String - - """ - The position in the diff for the commit that the comment was made on. - """ - position: Int - - """ - The repository associated with this node. - """ - repository: Repository! -} - -""" -The connection type for Commit. -""" -type CommitConnection { - """ - A list of edges. - """ - edges: [CommitEdge] - - """ - A list of nodes. - """ - nodes: [Commit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Ordering options for commit contribution connections. -""" -input CommitContributionOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field by which to order commit contributions. - """ - field: CommitContributionOrderField! -} - -""" -Properties by which commit contribution connections can be ordered. -""" -enum CommitContributionOrderField { - """ - Order commit contributions by how many commits they represent. - """ - COMMIT_COUNT - - """ - Order commit contributions by when they were made. - """ - OCCURRED_AT -} - -""" -This aggregates commits made by a user within one repository. -""" -type CommitContributionsByRepository { - """ - The commit contributions, each representing a day. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for commit contributions returned from the connection. - """ - orderBy: CommitContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedCommitContributionConnection! - - """ - The repository in which the commits were made. - """ - repository: Repository! - - """ - The HTTP path for the user's commits to the repository in this time range. - """ - resourcePath: URI! - - """ - The HTTP URL for the user's commits to the repository in this time range. - """ - url: URI! -} - -""" -An edge in a connection. -""" -type CommitEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Commit -} - -""" -The connection type for Commit. -""" -type CommitHistoryConnection { - """ - A list of edges. - """ - edges: [CommitEdge] - - """ - A list of nodes. - """ - nodes: [Commit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A content attachment -""" -type ContentAttachment { - """ - The body text of the content attachment. This parameter supports markdown. - """ - body: String! - - """ - The content reference that the content attachment is attached to. - """ - contentReference: ContentReference! - - """ - Identifies the primary key from the database. - """ - databaseId: Int! - id: ID! - - """ - The title of the content attachment. - """ - title: String! -} - -""" -A content reference -""" -type ContentReference { - """ - Identifies the primary key from the database. - """ - databaseId: Int! - id: ID! - - """ - The reference of the content reference. - """ - reference: String! -} - -""" -Represents a contribution a user made on GitHub, such as opening an issue. -""" -interface Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -A calendar of contributions made on GitHub by a user. -""" -type ContributionCalendar { - """ - A list of hex color codes used in this calendar. The darker the color, the more contributions it represents. - """ - colors: [String!]! - - """ - Determine if the color set was chosen because it's currently Halloween. - """ - isHalloween: Boolean! - - """ - A list of the months of contributions in this calendar. - """ - months: [ContributionCalendarMonth!]! - - """ - The count of total contributions in the calendar. - """ - totalContributions: Int! - - """ - A list of the weeks of contributions in this calendar. - """ - weeks: [ContributionCalendarWeek!]! -} - -""" -Represents a single day of contributions on GitHub by a user. -""" -type ContributionCalendarDay { - """ - The hex color code that represents how many contributions were made on this day compared to others in the calendar. - """ - color: String! - - """ - How many contributions were made by the user on this day. - """ - contributionCount: Int! - - """ - The day this square represents. - """ - date: Date! - - """ - A number representing which day of the week this square represents, e.g., 1 is Monday. - """ - weekday: Int! -} - -""" -A month of contributions in a user's contribution graph. -""" -type ContributionCalendarMonth { - """ - The date of the first day of this month. - """ - firstDay: Date! - - """ - The name of the month. - """ - name: String! - - """ - How many weeks started in this month. - """ - totalWeeks: Int! - - """ - The year the month occurred in. - """ - year: Int! -} - -""" -A week of contributions in a user's contribution graph. -""" -type ContributionCalendarWeek { - """ - The days of contributions in this week. - """ - contributionDays: [ContributionCalendarDay!]! - - """ - The date of the earliest square in this week. - """ - firstDay: Date! -} - -""" -Ordering options for contribution connections. -""" -input ContributionOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field by which to order contributions. - - **Upcoming Change on 2019-10-01 UTC** - **Description:** `field` will be removed. Only one order field is supported. - **Reason:** `field` will be removed. - """ - field: ContributionOrderField -} - -""" -Properties by which contribution connections can be ordered. -""" -enum ContributionOrderField { - """ - Order contributions by when they were made. - """ - OCCURRED_AT -} - -""" -A contributions collection aggregates contributions such as opened issues and commits created by a user. -""" -type ContributionsCollection { - """ - Commit contributions made by the user, grouped by repository. - """ - commitContributionsByRepository( - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [CommitContributionsByRepository!]! - - """ - A calendar of this user's contributions on GitHub. - """ - contributionCalendar: ContributionCalendar! - - """ - The years the user has been making contributions with the most recent year first. - """ - contributionYears: [Int!]! - - """ - Determine if this collection's time span ends in the current month. - """ - doesEndInCurrentMonth: Boolean! - - """ - The date of the first restricted contribution the user made in this time - period. Can only be non-null when the user has enabled private contribution counts. - """ - earliestRestrictedContributionDate: Date - - """ - The ending date and time of this collection. - """ - endedAt: DateTime! - - """ - The first issue the user opened on GitHub. This will be null if that issue was - opened outside the collection's time range and ignoreTimeRange is false. If - the issue is not visible but the user has opted to show private contributions, - a RestrictedContribution will be returned. - """ - firstIssueContribution: CreatedIssueOrRestrictedContribution - - """ - The first pull request the user opened on GitHub. This will be null if that - pull request was opened outside the collection's time range and - ignoreTimeRange is not true. If the pull request is not visible but the user - has opted to show private contributions, a RestrictedContribution will be returned. - """ - firstPullRequestContribution: CreatedPullRequestOrRestrictedContribution - - """ - The first repository the user created on GitHub. This will be null if that - first repository was created outside the collection's time range and - ignoreTimeRange is false. If the repository is not visible, then a - RestrictedContribution is returned. - """ - firstRepositoryContribution: CreatedRepositoryOrRestrictedContribution - - """ - Does the user have any more activity in the timeline that occurred prior to the collection's time range? - """ - hasActivityInThePast: Boolean! - - """ - Determine if there are any contributions in this collection. - """ - hasAnyContributions: Boolean! - - """ - Determine if the user made any contributions in this time frame whose details - are not visible because they were made in a private repository. Can only be - true if the user enabled private contribution counts. - """ - hasAnyRestrictedContributions: Boolean! - - """ - Whether or not the collector's time span is all within the same day. - """ - isSingleDay: Boolean! - - """ - A list of issues the user opened. - """ - issueContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Should the user's first issue ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from the result. - """ - excludePopular: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedIssueContributionConnection! - - """ - Issue contributions made by the user, grouped by repository. - """ - issueContributionsByRepository( - """ - Should the user's first issue ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from the result. - """ - excludePopular: Boolean = false - - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [IssueContributionsByRepository!]! - - """ - When the user signed up for GitHub. This will be null if that sign up date - falls outside the collection's time range and ignoreTimeRange is false. - """ - joinedGitHubContribution: JoinedGitHubContribution - - """ - The date of the most recent restricted contribution the user made in this time - period. Can only be non-null when the user has enabled private contribution counts. - """ - latestRestrictedContributionDate: Date - - """ - When this collection's time range does not include any activity from the user, use this - to get a different collection from an earlier time range that does have activity. - """ - mostRecentCollectionWithActivity: ContributionsCollection - - """ - Returns a different contributions collection from an earlier time range than this one - that does not have any contributions. - """ - mostRecentCollectionWithoutActivity: ContributionsCollection - - """ - The issue the user opened on GitHub that received the most comments in the specified - time frame. - """ - popularIssueContribution: CreatedIssueContribution - - """ - The pull request the user opened on GitHub that received the most comments in the - specified time frame. - """ - popularPullRequestContribution: CreatedPullRequestContribution - - """ - Pull request contributions made by the user. - """ - pullRequestContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Should the user's first pull request ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from the result. - """ - excludePopular: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedPullRequestContributionConnection! - - """ - Pull request contributions made by the user, grouped by repository. - """ - pullRequestContributionsByRepository( - """ - Should the user's first pull request ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from the result. - """ - excludePopular: Boolean = false - - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [PullRequestContributionsByRepository!]! - - """ - Pull request review contributions made by the user. - """ - pullRequestReviewContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedPullRequestReviewContributionConnection! - - """ - Pull request review contributions made by the user, grouped by repository. - """ - pullRequestReviewContributionsByRepository( - """ - How many repositories should be included. - """ - maxRepositories: Int = 25 - ): [PullRequestReviewContributionsByRepository!]! - - """ - A list of repositories owned by the user that the user created in this time range. - """ - repositoryContributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Should the user's first repository ever be excluded from the result. - """ - excludeFirst: Boolean = false - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedRepositoryContributionConnection! - - """ - A count of contributions made by the user that the viewer cannot access. Only - non-zero when the user has chosen to share their private contribution counts. - """ - restrictedContributionsCount: Int! - - """ - The beginning date and time of this collection. - """ - startedAt: DateTime! - - """ - How many commits were made by the user in this time span. - """ - totalCommitContributions: Int! - - """ - How many issues the user opened. - """ - totalIssueContributions( - """ - Should the user's first issue ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many pull requests the user opened. - """ - totalPullRequestContributions( - """ - Should the user's first pull request ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many pull request reviews the user left. - """ - totalPullRequestReviewContributions: Int! - - """ - How many different repositories the user committed to. - """ - totalRepositoriesWithContributedCommits: Int! - - """ - How many different repositories the user opened issues in. - """ - totalRepositoriesWithContributedIssues( - """ - Should the user's first issue ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented issue be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many different repositories the user left pull request reviews in. - """ - totalRepositoriesWithContributedPullRequestReviews: Int! - - """ - How many different repositories the user opened pull requests in. - """ - totalRepositoriesWithContributedPullRequests( - """ - Should the user's first pull request ever be excluded from this count. - """ - excludeFirst: Boolean = false - - """ - Should the user's most commented pull request be excluded from this count. - """ - excludePopular: Boolean = false - ): Int! - - """ - How many repositories the user created. - """ - totalRepositoryContributions( - """ - Should the user's first repository ever be excluded from this count. - """ - excludeFirst: Boolean = false - ): Int! - - """ - The user who made the contributions in this collection. - """ - user: User! -} - -""" -Autogenerated input type of ConvertProjectCardNoteToIssue -""" -input ConvertProjectCardNoteToIssueInput { - """ - The body of the newly created issue. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ProjectCard ID to convert. - """ - projectCardId: ID! - - """ - The ID of the repository to create the issue in. - """ - repositoryId: ID! - - """ - The title of the newly created issue. Defaults to the card's note text. - """ - title: String -} - -""" -Autogenerated return type of ConvertProjectCardNoteToIssue -""" -type ConvertProjectCardNoteToIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated ProjectCard. - """ - projectCard: ProjectCard -} - -""" -Represents a 'converted_note_to_issue' event on a given issue or pull request. -""" -type ConvertedNoteToIssueEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Autogenerated input type of CreateBranchProtectionRule -""" -input CreateBranchProtectionRuleInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Will new commits pushed to matching branches dismiss pull request review approvals. - """ - dismissesStaleReviews: Boolean - - """ - Can admins overwrite branch protection. - """ - isAdminEnforced: Boolean - - """ - The glob-like pattern used to determine matching branches. - """ - pattern: String! - - """ - A list of User, Team or App IDs allowed to push to matching branches. - """ - pushActorIds: [ID!] - - """ - The global relay id of the repository in which a new branch protection rule should be created in. - """ - repositoryId: ID! - - """ - Number of approving reviews required to update matching branches. - """ - requiredApprovingReviewCount: Int - - """ - List of required status check contexts that must pass for commits to be accepted to matching branches. - """ - requiredStatusCheckContexts: [String!] - - """ - Are approving reviews required to update matching branches. - """ - requiresApprovingReviews: Boolean - - """ - Are reviews from code owners required to update matching branches. - """ - requiresCodeOwnerReviews: Boolean - - """ - Are commits required to be signed. - """ - requiresCommitSignatures: Boolean - - """ - Are status checks required to update matching branches. - """ - requiresStatusChecks: Boolean - - """ - Are branches required to be up to date before merging. - """ - requiresStrictStatusChecks: Boolean - - """ - Is pushing to matching branches restricted. - """ - restrictsPushes: Boolean - - """ - Is dismissal of pull request reviews restricted. - """ - restrictsReviewDismissals: Boolean - - """ - A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. - """ - reviewDismissalActorIds: [ID!] -} - -""" -Autogenerated return type of CreateBranchProtectionRule -""" -type CreateBranchProtectionRulePayload { - """ - The newly created BranchProtectionRule. - """ - branchProtectionRule: BranchProtectionRule - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of CreateContentAttachment -""" -input CreateContentAttachmentInput { - """ - The body of the content attachment, which may contain markdown. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The node ID of the content_reference. - """ - contentReferenceId: ID! - - """ - The title of the content attachment. - """ - title: String! -} - -""" -Autogenerated input type of CreateEnterpriseOrganization -""" -input CreateEnterpriseOrganizationInput { - """ - The logins for the administrators of the new organization. - """ - adminLogins: [String!]! - - """ - The email used for sending billing receipts. - """ - billingEmail: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise owning the new organization. - """ - enterpriseId: ID! - - """ - The login of the new organization. - """ - login: String! - - """ - The profile name of the new organization. - """ - profileName: String! -} - -""" -Autogenerated input type of CreateIssue -""" -input CreateIssueInput { - """ - The Node ID for the user assignee for this issue. - """ - assigneeIds: [ID!] - - """ - The body for the issue description. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - An array of Node IDs of labels for this issue. - """ - labelIds: [ID!] - - """ - The Node ID of the milestone for this issue. - """ - milestoneId: ID - - """ - An array of Node IDs for projects associated with this issue. - """ - projectIds: [ID!] - - """ - The Node ID of the repository. - """ - repositoryId: ID! - - """ - The title for the issue. - """ - title: String! -} - -""" -Autogenerated return type of CreateIssue -""" -type CreateIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new issue. - """ - issue: Issue -} - -""" -Autogenerated input type of CreateProject -""" -input CreateProjectInput { - """ - The description of project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of project. - """ - name: String! - - """ - The owner ID to create the project under. - """ - ownerId: ID! - - """ - A list of repository IDs to create as linked repositories for the project - """ - repositoryIds: [ID!] - - """ - The name of the GitHub-provided template. - """ - template: ProjectTemplate -} - -""" -Autogenerated return type of CreateProject -""" -type CreateProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new project. - """ - project: Project -} - -""" -Autogenerated input type of CreatePullRequest -""" -input CreatePullRequestInput { - """ - The name of the branch you want your changes pulled into. This should be an existing branch - on the current repository. You cannot update the base branch on a pull request to point - to another repository. - """ - baseRefName: String! - - """ - The contents of the pull request. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the branch where your changes are implemented. For cross-repository pull requests - in the same network, namespace `head_ref_name` with a user like this: `username:branch`. - """ - headRefName: String! - - """ - Indicates whether maintainers can modify the pull request. - """ - maintainerCanModify: Boolean = true - - """ - The Node ID of the repository. - """ - repositoryId: ID! - - """ - The title of the pull request. - """ - title: String! -} - -""" -Autogenerated return type of CreatePullRequest -""" -type CreatePullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new pull request. - """ - pullRequest: PullRequest -} - -""" -Autogenerated input type of CreateRef -""" -input CreateRefInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The fully qualified name of the new Ref (ie: `refs/heads/my_new_branch`). - """ - name: String! - - """ - The GitObjectID that the new Ref shall target. Must point to a commit. - """ - oid: GitObjectID! - - """ - The Node ID of the Repository to create the Ref in. - """ - repositoryId: ID! -} - -""" -Autogenerated return type of CreateRef -""" -type CreateRefPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The newly created ref. - """ - ref: Ref -} - -""" -Autogenerated input type of CreateRepository -""" -input CreateRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A short description of the new repository. - """ - description: String - - """ - Indicates if the repository should have the issues feature enabled. - """ - hasIssuesEnabled: Boolean = true - - """ - Indicates if the repository should have the wiki feature enabled. - """ - hasWikiEnabled: Boolean = false - - """ - The URL for a web page about this repository. - """ - homepageUrl: URI - - """ - The name of the new repository. - """ - name: String! - - """ - The ID of the owner for the new repository. - """ - ownerId: ID - - """ - When an organization is specified as the owner, this ID identifies the team - that should be granted access to the new repository. - """ - teamId: ID - - """ - Whether this repository should be marked as a template such that anyone who - can access it can create new repositories with the same files and directory structure. - """ - template: Boolean = false - - """ - Indicates the repository's visibility level. - """ - visibility: RepositoryVisibility! -} - -""" -Autogenerated return type of CreateRepository -""" -type CreateRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new repository. - """ - repository: Repository -} - -""" -Represents the contribution a user made by committing to a repository. -""" -type CreatedCommitContribution implements Contribution { - """ - How many commits were made on this day to this repository by the user. - """ - commitCount: Int! - - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The repository the user made a commit in. - """ - repository: Repository! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedCommitContribution. -""" -type CreatedCommitContributionConnection { - """ - A list of edges. - """ - edges: [CreatedCommitContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedCommitContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of commits across days and repositories in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedCommitContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedCommitContribution -} - -""" -Represents the contribution a user made on GitHub by opening an issue. -""" -type CreatedIssueContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - The issue that was opened. - """ - issue: Issue! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedIssueContribution. -""" -type CreatedIssueContributionConnection { - """ - A list of edges. - """ - edges: [CreatedIssueContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedIssueContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedIssueContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedIssueContribution -} - -""" -Represents either a issue the viewer can access or a restricted contribution. -""" -union CreatedIssueOrRestrictedContribution = CreatedIssueContribution | RestrictedContribution - -""" -Represents the contribution a user made on GitHub by opening a pull request. -""" -type CreatedPullRequestContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The pull request that was opened. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedPullRequestContribution. -""" -type CreatedPullRequestContributionConnection { - """ - A list of edges. - """ - edges: [CreatedPullRequestContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedPullRequestContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedPullRequestContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedPullRequestContribution -} - -""" -Represents either a pull request the viewer can access or a restricted contribution. -""" -union CreatedPullRequestOrRestrictedContribution = CreatedPullRequestContribution | RestrictedContribution - -""" -Represents the contribution a user made by leaving a review on a pull request. -""" -type CreatedPullRequestReviewContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The pull request the user reviewed. - """ - pullRequest: PullRequest! - - """ - The review the user left on the pull request. - """ - pullRequestReview: PullRequestReview! - - """ - The repository containing the pull request that the user reviewed. - """ - repository: Repository! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedPullRequestReviewContribution. -""" -type CreatedPullRequestReviewContributionConnection { - """ - A list of edges. - """ - edges: [CreatedPullRequestReviewContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedPullRequestReviewContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedPullRequestReviewContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedPullRequestReviewContribution -} - -""" -Represents the contribution a user made on GitHub by creating a repository. -""" -type CreatedRepositoryContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The repository that was created. - """ - repository: Repository! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -The connection type for CreatedRepositoryContribution. -""" -type CreatedRepositoryContributionConnection { - """ - A list of edges. - """ - edges: [CreatedRepositoryContributionEdge] - - """ - A list of nodes. - """ - nodes: [CreatedRepositoryContribution] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type CreatedRepositoryContributionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: CreatedRepositoryContribution -} - -""" -Represents either a repository the viewer can access or a restricted contribution. -""" -union CreatedRepositoryOrRestrictedContribution = CreatedRepositoryContribution | RestrictedContribution - -""" -Represents a mention made by one issue or pull request to another. -""" -type CrossReferencedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reference originated in a different repository. - """ - isCrossRepository: Boolean! - - """ - Identifies when the reference was made. - """ - referencedAt: DateTime! - - """ - The HTTP path for this pull request. - """ - resourcePath: URI! - - """ - Issue or pull request that made the reference. - """ - source: ReferencedSubject! - - """ - Issue or pull request to which the reference was made. - """ - target: ReferencedSubject! - - """ - The HTTP URL for this pull request. - """ - url: URI! - - """ - Checks if the target will be closed when the source is merged. - """ - willCloseTarget: Boolean! -} - -""" -An ISO-8601 encoded date string. -""" -scalar Date - -""" -An ISO-8601 encoded UTC date string. -""" -scalar DateTime - -""" -Autogenerated input type of DeclineTopicSuggestion -""" -input DeclineTopicSuggestionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the suggested topic. - """ - name: String! - - """ - The reason why the suggested topic is declined. - """ - reason: TopicSuggestionDeclineReason! - - """ - The Node ID of the repository. - """ - repositoryId: ID! -} - -""" -Autogenerated return type of DeclineTopicSuggestion -""" -type DeclineTopicSuggestionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The declined topic. - """ - topic: Topic -} - -""" -The possible default permissions for repositories. -""" -enum DefaultRepositoryPermissionField { - """ - Can read, write, and administrate repos by default - """ - ADMIN - - """ - No access - """ - NONE - - """ - Can read repos by default - """ - READ - - """ - Can read and write repos by default - """ - WRITE -} - -""" -Entities that can be deleted. -""" -interface Deletable { - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! -} - -""" -Autogenerated input type of DeleteBranchProtectionRule -""" -input DeleteBranchProtectionRuleInput { - """ - The global relay id of the branch protection rule to be deleted. - """ - branchProtectionRuleId: ID! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of DeleteBranchProtectionRule -""" -type DeleteBranchProtectionRulePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteIssueComment -""" -input DeleteIssueCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the comment to delete. - """ - id: ID! -} - -""" -Autogenerated return type of DeleteIssueComment -""" -type DeleteIssueCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of DeleteIssue -""" -input DeleteIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the issue to delete. - """ - issueId: ID! -} - -""" -Autogenerated return type of DeleteIssue -""" -type DeleteIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The repository the issue belonged to - """ - repository: Repository -} - -""" -Autogenerated input type of DeleteProjectCard -""" -input DeleteProjectCardInput { - """ - The id of the card to delete. - """ - cardId: ID! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of DeleteProjectCard -""" -type DeleteProjectCardPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The column the deleted card was in. - """ - column: ProjectColumn - - """ - The deleted card ID. - """ - deletedCardId: ID -} - -""" -Autogenerated input type of DeleteProjectColumn -""" -input DeleteProjectColumnInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the column to delete. - """ - columnId: ID! -} - -""" -Autogenerated return type of DeleteProjectColumn -""" -type DeleteProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The deleted column ID. - """ - deletedColumnId: ID - - """ - The project the deleted column was in. - """ - project: Project -} - -""" -Autogenerated input type of DeleteProject -""" -input DeleteProjectInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Project ID to update. - """ - projectId: ID! -} - -""" -Autogenerated return type of DeleteProject -""" -type DeleteProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The repository or organization the project was removed from. - """ - owner: ProjectOwner -} - -""" -Autogenerated input type of DeletePullRequestReviewComment -""" -input DeletePullRequestReviewCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the comment to delete. - """ - id: ID! -} - -""" -Autogenerated return type of DeletePullRequestReviewComment -""" -type DeletePullRequestReviewCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request review the deleted comment belonged to. - """ - pullRequestReview: PullRequestReview -} - -""" -Autogenerated input type of DeletePullRequestReview -""" -input DeletePullRequestReviewInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pull request review to delete. - """ - pullRequestReviewId: ID! -} - -""" -Autogenerated return type of DeletePullRequestReview -""" -type DeletePullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The deleted pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Autogenerated input type of DeleteRef -""" -input DeleteRefInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the Ref to be deleted. - """ - refId: ID! -} - -""" -Autogenerated return type of DeleteRef -""" -type DeleteRefPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Represents a 'demilestoned' event on a given issue or pull request. -""" -type DemilestonedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the milestone title associated with the 'demilestoned' event. - """ - milestoneTitle: String! - - """ - Object referenced by event. - """ - subject: MilestoneItem! -} - -""" -A repository deploy key. -""" -type DeployKey implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The deploy key. - """ - key: String! - - """ - Whether or not the deploy key is read only. - """ - readOnly: Boolean! - - """ - The deploy key title. - """ - title: String! - - """ - Whether or not the deploy key has been verified. - """ - verified: Boolean! -} - -""" -The connection type for DeployKey. -""" -type DeployKeyConnection { - """ - A list of edges. - """ - edges: [DeployKeyEdge] - - """ - A list of nodes. - """ - nodes: [DeployKey] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DeployKeyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: DeployKey -} - -""" -Represents a 'deployed' event on a given pull request. -""" -type DeployedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The deployment associated with the 'deployed' event. - """ - deployment: Deployment! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The ref associated with the 'deployed' event. - """ - ref: Ref -} - -""" -Represents triggered deployment instance. -""" -type Deployment implements Node { - """ - Identifies the commit sha of the deployment. - """ - commit: Commit - - """ - Identifies the oid of the deployment commit, even if the commit has been deleted. - """ - commitOid: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the actor who triggered the deployment. - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The deployment description. - """ - description: String - - """ - The environment to which this deployment was made. - """ - environment: String - id: ID! - - """ - The latest status of this deployment. - """ - latestStatus: DeploymentStatus - - """ - Extra information that a deployment system might need. - """ - payload: String - - """ - Identifies the Ref of the deployment, if the deployment was created by ref. - """ - ref: Ref - - """ - Identifies the repository associated with the deployment. - """ - repository: Repository! - - """ - The current state of the deployment. - """ - state: DeploymentState - - """ - A list of statuses associated with the deployment. - """ - statuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): DeploymentStatusConnection - - """ - The deployment task. - """ - task: String - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for Deployment. -""" -type DeploymentConnection { - """ - A list of edges. - """ - edges: [DeploymentEdge] - - """ - A list of nodes. - """ - nodes: [Deployment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DeploymentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Deployment -} - -""" -Represents a 'deployment_environment_changed' event on a given pull request. -""" -type DeploymentEnvironmentChangedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The deployment status that updated the deployment environment. - """ - deploymentStatus: DeploymentStatus! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Ordering options for deployment connections -""" -input DeploymentOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order deployments by. - """ - field: DeploymentOrderField! -} - -""" -Properties by which deployment connections can be ordered. -""" -enum DeploymentOrderField { - """ - Order collection by creation time - """ - CREATED_AT -} - -""" -The possible states in which a deployment can be. -""" -enum DeploymentState { - """ - The pending deployment was not updated after 30 minutes. - """ - ABANDONED - - """ - The deployment is currently active. - """ - ACTIVE - - """ - An inactive transient deployment. - """ - DESTROYED - - """ - The deployment experienced an error. - """ - ERROR - - """ - The deployment has failed. - """ - FAILURE - - """ - The deployment is inactive. - """ - INACTIVE - - """ - The deployment is in progress. - """ - IN_PROGRESS - - """ - The deployment is pending. - """ - PENDING - - """ - The deployment has queued - """ - QUEUED -} - -""" -Describes the status of a given deployment attempt. -""" -type DeploymentStatus implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the actor who triggered the deployment. - """ - creator: Actor - - """ - Identifies the deployment associated with status. - """ - deployment: Deployment! - - """ - Identifies the description of the deployment. - """ - description: String - - """ - Identifies the environment URL of the deployment. - """ - environmentUrl: URI - id: ID! - - """ - Identifies the log URL of the deployment. - """ - logUrl: URI - - """ - Identifies the current state of the deployment. - """ - state: DeploymentStatusState! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -The connection type for DeploymentStatus. -""" -type DeploymentStatusConnection { - """ - A list of edges. - """ - edges: [DeploymentStatusEdge] - - """ - A list of nodes. - """ - nodes: [DeploymentStatus] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type DeploymentStatusEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: DeploymentStatus -} - -""" -The possible states for a deployment status. -""" -enum DeploymentStatusState { - """ - The deployment experienced an error. - """ - ERROR - - """ - The deployment has failed. - """ - FAILURE - - """ - The deployment is inactive. - """ - INACTIVE - - """ - The deployment is in progress. - """ - IN_PROGRESS - - """ - The deployment is pending. - """ - PENDING - - """ - The deployment is queued - """ - QUEUED - - """ - The deployment was successful. - """ - SUCCESS -} - -""" -Autogenerated input type of DismissPullRequestReview -""" -input DismissPullRequestReviewInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The contents of the pull request review dismissal message. - """ - message: String! - - """ - The Node ID of the pull request review to modify. - """ - pullRequestReviewId: ID! -} - -""" -Autogenerated return type of DismissPullRequestReview -""" -type DismissPullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The dismissed pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Specifies a review comment to be left with a Pull Request Review. -""" -input DraftPullRequestReviewComment { - """ - Body of the comment to leave. - """ - body: String! - - """ - Path to the file being commented on. - """ - path: String! - - """ - Position in the file to leave a comment on. - """ - position: Int! -} - -""" -Metadata for an audit entry containing enterprise account information. -""" -interface EnterpriseAuditEntryData { - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI -} - -""" -An external identity provisioned by SAML SSO or SCIM. -""" -type ExternalIdentity implements Node { - """ - The GUID for this identity - """ - guid: String! - id: ID! - - """ - Organization invitation for this SCIM-provisioned external identity - """ - organizationInvitation: OrganizationInvitation - - """ - SAML Identity attributes - """ - samlIdentity: ExternalIdentitySamlAttributes - - """ - SCIM Identity attributes - """ - scimIdentity: ExternalIdentityScimAttributes - - """ - User linked to this external identity. Will be NULL if this identity has not been claimed by an organization member. - """ - user: User -} - -""" -The connection type for ExternalIdentity. -""" -type ExternalIdentityConnection { - """ - A list of edges. - """ - edges: [ExternalIdentityEdge] - - """ - A list of nodes. - """ - nodes: [ExternalIdentity] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ExternalIdentityEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ExternalIdentity -} - -""" -SAML attributes for the External Identity -""" -type ExternalIdentitySamlAttributes { - """ - The NameID of the SAML identity - """ - nameId: String -} - -""" -SCIM attributes for the External Identity -""" -type ExternalIdentityScimAttributes { - """ - The userName of the SCIM identity - """ - username: String -} - -""" -The connection type for User. -""" -type FollowerConnection { - """ - A list of edges. - """ - edges: [UserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -The connection type for User. -""" -type FollowingConnection { - """ - A list of edges. - """ - edges: [UserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A Gist. -""" -type Gist implements Node & Starrable & UniformResourceLocatable { - """ - A list of comments associated with the gist - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): GistCommentConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The gist description. - """ - description: String - - """ - The files in this gist. - """ - files( - """ - The maximum number of files to return. - """ - limit: Int = 10 - - """ - The oid of the files to return - """ - oid: GitObjectID - ): [GistFile] - - """ - A list of forks associated with the gist - """ - forks( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for gists returned from the connection - """ - orderBy: GistOrder - ): GistConnection! - id: ID! - - """ - Identifies if the gist is a fork. - """ - isFork: Boolean! - - """ - Whether the gist is public or not. - """ - isPublic: Boolean! - - """ - The gist name. - """ - name: String! - - """ - The gist owner. - """ - owner: RepositoryOwner - - """ - Identifies when the gist was last pushed to. - """ - pushedAt: DateTime - - """ - The HTML path to this resource. - """ - resourcePath: URI! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this Gist. - """ - url: URI! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! -} - -""" -Represents a comment on an Gist. -""" -type GistComment implements Comment & Deletable & Node & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the gist. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the comment body. - """ - body: String! - - """ - The comment body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - - """ - The associated gist. - """ - gist: Gist! - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for GistComment. -""" -type GistCommentConnection { - """ - A list of edges. - """ - edges: [GistCommentEdge] - - """ - A list of nodes. - """ - nodes: [GistComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type GistCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: GistComment -} - -""" -The connection type for Gist. -""" -type GistConnection { - """ - A list of edges. - """ - edges: [GistEdge] - - """ - A list of nodes. - """ - nodes: [Gist] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type GistEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Gist -} - -""" -A file in a gist. -""" -type GistFile { - """ - The file name encoded to remove characters that are invalid in URL paths. - """ - encodedName: String - - """ - The gist file encoding. - """ - encoding: String - - """ - The file extension from the file name. - """ - extension: String - - """ - Indicates if this file is an image. - """ - isImage: Boolean! - - """ - Whether the file's contents were truncated. - """ - isTruncated: Boolean! - - """ - The programming language this file is written in. - """ - language: Language - - """ - The gist file name. - """ - name: String - - """ - The gist file size in bytes. - """ - size: Int - - """ - UTF8 text data or null if the file is binary - """ - text( - """ - Optionally truncate the returned file to this length. - """ - truncate: Int - ): String -} - -""" -Ordering options for gist connections -""" -input GistOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repositories by. - """ - field: GistOrderField! -} - -""" -Properties by which gist connections can be ordered. -""" -enum GistOrderField { - """ - Order gists by creation time - """ - CREATED_AT - - """ - Order gists by push time - """ - PUSHED_AT - - """ - Order gists by update time - """ - UPDATED_AT -} - -""" -The privacy of a Gist -""" -enum GistPrivacy { - """ - Gists that are public and secret - """ - ALL - - """ - Public - """ - PUBLIC - - """ - Secret - """ - SECRET -} - -""" -Represents an actor in a Git commit (ie. an author or committer). -""" -type GitActor { - """ - A URL pointing to the author's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - The timestamp of the Git action (authoring or committing). - """ - date: GitTimestamp - - """ - The email in the Git commit. - """ - email: String - - """ - The name in the Git commit. - """ - name: String - - """ - The GitHub user corresponding to the email field. Null if no such user exists. - """ - user: User -} - -""" -An edge in a connection. -""" -type GitActorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: GitActor -} - -""" -Represents information about the GitHub instance. -""" -type GitHubMetadata { - """ - Returns a String that's a SHA of `github-services` - """ - gitHubServicesSha: GitObjectID! - - """ - IP addresses that users connect to for git operations - """ - gitIpAddresses: [String!] - - """ - IP addresses that service hooks are sent from - """ - hookIpAddresses: [String!] - - """ - IP addresses that the importer connects from - """ - importerIpAddresses: [String!] - - """ - Whether or not users are verified - """ - isPasswordAuthenticationVerifiable: Boolean! - - """ - IP addresses for GitHub Pages' A records - """ - pagesIpAddresses: [String!] -} - -""" -Represents a Git object. -""" -interface GitObject { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - id: ID! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! -} - -""" -A Git object ID. -""" -scalar GitObjectID - -""" -Git SSH string -""" -scalar GitSSHRemote - -""" -Information about a signature (GPG or S/MIME) on a Commit or Tag. -""" -interface GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -The state of a Git signature. -""" -enum GitSignatureState { - """ - The signing certificate or its chain could not be verified - """ - BAD_CERT - - """ - Invalid email used for signing - """ - BAD_EMAIL - - """ - Signing key expired - """ - EXPIRED_KEY - - """ - Internal error - the GPG verification service misbehaved - """ - GPGVERIFY_ERROR - - """ - Internal error - the GPG verification service is unavailable at the moment - """ - GPGVERIFY_UNAVAILABLE - - """ - Invalid signature - """ - INVALID - - """ - Malformed signature - """ - MALFORMED_SIG - - """ - The usage flags for the key that signed this don't allow signing - """ - NOT_SIGNING_KEY - - """ - Email used for signing not known to GitHub - """ - NO_USER - - """ - Valid signature, though certificate revocation check failed - """ - OCSP_ERROR - - """ - Valid signature, pending certificate revocation checking - """ - OCSP_PENDING - - """ - One or more certificates in chain has been revoked - """ - OCSP_REVOKED - - """ - Key used for signing not known to GitHub - """ - UNKNOWN_KEY - - """ - Unknown signature type - """ - UNKNOWN_SIG_TYPE - - """ - Unsigned - """ - UNSIGNED - - """ - Email used for signing unverified on GitHub - """ - UNVERIFIED_EMAIL - - """ - Valid signature and verified by GitHub - """ - VALID -} - -""" -An ISO-8601 encoded date string. Unlike the DateTime type, GitTimestamp is not converted in UTC. -""" -scalar GitTimestamp - -""" -Represents a GPG signature on a Commit or Tag. -""" -type GpgSignature implements GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Hex-encoded ID of the key that signed this object. - """ - keyId: String - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -A string containing HTML code. -""" -scalar HTML - -""" -Represents a 'head_ref_deleted' event on a given pull request. -""" -type HeadRefDeletedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the Ref associated with the `head_ref_deleted` event. - """ - headRef: Ref - - """ - Identifies the name of the Ref associated with the `head_ref_deleted` event. - """ - headRefName: String! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -Represents a 'head_ref_force_pushed' event on a given pull request. -""" -type HeadRefForcePushedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the after commit SHA for the 'head_ref_force_pushed' event. - """ - afterCommit: Commit - - """ - Identifies the before commit SHA for the 'head_ref_force_pushed' event. - """ - beforeCommit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the fully qualified ref name for the 'head_ref_force_pushed' event. - """ - ref: Ref -} - -""" -Represents a 'head_ref_restored' event on a given pull request. -""" -type HeadRefRestoredEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! -} - -""" -The possible states in which authentication can be configured with an identity provider. -""" -enum IdentityProviderConfigurationState { - """ - Authentication with an identity provider is configured but not enforced. - """ - CONFIGURED - - """ - Authentication with an identity provider is configured and enforced. - """ - ENFORCED - - """ - Authentication with an identity provider is not configured. - """ - UNCONFIGURED -} - -""" -Autogenerated input type of ImportProject -""" -input ImportProjectInput { - """ - The description of Project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A list of columns containing issues and pull requests. - """ - columnImports: [ProjectColumnImport!]! - - """ - The name of Project. - """ - name: String! - - """ - The name of the Organization or User to create the Project under. - """ - ownerName: String! - - """ - Whether the Project is public or not. - """ - public: Boolean = false -} - -""" -An installation on a repository -""" -type InstalledAppEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: App -} - -""" -Autogenerated input type of InviteEnterpriseAdmin -""" -input InviteEnterpriseAdminInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The email of the person to invite as an administrator. - """ - email: String - - """ - The ID of the enterprise to which you want to invite an administrator. - """ - enterpriseId: ID! - - """ - The login of a user to invite as an administrator. - """ - invitee: String -} - -""" -An Issue is a place to discuss ideas, enhancements, tasks, and bugs for a project. -""" -type Issue implements Assignable & Closable & Comment & Labelable & Lockable & Node & Reactable & RepositoryNode & Subscribable & UniformResourceLocatable & Updatable & UpdatableComment { - """ - Reason that the conversation was locked. - """ - activeLockReason: LockReason - - """ - A list of Users assigned to this object. - """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the body of the issue. - """ - body: String! - - """ - Identifies the body of the issue rendered to HTML. - """ - bodyHTML: HTML! - - """ - Identifies the body of the issue rendered to text. - """ - bodyText: String! - - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - A list of comments associated with the Issue. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): IssueCommentConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - A list of labels associated with the object. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): LabelConnection - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - `true` if the object is locked - """ - locked: Boolean! - - """ - Identifies the milestone associated with the issue. - """ - milestone: Milestone - - """ - Identifies the issue number. - """ - number: Int! - - """ - A list of Users that are participating in the Issue conversation. - """ - participants( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - List of project cards associated with this issue. - """ - projectCards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path for this issue - """ - resourcePath: URI! - - """ - Identifies the state of the issue. - """ - state: IssueState! - - """ - A list of events, comments, commits, etc. associated with the issue. - """ - timeline( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows filtering timeline events by a `since` timestamp. - """ - since: DateTime - ): IssueTimelineConnection! @deprecated(reason: "`timeline` will be removed Use Issue.timelineItems instead. Removal on 2019-10-01 UTC.") - - """ - A list of events, comments, commits, etc. associated with the issue. - """ - timelineItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Filter timeline items by type. - """ - itemTypes: [IssueTimelineItemsItemType!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter timeline items by a `since` timestamp. - """ - since: DateTime - - """ - Skips the first _n_ elements in the list. - """ - skip: Int - ): IssueTimelineItemsConnection! - - """ - Identifies the issue title. - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this issue - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -Represents a comment on an Issue. -""" -type IssueComment implements Comment & Deletable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - Identifies the issue associated with the comment. - """ - issue: Issue! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Returns the pull request associated with the comment, if this comment was made on a - pull request. - """ - pullRequest: PullRequest - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path for this issue comment - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this issue comment - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for IssueComment. -""" -type IssueCommentConnection { - """ - A list of edges. - """ - edges: [IssueCommentEdge] - - """ - A list of nodes. - """ - nodes: [IssueComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type IssueCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueComment -} - -""" -The connection type for Issue. -""" -type IssueConnection { - """ - A list of edges. - """ - edges: [IssueEdge] - - """ - A list of nodes. - """ - nodes: [Issue] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -This aggregates issues opened by a user within one repository. -""" -type IssueContributionsByRepository { - """ - The issue contributions. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedIssueContributionConnection! - - """ - The repository in which the issues were opened. - """ - repository: Repository! -} - -""" -An edge in a connection. -""" -type IssueEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Issue -} - -""" -Ways in which to filter lists of issues. -""" -input IssueFilters { - """ - List issues assigned to given name. Pass in `null` for issues with no assigned - user, and `*` for issues assigned to any user. - """ - assignee: String - - """ - List issues created by given name. - """ - createdBy: String - - """ - List issues where the list of label names exist on the issue. - """ - labels: [String!] - - """ - List issues where the given name is mentioned in the issue. - """ - mentioned: String - - """ - List issues by given milestone argument. If an string representation of an - integer is passed, it should refer to a milestone by its number field. Pass in - `null` for issues with no milestone, and `*` for issues that are assigned to any milestone. - """ - milestone: String - - """ - List issues that have been updated at or after the given date. - """ - since: DateTime - - """ - List issues filtered by the list of states given. - """ - states: [IssueState!] - - """ - List issues subscribed to by viewer. - """ - viewerSubscribed: Boolean = false -} - -""" -Used for return value of Repository.issueOrPullRequest. -""" -union IssueOrPullRequest = Issue | PullRequest - -""" -An edge in a connection. -""" -type IssueOrPullRequestEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueOrPullRequest -} - -""" -Ways in which lists of issues can be ordered upon return. -""" -input IssueOrder { - """ - The direction in which to order issues by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order issues by. - """ - field: IssueOrderField! -} - -""" -Properties by which issue connections can be ordered. -""" -enum IssueOrderField { - """ - Order issues by comment count - """ - COMMENTS - - """ - Order issues by creation time - """ - CREATED_AT - - """ - Order issues by update time - """ - UPDATED_AT -} - -""" -The possible PubSub channels for an issue. -""" -enum IssuePubSubTopic { - """ - The channel ID for marking an issue as read. - """ - MARKASREAD - - """ - The channel ID for observing issue state updates. - """ - STATE - - """ - The channel ID for updating items on the issue timeline. - """ - TIMELINE - - """ - The channel ID for observing issue updates. - """ - UPDATED -} - -""" -The possible states of an issue. -""" -enum IssueState { - """ - An issue that has been closed - """ - CLOSED - - """ - An issue that is still open - """ - OPEN -} - -""" -The connection type for IssueTimelineItem. -""" -type IssueTimelineConnection { - """ - A list of edges. - """ - edges: [IssueTimelineItemEdge] - - """ - A list of nodes. - """ - nodes: [IssueTimelineItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An item in an issue timeline -""" -union IssueTimelineItem = AssignedEvent | ClosedEvent | Commit | CrossReferencedEvent | DemilestonedEvent | IssueComment | LabeledEvent | LockedEvent | MilestonedEvent | ReferencedEvent | RenamedTitleEvent | ReopenedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -An edge in a connection. -""" -type IssueTimelineItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueTimelineItem -} - -""" -An item in an issue timeline -""" -union IssueTimelineItems = AddedToProjectEvent | AssignedEvent | ClosedEvent | CommentDeletedEvent | ConvertedNoteToIssueEvent | CrossReferencedEvent | DemilestonedEvent | IssueComment | LabeledEvent | LockedEvent | MarkedAsDuplicateEvent | MentionedEvent | MilestonedEvent | MovedColumnsInProjectEvent | PinnedEvent | ReferencedEvent | RemovedFromProjectEvent | RenamedTitleEvent | ReopenedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnpinnedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -The connection type for IssueTimelineItems. -""" -type IssueTimelineItemsConnection { - """ - A list of edges. - """ - edges: [IssueTimelineItemsEdge] - - """ - Identifies the count of items after applying `before` and `after` filters. - """ - filteredCount: Int! - - """ - A list of nodes. - """ - nodes: [IssueTimelineItems] - - """ - Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing. - """ - pageCount: Int! - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Identifies the date and time when the timeline was last updated. - """ - updatedAt: DateTime! -} - -""" -An edge in a connection. -""" -type IssueTimelineItemsEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: IssueTimelineItems -} - -""" -The possible item types found in a timeline. -""" -enum IssueTimelineItemsItemType { - """ - Represents a 'added_to_project' event on a given issue or pull request. - """ - ADDED_TO_PROJECT_EVENT - - """ - Represents an 'assigned' event on any assignable object. - """ - ASSIGNED_EVENT - - """ - Represents a 'closed' event on any `Closable`. - """ - CLOSED_EVENT - - """ - Represents a 'comment_deleted' event on a given issue or pull request. - """ - COMMENT_DELETED_EVENT - - """ - Represents a 'converted_note_to_issue' event on a given issue or pull request. - """ - CONVERTED_NOTE_TO_ISSUE_EVENT - - """ - Represents a mention made by one issue or pull request to another. - """ - CROSS_REFERENCED_EVENT - - """ - Represents a 'demilestoned' event on a given issue or pull request. - """ - DEMILESTONED_EVENT - - """ - Represents a comment on an Issue. - """ - ISSUE_COMMENT - - """ - Represents a 'labeled' event on a given issue or pull request. - """ - LABELED_EVENT - - """ - Represents a 'locked' event on a given issue or pull request. - """ - LOCKED_EVENT - - """ - Represents a 'marked_as_duplicate' event on a given issue or pull request. - """ - MARKED_AS_DUPLICATE_EVENT - - """ - Represents a 'mentioned' event on a given issue or pull request. - """ - MENTIONED_EVENT - - """ - Represents a 'milestoned' event on a given issue or pull request. - """ - MILESTONED_EVENT - - """ - Represents a 'moved_columns_in_project' event on a given issue or pull request. - """ - MOVED_COLUMNS_IN_PROJECT_EVENT - - """ - Represents a 'pinned' event on a given issue or pull request. - """ - PINNED_EVENT - - """ - Represents a 'referenced' event on a given `ReferencedSubject`. - """ - REFERENCED_EVENT - - """ - Represents a 'removed_from_project' event on a given issue or pull request. - """ - REMOVED_FROM_PROJECT_EVENT - - """ - Represents a 'renamed' event on a given issue or pull request - """ - RENAMED_TITLE_EVENT - - """ - Represents a 'reopened' event on any `Closable`. - """ - REOPENED_EVENT - - """ - Represents a 'subscribed' event on a given `Subscribable`. - """ - SUBSCRIBED_EVENT - - """ - Represents a 'transferred' event on a given issue or pull request. - """ - TRANSFERRED_EVENT - - """ - Represents an 'unassigned' event on any assignable object. - """ - UNASSIGNED_EVENT - - """ - Represents an 'unlabeled' event on a given issue or pull request. - """ - UNLABELED_EVENT - - """ - Represents an 'unlocked' event on a given issue or pull request. - """ - UNLOCKED_EVENT - - """ - Represents an 'unpinned' event on a given issue or pull request. - """ - UNPINNED_EVENT - - """ - Represents an 'unsubscribed' event on a given `Subscribable`. - """ - UNSUBSCRIBED_EVENT - - """ - Represents a 'user_blocked' event on a given user. - """ - USER_BLOCKED_EVENT -} - -""" -Represents a user signing up for a GitHub account. -""" -type JoinedGitHubContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -A label for categorizing Issues or Milestones with a given Repository. -""" -type Label implements Node { - """ - Identifies the label color. - """ - color: String! - - """ - Identifies the date and time when the label was created. - """ - createdAt: DateTime - - """ - A brief description of this label. - """ - description: String - id: ID! - - """ - Indicates whether or not this is a default label. - """ - isDefault: Boolean! - - """ - A list of issues associated with this label. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Identifies the label name. - """ - name: String! - - """ - A list of pull requests associated with this label. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - The repository associated with this label. - """ - repository: Repository! - - """ - The HTTP path for this label. - """ - resourcePath: URI! - - """ - Identifies the date and time when the label was last updated. - """ - updatedAt: DateTime - - """ - The HTTP URL for this label. - """ - url: URI! -} - -""" -The connection type for Label. -""" -type LabelConnection { - """ - A list of edges. - """ - edges: [LabelEdge] - - """ - A list of nodes. - """ - nodes: [Label] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type LabelEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Label -} - -""" -An object that can have labels assigned to it. -""" -interface Labelable { - """ - A list of labels associated with the object. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): LabelConnection -} - -""" -Represents a 'labeled' event on a given issue or pull request. -""" -type LabeledEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the label associated with the 'labeled' event. - """ - label: Label! - - """ - Identifies the `Labelable` associated with the event. - """ - labelable: Labelable! -} - -""" -Represents a given language found in repositories. -""" -type Language implements Node { - """ - The color defined for the current language. - """ - color: String - id: ID! - - """ - The name of the current language. - """ - name: String! -} - -""" -A list of languages associated with the parent. -""" -type LanguageConnection { - """ - A list of edges. - """ - edges: [LanguageEdge] - - """ - A list of nodes. - """ - nodes: [Language] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - The total size in bytes of files written in that language. - """ - totalSize: Int! -} - -""" -Represents the language of a repository. -""" -type LanguageEdge { - cursor: String! - node: Language! - - """ - The number of bytes of code written in the language. - """ - size: Int! -} - -""" -Ordering options for language connections. -""" -input LanguageOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order languages by. - """ - field: LanguageOrderField! -} - -""" -Properties by which language connections can be ordered. -""" -enum LanguageOrderField { - """ - Order languages by the size of all files containing the language - """ - SIZE -} - -""" -A repository's open source license -""" -type License implements Node { - """ - The full text of the license - """ - body: String! - - """ - The conditions set by the license - """ - conditions: [LicenseRule]! - - """ - A human-readable description of the license - """ - description: String - - """ - Whether the license should be featured - """ - featured: Boolean! - - """ - Whether the license should be displayed in license pickers - """ - hidden: Boolean! - id: ID! - - """ - Instructions on how to implement the license - """ - implementation: String - - """ - The lowercased SPDX ID of the license - """ - key: String! - - """ - The limitations set by the license - """ - limitations: [LicenseRule]! - - """ - The license full name specified by - """ - name: String! - - """ - Customary short name if applicable (e.g, GPLv3) - """ - nickname: String - - """ - The permissions set by the license - """ - permissions: [LicenseRule]! - - """ - Whether the license is a pseudo-license placeholder (e.g., other, no-license) - """ - pseudoLicense: Boolean! - - """ - Short identifier specified by - """ - spdxId: String - - """ - URL to the license on - """ - url: URI -} - -""" -Describes a License's conditions, permissions, and limitations -""" -type LicenseRule { - """ - A description of the rule - """ - description: String! - - """ - The machine-readable rule key - """ - key: String! - - """ - The human-readable rule label - """ - label: String! -} - -""" -Autogenerated input type of LinkRepositoryToProject -""" -input LinkRepositoryToProjectInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Project to link to a Repository - """ - projectId: ID! - - """ - The ID of the Repository to link to a Project. - """ - repositoryId: ID! -} - -""" -Autogenerated return type of LinkRepositoryToProject -""" -type LinkRepositoryToProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The linked Project. - """ - project: Project - - """ - The linked Repository. - """ - repository: Repository -} - -""" -Autogenerated input type of LockLockable -""" -input LockLockableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A reason for why the issue or pull request will be locked. - """ - lockReason: LockReason - - """ - ID of the issue or pull request to be locked. - """ - lockableId: ID! -} - -""" -Autogenerated return type of LockLockable -""" -type LockLockablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was locked. - """ - lockedRecord: Lockable -} - -""" -The possible reasons that an issue or pull request was locked. -""" -enum LockReason { - """ - The issue or pull request was locked because the conversation was off-topic. - """ - OFF_TOPIC - - """ - The issue or pull request was locked because the conversation was resolved. - """ - RESOLVED - - """ - The issue or pull request was locked because the conversation was spam. - """ - SPAM - - """ - The issue or pull request was locked because the conversation was too heated. - """ - TOO_HEATED -} - -""" -An object that can be locked. -""" -interface Lockable { - """ - Reason that the conversation was locked. - """ - activeLockReason: LockReason - - """ - `true` if the object is locked - """ - locked: Boolean! -} - -""" -Represents a 'locked' event on a given issue or pull request. -""" -type LockedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reason that the conversation was locked (optional). - """ - lockReason: LockReason - - """ - Object that was locked. - """ - lockable: Lockable! -} - -""" -A placeholder user for attribution of imported data on GitHub. -""" -type Mannequin implements Actor & Node & UniformResourceLocatable { - """ - A URL pointing to the GitHub App's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The username of the actor. - """ - login: String! - - """ - The HTML path to this resource. - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The URL to this resource. - """ - url: URI! -} - -""" -Represents a 'marked_as_duplicate' event on a given issue or pull request. -""" -type MarkedAsDuplicateEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! -} - -""" -A public description of a Marketplace category. -""" -type MarketplaceCategory implements Node { - """ - The category's description. - """ - description: String - - """ - The technical description of how apps listed in this category work with GitHub. - """ - howItWorks: String - id: ID! - - """ - The category's name. - """ - name: String! - - """ - How many Marketplace listings have this as their primary category. - """ - primaryListingCount: Int! - - """ - The HTTP path for this Marketplace category. - """ - resourcePath: URI! - - """ - How many Marketplace listings have this as their secondary category. - """ - secondaryListingCount: Int! - - """ - The short name of the category used in its URL. - """ - slug: String! - - """ - The HTTP URL for this Marketplace category. - """ - url: URI! -} - -""" -A listing in the GitHub integration marketplace. -""" -type MarketplaceListing implements Node { - """ - The GitHub App this listing represents. - """ - app: App - - """ - URL to the listing owner's company site. - """ - companyUrl: URI - - """ - The HTTP path for configuring access to the listing's integration or OAuth app - """ - configurationResourcePath: URI! - - """ - The HTTP URL for configuring access to the listing's integration or OAuth app - """ - configurationUrl: URI! - - """ - URL to the listing's documentation. - """ - documentationUrl: URI - - """ - The listing's detailed description. - """ - extendedDescription: String - - """ - The listing's detailed description rendered to HTML. - """ - extendedDescriptionHTML: HTML! - - """ - The listing's introductory description. - """ - fullDescription: String! - - """ - The listing's introductory description rendered to HTML. - """ - fullDescriptionHTML: HTML! - - """ - Whether this listing has been submitted for review from GitHub for approval to be displayed in the Marketplace. - """ - hasApprovalBeenRequested: Boolean! @deprecated(reason: "`hasApprovalBeenRequested` will be removed. Use `isVerificationPendingFromDraft` instead. Removal on 2019-10-01 UTC.") - - """ - Does this listing have any plans with a free trial? - """ - hasPublishedFreeTrialPlans: Boolean! - - """ - Does this listing have a terms of service link? - """ - hasTermsOfService: Boolean! - - """ - A technical description of how this app works with GitHub. - """ - howItWorks: String - - """ - The listing's technical description rendered to HTML. - """ - howItWorksHTML: HTML! - id: ID! - - """ - URL to install the product to the viewer's account or organization. - """ - installationUrl: URI - - """ - Whether this listing's app has been installed for the current viewer - """ - installedForViewer: Boolean! - - """ - Whether this listing has been approved for display in the Marketplace. - """ - isApproved: Boolean! @deprecated(reason: "`isApproved` will be removed. Use `isPublic` instead. Removal on 2019-10-01 UTC.") - - """ - Whether this listing has been removed from the Marketplace. - """ - isArchived: Boolean! - - """ - Whether this listing has been removed from the Marketplace. - """ - isDelisted: Boolean! @deprecated(reason: "`isDelisted` will be removed. Use `isArchived` instead. Removal on 2019-10-01 UTC.") - - """ - Whether this listing is still an editable draft that has not been submitted - for review and is not publicly visible in the Marketplace. - """ - isDraft: Boolean! - - """ - Whether the product this listing represents is available as part of a paid plan. - """ - isPaid: Boolean! - - """ - Whether this listing has been approved for display in the Marketplace. - """ - isPublic: Boolean! - - """ - Whether this listing has been rejected by GitHub for display in the Marketplace. - """ - isRejected: Boolean! - - """ - Whether this listing has been approved for unverified display in the Marketplace. - """ - isUnverified: Boolean! - - """ - Whether this draft listing has been submitted for review for approval to be unverified in the Marketplace. - """ - isUnverifiedPending: Boolean! - - """ - Whether this draft listing has been submitted for review from GitHub for approval to be verified in the Marketplace. - """ - isVerificationPendingFromDraft: Boolean! - - """ - Whether this unverified listing has been submitted for review from GitHub for approval to be verified in the Marketplace. - """ - isVerificationPendingFromUnverified: Boolean! - - """ - Whether this listing has been approved for verified display in the Marketplace. - """ - isVerified: Boolean! - - """ - The hex color code, without the leading '#', for the logo background. - """ - logoBackgroundColor: String! - - """ - URL for the listing's logo image. - """ - logoUrl( - """ - The size in pixels of the resulting square image. - """ - size: Int = 400 - ): URI - - """ - The listing's full name. - """ - name: String! - - """ - The listing's very short description without a trailing period or ampersands. - """ - normalizedShortDescription: String! - - """ - URL to the listing's detailed pricing. - """ - pricingUrl: URI - - """ - The category that best describes the listing. - """ - primaryCategory: MarketplaceCategory! - - """ - URL to the listing's privacy policy, may return an empty string for listings that do not require a privacy policy URL. - """ - privacyPolicyUrl: URI! - - """ - The HTTP path for the Marketplace listing. - """ - resourcePath: URI! - - """ - The URLs for the listing's screenshots. - """ - screenshotUrls: [String]! - - """ - An alternate category that describes the listing. - """ - secondaryCategory: MarketplaceCategory - - """ - The listing's very short description. - """ - shortDescription: String! - - """ - The short name of the listing used in its URL. - """ - slug: String! - - """ - URL to the listing's status page. - """ - statusUrl: URI - - """ - An email address for support for this listing's app. - """ - supportEmail: String - - """ - Either a URL or an email address for support for this listing's app, may - return an empty string for listings that do not require a support URL. - """ - supportUrl: URI! - - """ - URL to the listing's terms of service. - """ - termsOfServiceUrl: URI - - """ - The HTTP URL for the Marketplace listing. - """ - url: URI! - - """ - Can the current viewer add plans for this Marketplace listing. - """ - viewerCanAddPlans: Boolean! - - """ - Can the current viewer approve this Marketplace listing. - """ - viewerCanApprove: Boolean! - - """ - Can the current viewer delist this Marketplace listing. - """ - viewerCanDelist: Boolean! - - """ - Can the current viewer edit this Marketplace listing. - """ - viewerCanEdit: Boolean! - - """ - Can the current viewer edit the primary and secondary category of this - Marketplace listing. - """ - viewerCanEditCategories: Boolean! - - """ - Can the current viewer edit the plans for this Marketplace listing. - """ - viewerCanEditPlans: Boolean! - - """ - Can the current viewer return this Marketplace listing to draft state - so it becomes editable again. - """ - viewerCanRedraft: Boolean! - - """ - Can the current viewer reject this Marketplace listing by returning it to - an editable draft state or rejecting it entirely. - """ - viewerCanReject: Boolean! - - """ - Can the current viewer request this listing be reviewed for display in - the Marketplace as verified. - """ - viewerCanRequestApproval: Boolean! - - """ - Indicates whether the current user has an active subscription to this Marketplace listing. - """ - viewerHasPurchased: Boolean! - - """ - Indicates if the current user has purchased a subscription to this Marketplace listing - for all of the organizations the user owns. - """ - viewerHasPurchasedForAllOrganizations: Boolean! - - """ - Does the current viewer role allow them to administer this Marketplace listing. - """ - viewerIsListingAdmin: Boolean! -} - -""" -Look up Marketplace Listings -""" -type MarketplaceListingConnection { - """ - A list of edges. - """ - edges: [MarketplaceListingEdge] - - """ - A list of nodes. - """ - nodes: [MarketplaceListing] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type MarketplaceListingEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: MarketplaceListing -} - -""" -Entities that have members who can set status messages. -""" -interface MemberStatusable { - """ - Get the status messages members of this entity have set that are either public or visible only to the organization. - """ - memberStatuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for user statuses returned from the connection. - """ - orderBy: UserStatusOrder = {field: UPDATED_AT, direction: DESC} - ): UserStatusConnection! -} - -""" -Audit log entry for a members_can_delete_repos.clear event. -""" -type MembersCanDeleteReposClearAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a members_can_delete_repos.disable event. -""" -type MembersCanDeleteReposDisableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a members_can_delete_repos.enable event. -""" -type MembersCanDeleteReposEnableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Represents a 'mentioned' event on a given issue or pull request. -""" -type MentionedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Autogenerated input type of MergeBranch -""" -input MergeBranchInput { - """ - The name of the base branch that the provided head will be merged into. - """ - base: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Message to use for the merge commit. If omitted, a default will be used. - """ - commitMessage: String - - """ - The head to merge into the base branch. This can be a branch name or a commit GitObjectID. - """ - head: String! - - """ - The Node ID of the Repository containing the base branch that will be modified. - """ - repositoryId: ID! -} - -""" -Autogenerated return type of MergeBranch -""" -type MergeBranchPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The resulting merge Commit. - """ - mergeCommit: Commit -} - -""" -Autogenerated input type of MergePullRequest -""" -input MergePullRequestInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Commit body to use for the merge commit; if omitted, a default message will be used - """ - commitBody: String - - """ - Commit headline to use for the merge commit; if omitted, a default message will be used. - """ - commitHeadline: String - - """ - OID that the pull request head ref must match to allow merge; if omitted, no check is performed. - """ - expectedHeadOid: GitObjectID - - """ - ID of the pull request to be merged. - """ - pullRequestId: ID! -} - -""" -Autogenerated return type of MergePullRequest -""" -type MergePullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that was merged. - """ - pullRequest: PullRequest -} - -""" -Whether or not a PullRequest can be merged. -""" -enum MergeableState { - """ - The pull request cannot be merged due to merge conflicts. - """ - CONFLICTING - - """ - The pull request can be merged. - """ - MERGEABLE - - """ - The mergeability of the pull request is still being calculated. - """ - UNKNOWN -} - -""" -Represents a 'merged' event on a given pull request. -""" -type MergedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the commit associated with the `merge` event. - """ - commit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the Ref associated with the `merge` event. - """ - mergeRef: Ref - - """ - Identifies the name of the Ref associated with the `merge` event. - """ - mergeRefName: String! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this merged event. - """ - resourcePath: URI! - - """ - The HTTP URL for this merged event. - """ - url: URI! -} - -""" -Represents a Milestone object on a given repository. -""" -type Milestone implements Closable & Node & UniformResourceLocatable { - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the actor who created the milestone. - """ - creator: Actor - - """ - Identifies the description of the milestone. - """ - description: String - - """ - Identifies the due date of the milestone. - """ - dueOn: DateTime - id: ID! - - """ - Just for debugging on review-lab - """ - issuePrioritiesDebug: String! - - """ - A list of issues associated with the milestone. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Identifies the number of the milestone. - """ - number: Int! - - """ - A list of pull requests associated with the milestone. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - The repository associated with this milestone. - """ - repository: Repository! - - """ - The HTTP path for this milestone - """ - resourcePath: URI! - - """ - Identifies the state of the milestone. - """ - state: MilestoneState! - - """ - Identifies the title of the milestone. - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this milestone - """ - url: URI! -} - -""" -The connection type for Milestone. -""" -type MilestoneConnection { - """ - A list of edges. - """ - edges: [MilestoneEdge] - - """ - A list of nodes. - """ - nodes: [Milestone] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type MilestoneEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Milestone -} - -""" -Types that can be inside a Milestone. -""" -union MilestoneItem = Issue | PullRequest - -""" -Ordering options for milestone connections. -""" -input MilestoneOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order milestones by. - """ - field: MilestoneOrderField! -} - -""" -Properties by which milestone connections can be ordered. -""" -enum MilestoneOrderField { - """ - Order milestones by when they were created. - """ - CREATED_AT - - """ - Order milestones by when they are due. - """ - DUE_DATE - - """ - Order milestones by their number. - """ - NUMBER - - """ - Order milestones by when they were last updated. - """ - UPDATED_AT -} - -""" -The possible states of a milestone. -""" -enum MilestoneState { - """ - A milestone that has been closed. - """ - CLOSED - - """ - A milestone that is still open. - """ - OPEN -} - -""" -Represents a 'milestoned' event on a given issue or pull request. -""" -type MilestonedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the milestone title associated with the 'milestoned' event. - """ - milestoneTitle: String! - - """ - Object referenced by event. - """ - subject: MilestoneItem! -} - -""" -Autogenerated input type of MinimizeComment -""" -input MinimizeCommentInput { - """ - The classification of comment - """ - classifier: ReportedContentClassifiers! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! -} - -""" -Autogenerated input type of MoveProjectCard -""" -input MoveProjectCardInput { - """ - Place the new card after the card with this id. Pass null to place it at the top. - """ - afterCardId: ID - - """ - The id of the card to move. - """ - cardId: ID! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the column to move it into. - """ - columnId: ID! -} - -""" -Autogenerated return type of MoveProjectCard -""" -type MoveProjectCardPayload { - """ - The new edge of the moved card. - """ - cardEdge: ProjectCardEdge - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of MoveProjectColumn -""" -input MoveProjectColumnInput { - """ - Place the new column after the column with this id. Pass null to place it at the front. - """ - afterColumnId: ID - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The id of the column to move. - """ - columnId: ID! -} - -""" -Autogenerated return type of MoveProjectColumn -""" -type MoveProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new edge of the moved column. - """ - columnEdge: ProjectColumnEdge -} - -""" -Represents a 'moved_columns_in_project' event on a given issue or pull request. -""" -type MovedColumnsInProjectEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -The root query for implementing GraphQL mutations. -""" -type Mutation { - """ - Applies a suggested topic to the repository. - """ - acceptTopicSuggestion(input: AcceptTopicSuggestionInput!): AcceptTopicSuggestionPayload - - """ - Adds assignees to an assignable object. - """ - addAssigneesToAssignable(input: AddAssigneesToAssignableInput!): AddAssigneesToAssignablePayload - - """ - Adds a comment to an Issue or Pull Request. - """ - addComment(input: AddCommentInput!): AddCommentPayload - - """ - Adds labels to a labelable object. - """ - addLabelsToLabelable(input: AddLabelsToLabelableInput!): AddLabelsToLabelablePayload - - """ - Adds a card to a ProjectColumn. Either `contentId` or `note` must be provided but **not** both. - """ - addProjectCard(input: AddProjectCardInput!): AddProjectCardPayload - - """ - Adds a column to a Project. - """ - addProjectColumn(input: AddProjectColumnInput!): AddProjectColumnPayload - - """ - Adds a review to a Pull Request. - """ - addPullRequestReview(input: AddPullRequestReviewInput!): AddPullRequestReviewPayload - - """ - Adds a comment to a review. - """ - addPullRequestReviewComment(input: AddPullRequestReviewCommentInput!): AddPullRequestReviewCommentPayload - - """ - Adds a reaction to a subject. - """ - addReaction(input: AddReactionInput!): AddReactionPayload - - """ - Adds a star to a Starrable. - """ - addStar(input: AddStarInput!): AddStarPayload - - """ - Update your status on GitHub. - """ - changeUserStatus(input: ChangeUserStatusInput!): ChangeUserStatusPayload - - """ - Clears all labels from a labelable object. - """ - clearLabelsFromLabelable(input: ClearLabelsFromLabelableInput!): ClearLabelsFromLabelablePayload - - """ - Creates a new project by cloning configuration from an existing project. - """ - cloneProject(input: CloneProjectInput!): CloneProjectPayload - - """ - Create a new repository with the same files and directory structure as a template repository. - """ - cloneTemplateRepository(input: CloneTemplateRepositoryInput!): CloneTemplateRepositoryPayload - - """ - Close an issue. - """ - closeIssue(input: CloseIssueInput!): CloseIssuePayload - - """ - Close a pull request. - """ - closePullRequest(input: ClosePullRequestInput!): ClosePullRequestPayload - - """ - Convert a project note card to one associated with a newly created issue. - """ - convertProjectCardNoteToIssue(input: ConvertProjectCardNoteToIssueInput!): ConvertProjectCardNoteToIssuePayload - - """ - Create a new branch protection rule - """ - createBranchProtectionRule(input: CreateBranchProtectionRuleInput!): CreateBranchProtectionRulePayload - - """ - Creates a new issue. - """ - createIssue(input: CreateIssueInput!): CreateIssuePayload - - """ - Creates a new project. - """ - createProject(input: CreateProjectInput!): CreateProjectPayload - - """ - Create a new pull request - """ - createPullRequest(input: CreatePullRequestInput!): CreatePullRequestPayload - - """ - Create a new Git Ref. - """ - createRef(input: CreateRefInput!): CreateRefPayload - - """ - Create a new repository. - """ - createRepository(input: CreateRepositoryInput!): CreateRepositoryPayload - - """ - Rejects a suggested topic for the repository. - """ - declineTopicSuggestion(input: DeclineTopicSuggestionInput!): DeclineTopicSuggestionPayload - - """ - Delete a branch protection rule - """ - deleteBranchProtectionRule(input: DeleteBranchProtectionRuleInput!): DeleteBranchProtectionRulePayload - - """ - Deletes an Issue object. - """ - deleteIssue(input: DeleteIssueInput!): DeleteIssuePayload - - """ - Deletes an IssueComment object. - """ - deleteIssueComment(input: DeleteIssueCommentInput!): DeleteIssueCommentPayload - - """ - Deletes a project. - """ - deleteProject(input: DeleteProjectInput!): DeleteProjectPayload - - """ - Deletes a project card. - """ - deleteProjectCard(input: DeleteProjectCardInput!): DeleteProjectCardPayload - - """ - Deletes a project column. - """ - deleteProjectColumn(input: DeleteProjectColumnInput!): DeleteProjectColumnPayload - - """ - Deletes a pull request review. - """ - deletePullRequestReview(input: DeletePullRequestReviewInput!): DeletePullRequestReviewPayload - - """ - Deletes a pull request review comment. - """ - deletePullRequestReviewComment(input: DeletePullRequestReviewCommentInput!): DeletePullRequestReviewCommentPayload - - """ - Delete a Git Ref. - """ - deleteRef(input: DeleteRefInput!): DeleteRefPayload - - """ - Dismisses an approved or rejected pull request review. - """ - dismissPullRequestReview(input: DismissPullRequestReviewInput!): DismissPullRequestReviewPayload - - """ - Creates a repository link for a project. - """ - linkRepositoryToProject(input: LinkRepositoryToProjectInput!): LinkRepositoryToProjectPayload - - """ - Lock a lockable object - """ - lockLockable(input: LockLockableInput!): LockLockablePayload - - """ - Merge a head into a branch. - """ - mergeBranch(input: MergeBranchInput!): MergeBranchPayload - - """ - Merge a pull request. - """ - mergePullRequest(input: MergePullRequestInput!): MergePullRequestPayload - - """ - Moves a project card to another place. - """ - moveProjectCard(input: MoveProjectCardInput!): MoveProjectCardPayload - - """ - Moves a project column to another place. - """ - moveProjectColumn(input: MoveProjectColumnInput!): MoveProjectColumnPayload - - """ - Removes assignees from an assignable object. - """ - removeAssigneesFromAssignable(input: RemoveAssigneesFromAssignableInput!): RemoveAssigneesFromAssignablePayload - - """ - Removes labels from a Labelable object. - """ - removeLabelsFromLabelable(input: RemoveLabelsFromLabelableInput!): RemoveLabelsFromLabelablePayload - - """ - Removes outside collaborator from all repositories in an organization. - """ - removeOutsideCollaborator(input: RemoveOutsideCollaboratorInput!): RemoveOutsideCollaboratorPayload - - """ - Removes a reaction from a subject. - """ - removeReaction(input: RemoveReactionInput!): RemoveReactionPayload - - """ - Removes a star from a Starrable. - """ - removeStar(input: RemoveStarInput!): RemoveStarPayload - - """ - Reopen a issue. - """ - reopenIssue(input: ReopenIssueInput!): ReopenIssuePayload - - """ - Reopen a pull request. - """ - reopenPullRequest(input: ReopenPullRequestInput!): ReopenPullRequestPayload - - """ - Set review requests on a pull request. - """ - requestReviews(input: RequestReviewsInput!): RequestReviewsPayload - - """ - Marks a review thread as resolved. - """ - resolveReviewThread(input: ResolveReviewThreadInput!): ResolveReviewThreadPayload - - """ - Submits a pending pull request review. - """ - submitPullRequestReview(input: SubmitPullRequestReviewInput!): SubmitPullRequestReviewPayload - - """ - Transfer an issue to a different repository - """ - transferIssue(input: TransferIssueInput!): TransferIssuePayload - - """ - Deletes a repository link from a project. - """ - unlinkRepositoryFromProject(input: UnlinkRepositoryFromProjectInput!): UnlinkRepositoryFromProjectPayload - - """ - Unlock a lockable object - """ - unlockLockable(input: UnlockLockableInput!): UnlockLockablePayload - - """ - Unmark an issue as a duplicate of another issue. - """ - unmarkIssueAsDuplicate(input: UnmarkIssueAsDuplicateInput!): UnmarkIssueAsDuplicatePayload - - """ - Marks a review thread as unresolved. - """ - unresolveReviewThread(input: UnresolveReviewThreadInput!): UnresolveReviewThreadPayload - - """ - Create a new branch protection rule - """ - updateBranchProtectionRule(input: UpdateBranchProtectionRuleInput!): UpdateBranchProtectionRulePayload - - """ - Updates an Issue. - """ - updateIssue(input: UpdateIssueInput!): UpdateIssuePayload - - """ - Updates an IssueComment object. - """ - updateIssueComment(input: UpdateIssueCommentInput!): UpdateIssueCommentPayload - - """ - Updates an existing project. - """ - updateProject(input: UpdateProjectInput!): UpdateProjectPayload - - """ - Updates an existing project card. - """ - updateProjectCard(input: UpdateProjectCardInput!): UpdateProjectCardPayload - - """ - Updates an existing project column. - """ - updateProjectColumn(input: UpdateProjectColumnInput!): UpdateProjectColumnPayload - - """ - Update a pull request - """ - updatePullRequest(input: UpdatePullRequestInput!): UpdatePullRequestPayload - - """ - Updates the body of a pull request review. - """ - updatePullRequestReview(input: UpdatePullRequestReviewInput!): UpdatePullRequestReviewPayload - - """ - Updates a pull request review comment. - """ - updatePullRequestReviewComment(input: UpdatePullRequestReviewCommentInput!): UpdatePullRequestReviewCommentPayload - - """ - Update a Git Ref. - """ - updateRef(input: UpdateRefInput!): UpdateRefPayload - - """ - Update information about a repository. - """ - updateRepository(input: UpdateRepositoryInput!): UpdateRepositoryPayload - - """ - Updates the state for subscribable subjects. - """ - updateSubscription(input: UpdateSubscriptionInput!): UpdateSubscriptionPayload - - """ - Replaces the repository's topics with the given topics. - """ - updateTopics(input: UpdateTopicsInput!): UpdateTopicsPayload -} - -""" -An object with an ID. -""" -interface Node { - """ - ID of the object. - """ - id: ID! -} - -""" -Metadata for an audit entry with action oauth_application.* -""" -interface OauthApplicationAuditEntryData { - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI -} - -""" -Audit log entry for a oauth_application.create event. -""" -type OauthApplicationCreateAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The application URL of the OAuth Application. - """ - applicationUrl: URI - - """ - The callback URL of the OAuth Application. - """ - callbackUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The rate limit of the OAuth Application. - """ - rateLimit: Int - - """ - The state of the OAuth Application. - """ - state: OauthApplicationCreateAuditEntryState - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The state of an OAuth Application when it was created. -""" -enum OauthApplicationCreateAuditEntryState { - """ - The OAuth Application was active and allowed to have OAuth Accesses. - """ - ACTIVE - - """ - The OAuth Application was in the process of being deleted. - """ - PENDING_DELETION - - """ - The OAuth Application was suspended from generating OAuth Accesses due to abuse or security concerns. - """ - SUSPENDED -} - -""" -The state of an OAuth Application when its tokens were revoked. -""" -enum OauthApplicationRevokeTokensAuditEntryState { - """ - The OAuth Application was active and allowed to have OAuth Accesses. - """ - ACTIVE - - """ - The OAuth Application was in the process of being deleted. - """ - PENDING_DELETION - - """ - The OAuth Application was suspended from generating OAuth Accesses due to abuse or security concerns. - """ - SUSPENDED -} - -""" -Possible directions in which to order a list of items when provided an `orderBy` argument. -""" -enum OrderDirection { - """ - Specifies an ascending order for a given `orderBy` argument. - """ - ASC - - """ - Specifies a descending order for a given `orderBy` argument. - """ - DESC -} - -""" -Audit log entry for a org.add_billing_manager -""" -type OrgAddBillingManagerAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The email address used to invite a billing manager for the organization. - """ - invitationEmail: String - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.add_member -""" -type OrgAddMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The permission level of the member added to the organization. - """ - permission: OrgAddMemberAuditEntryPermission - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The permissions available to members on an Organization. -""" -enum OrgAddMemberAuditEntryPermission { - """ - Can read, clone, push, and add collaborators to repositories. - """ - ADMIN - - """ - Can read and clone repositories. - """ - READ -} - -""" -Audit log entry for a org.block_user -""" -type OrgBlockUserAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The blocked user. - """ - blockedUser: User - - """ - The username of the blocked user. - """ - blockedUserName: String - - """ - The HTTP path for the blocked user. - """ - blockedUserResourcePath: URI - - """ - The HTTP URL for the blocked user. - """ - blockedUserUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.config.disable_collaborators_only event. -""" -type OrgConfigDisableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.config.enable_collaborators_only event. -""" -type OrgConfigEnableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.disable_oauth_app_restrictions event. -""" -type OrgDisableOauthAppRestrictionsAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.disable_saml event. -""" -type OrgDisableSamlAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The SAML provider's digest algorithm URL. - """ - digestMethodUrl: URI - id: ID! - - """ - The SAML provider's issuer URL. - """ - issuerUrl: URI - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The SAML provider's signature algorithm URL. - """ - signatureMethodUrl: URI - - """ - The SAML provider's single sign-on URL. - """ - singleSignOnUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.disable_two_factor_requirement event. -""" -type OrgDisableTwoFactorRequirementAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.enable_oauth_app_restrictions event. -""" -type OrgEnableOauthAppRestrictionsAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.enable_saml event. -""" -type OrgEnableSamlAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The SAML provider's digest algorithm URL. - """ - digestMethodUrl: URI - id: ID! - - """ - The SAML provider's issuer URL. - """ - issuerUrl: URI - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The SAML provider's signature algorithm URL. - """ - signatureMethodUrl: URI - - """ - The SAML provider's single sign-on URL. - """ - singleSignOnUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.enable_two_factor_requirement event. -""" -type OrgEnableTwoFactorRequirementAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.invite_member event. -""" -type OrgInviteMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The email address of the organization invitation. - """ - email: String - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The organization invitation. - """ - organizationInvitation: OrganizationInvitation - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.invite_to_business event. -""" -type OrgInviteToBusinessAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.oauth_app_access_approved event. -""" -type OrgOauthAppAccessApprovedAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.oauth_app_access_denied event. -""" -type OrgOauthAppAccessDeniedAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.oauth_app_access_requested event. -""" -type OrgOauthAppAccessRequestedAuditEntry implements AuditEntry & Node & OauthApplicationAuditEntryData & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The name of the OAuth Application. - """ - oauthApplicationName: String - - """ - The HTTP path for the OAuth Application - """ - oauthApplicationResourcePath: URI - - """ - The HTTP URL for the OAuth Application - """ - oauthApplicationUrl: URI - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.remove_billing_manager event. -""" -type OrgRemoveBillingManagerAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The reason for the billing manager being removed. - """ - reason: OrgRemoveBillingManagerAuditEntryReason - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The reason a billing manager was removed from an Organization. -""" -enum OrgRemoveBillingManagerAuditEntryReason { - """ - SAML external identity missing - """ - SAML_EXTERNAL_IDENTITY_MISSING - - """ - SAML SSO enforcement requires an external identity - """ - SAML_SSO_ENFORCEMENT_REQUIRES_EXTERNAL_IDENTITY - - """ - The organization required 2FA of its billing managers and this user did not have 2FA enabled. - """ - TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE -} - -""" -Audit log entry for a org.remove_member event. -""" -type OrgRemoveMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The types of membership the member has with the organization. - """ - membershipTypes: [OrgRemoveMemberAuditEntryMembershipType!] - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The reason for the member being removed. - """ - reason: OrgRemoveMemberAuditEntryReason - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The type of membership a user has with an Organization. -""" -enum OrgRemoveMemberAuditEntryMembershipType { - """ - Organization administrators have full access and can change several settings, - including the names of repositories that belong to the Organization and Owners - team membership. In addition, organization admins can delete the organization - and all of its repositories. - """ - ADMIN - - """ - A billing manager is a user who manages the billing settings for the Organization, such as updating payment information. - """ - BILLING_MANAGER - - """ - A direct member is a user that is a member of the Organization. - """ - DIRECT_MEMBER - - """ - An outside collaborator is a person who isn't explicitly a member of the - Organization, but who has Read, Write, or Admin permissions to one or more - repositories in the organization. - """ - OUTSIDE_COLLABORATOR - - """ - An unaffiliated collaborator is a person who is not a member of the - Organization and does not have access to any repositories in the Organization. - """ - UNAFFILIATED -} - -""" -The reason a member was removed from an Organization. -""" -enum OrgRemoveMemberAuditEntryReason { - """ - SAML external identity missing - """ - SAML_EXTERNAL_IDENTITY_MISSING - - """ - SAML SSO enforcement requires an external identity - """ - SAML_SSO_ENFORCEMENT_REQUIRES_EXTERNAL_IDENTITY - - """ - The organization required 2FA of its billing managers and this user did not have 2FA enabled. - """ - TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE -} - -""" -Audit log entry for a org.remove_outside_collaborator event. -""" -type OrgRemoveOutsideCollaboratorAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The types of membership the outside collaborator has with the organization. - """ - membershipTypes: [OrgRemoveOutsideCollaboratorAuditEntryMembershipType!] - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The reason for the outside collaborator being removed from the Organization. - """ - reason: OrgRemoveOutsideCollaboratorAuditEntryReason - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The type of membership a user has with an Organization. -""" -enum OrgRemoveOutsideCollaboratorAuditEntryMembershipType { - """ - A billing manager is a user who manages the billing settings for the Organization, such as updating payment information. - """ - BILLING_MANAGER - - """ - An outside collaborator is a person who isn't explicitly a member of the - Organization, but who has Read, Write, or Admin permissions to one or more - repositories in the organization. - """ - OUTSIDE_COLLABORATOR - - """ - An unaffiliated collaborator is a person who is not a member of the - Organization and does not have access to any repositories in the organization. - """ - UNAFFILIATED -} - -""" -The reason an outside collaborator was removed from an Organization. -""" -enum OrgRemoveOutsideCollaboratorAuditEntryReason { - """ - SAML external identity missing - """ - SAML_EXTERNAL_IDENTITY_MISSING - - """ - The organization required 2FA of its billing managers and this user did not have 2FA enabled. - """ - TWO_FACTOR_REQUIREMENT_NON_COMPLIANCE -} - -""" -Audit log entry for a org.restore_member event. -""" -type OrgRestoreMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The number of custom email routings for the restored member. - """ - restoredCustomEmailRoutingsCount: Int - - """ - The number of issue assignments for the restored member. - """ - restoredIssueAssignmentsCount: Int - - """ - Restored organization membership objects. - """ - restoredMemberships: [OrgRestoreMemberAuditEntryMembership!] - - """ - The number of restored memberships. - """ - restoredMembershipsCount: Int - - """ - The number of repositories of the restored member. - """ - restoredRepositoriesCount: Int - - """ - The number of starred repositories for the restored member. - """ - restoredRepositoryStarsCount: Int - - """ - The number of watched repositories for the restored member. - """ - restoredRepositoryWatchesCount: Int - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Types of memberships that can be restored for an Organization member. -""" -union OrgRestoreMemberAuditEntryMembership = OrgRestoreMemberMembershipOrganizationAuditEntryData | OrgRestoreMemberMembershipRepositoryAuditEntryData | OrgRestoreMemberMembershipTeamAuditEntryData - -""" -Metadata for an organization membership for org.restore_member actions -""" -type OrgRestoreMemberMembershipOrganizationAuditEntryData implements OrganizationAuditEntryData { - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI -} - -""" -Metadata for a repository membership for org.restore_member actions -""" -type OrgRestoreMemberMembershipRepositoryAuditEntryData implements RepositoryAuditEntryData { - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI -} - -""" -Metadata for a team membership for org.restore_member actions -""" -type OrgRestoreMemberMembershipTeamAuditEntryData implements TeamAuditEntryData { - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI -} - -""" -Audit log entry for a org.unblock_user -""" -type OrgUnblockUserAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The user being unblocked by the organization. - """ - blockedUser: User - - """ - The username of the blocked user. - """ - blockedUserName: String - - """ - The HTTP path for the blocked user. - """ - blockedUserResourcePath: URI - - """ - The HTTP URL for the blocked user. - """ - blockedUserUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a org.update_default_repository_permission -""" -type OrgUpdateDefaultRepositoryPermissionAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The new default repository permission level for the organization. - """ - permission: OrgUpdateDefaultRepositoryPermissionAuditEntryPermission - - """ - The former default repository permission level for the organization. - """ - permissionWas: OrgUpdateDefaultRepositoryPermissionAuditEntryPermission - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The default permission a repository can have in an Organization. -""" -enum OrgUpdateDefaultRepositoryPermissionAuditEntryPermission { - """ - Can read, clone, push, and add collaborators to repositories. - """ - ADMIN - - """ - No default permission value. - """ - NONE - - """ - Can read and clone repositories. - """ - READ - - """ - Can read, clone and push to repositories. - """ - WRITE -} - -""" -Audit log entry for a org.update_member event. -""" -type OrgUpdateMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The new member permission level for the organization. - """ - permission: OrgUpdateMemberAuditEntryPermission - - """ - The former member permission level for the organization. - """ - permissionWas: OrgUpdateMemberAuditEntryPermission - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The permissions available to members on an Organization. -""" -enum OrgUpdateMemberAuditEntryPermission { - """ - Can read, clone, push, and add collaborators to repositories. - """ - ADMIN - - """ - Can read and clone repositories. - """ - READ -} - -""" -Audit log entry for a org.update_member_repository_creation_permission event. -""" -type OrgUpdateMemberRepositoryCreationPermissionAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - Can members create repositories in the organization. - """ - canCreateRepositories: Boolean - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The permission for visibility level of repositories for this organization. - """ - visibility: OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility -} - -""" -The permissions available for repository creation on an Organization. -""" -enum OrgUpdateMemberRepositoryCreationPermissionAuditEntryVisibility { - """ - All organization members are restricted from creating any repositories. - """ - ALL - - """ - All organization members are restricted from creating public repositories. - """ - PUBLIC -} - -""" -Audit log entry for a org.update_member_repository_invitation_permission event. -""" -type OrgUpdateMemberRepositoryInvitationPermissionAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - Can outside collaborators be invited to repositories in the organization. - """ - canInviteOutsideCollaboratorsToRepositories: Boolean - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -An account on GitHub, with one or more owners, that has repositories, members and teams. -""" -type Organization implements Actor & MemberStatusable & Node & ProfileOwner & ProjectOwner & RegistryPackageOwner & RegistryPackageSearch & RepositoryOwner & UniformResourceLocatable { - """ - Determine if this repository owner has any items that can be pinned to their profile. - """ - anyPinnableItems( - """ - Filter to only a particular kind of pinnable item. - """ - type: PinnableItemType - ): Boolean! - - """ - Audit log entries of the organization - """ - auditLog( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned audit log entries. - """ - orderBy: AuditLogOrder = {field: CREATED_AT, direction: DESC} - - """ - The query string to filter audit entries - """ - query: String - ): OrganizationAuditEntryConnection! - - """ - A URL pointing to the organization's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The organization's public profile description. - """ - description: String - - """ - The organization's public email. - """ - email: String - id: ID! - - """ - Whether the organization has verified its profile email and website. - """ - isVerified: Boolean! - - """ - Showcases a selection of repositories and gists that the profile owner has - either curated or that have been selected automatically based on popularity. - """ - itemShowcase: ProfileItemShowcase! - - """ - The organization's public profile location. - """ - location: String - - """ - The organization's login name. - """ - login: String! - - """ - Get the status messages members of this entity have set that are either public or visible only to the organization. - """ - memberStatuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for user statuses returned from the connection. - """ - orderBy: UserStatusOrder = {field: UPDATED_AT, direction: DESC} - ): UserStatusConnection! - - """ - A list of users who are members of this organization. - """ - membersWithRole( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationMemberConnection! - - """ - The organization's public profile name. - """ - name: String - - """ - The HTTP path creating a new team - """ - newTeamResourcePath: URI! - - """ - The HTTP URL creating a new team - """ - newTeamUrl: URI! - - """ - The billing email for the organization. - """ - organizationBillingEmail: String - - """ - A list of users who have been invited to join this organization. - """ - pendingMembers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - A list of repositories and gists this profile owner can pin to their profile. - """ - pinnableItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinnable items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - A list of repositories and gists this profile owner has pinned to their profile - """ - pinnedItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinned items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - Returns how many more items this profile owner can pin to their profile. - """ - pinnedItemsRemaining: Int! - - """ - A list of repositories this user has pinned to their profile - """ - pinnedRepositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! @deprecated(reason: "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-10-01 UTC.") - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing organization's projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing organization's projects - """ - projectsUrl: URI! - - """ - A list of registry packages under the owner. - """ - registryPackages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find registry package by name. - """ - name: String - - """ - Find registry packages by their names. - """ - names: [String] - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Filter registry package by whether it is publicly visible - """ - publicOnly: Boolean = false - - """ - Filter registry package by type (string). - """ - registryPackageType: String - - """ - Find registry packages in a repository. - """ - repositoryId: ID - ): RegistryPackageConnection! - - """ - A list of registry packages for a particular search query. - """ - registryPackagesForQuery( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Find registry package by search query. - """ - query: String - ): RegistryPackageConnection! - - """ - A list of repositories that the user owns. - """ - repositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they are forks of another repository - """ - isFork: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Find Repository. - """ - repository( - """ - Name of Repository to find. - """ - name: String! - ): Repository - - """ - When true the organization requires all members, billing managers, and outside - collaborators to enable two-factor authentication. - """ - requiresTwoFactorAuthentication: Boolean - - """ - The HTTP path for this organization. - """ - resourcePath: URI! - - """ - The Organization's SAML identity providers - """ - samlIdentityProvider: OrganizationIdentityProvider - - """ - Find an organization's team by its slug. - """ - team( - """ - The name or slug of the team to find. - """ - slug: String! - ): Team - - """ - A list of teams in this organization. - """ - teams( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - If true, filters teams that are mapped to an LDAP Group (Enterprise only) - """ - ldapMapped: Boolean - - """ - Ordering options for teams returned from the connection - """ - orderBy: TeamOrder - - """ - If non-null, filters teams according to privacy - """ - privacy: TeamPrivacy - - """ - If non-null, filters teams with query on team name and team slug - """ - query: String - - """ - If non-null, filters teams according to whether the viewer is an admin or member on team - """ - role: TeamRole - - """ - If true, restrict to only root teams - """ - rootTeamsOnly: Boolean = false - - """ - User logins to filter by - """ - userLogins: [String!] - ): TeamConnection! - - """ - The HTTP path listing organization's teams - """ - teamsResourcePath: URI! - - """ - The HTTP URL listing organization's teams - """ - teamsUrl: URI! - - """ - The HTTP URL for this organization. - """ - url: URI! - - """ - Organization is adminable by the viewer. - """ - viewerCanAdminister: Boolean! - - """ - Can the viewer pin repositories and gists to the profile? - """ - viewerCanChangePinnedItems: Boolean! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! - - """ - Viewer can create repositories on this organization - """ - viewerCanCreateRepositories: Boolean! - - """ - Viewer can create teams on this organization. - """ - viewerCanCreateTeams: Boolean! - - """ - Viewer is an active member of this organization. - """ - viewerIsAMember: Boolean! - - """ - The organization's public profile URL. - """ - websiteUrl: URI -} - -""" -An audit entry in an organization audit log. -""" -union OrganizationAuditEntry = MembersCanDeleteReposClearAuditEntry | MembersCanDeleteReposDisableAuditEntry | MembersCanDeleteReposEnableAuditEntry | OauthApplicationCreateAuditEntry | OrgAddBillingManagerAuditEntry | OrgAddMemberAuditEntry | OrgBlockUserAuditEntry | OrgConfigDisableCollaboratorsOnlyAuditEntry | OrgConfigEnableCollaboratorsOnlyAuditEntry | OrgDisableOauthAppRestrictionsAuditEntry | OrgDisableSamlAuditEntry | OrgDisableTwoFactorRequirementAuditEntry | OrgEnableOauthAppRestrictionsAuditEntry | OrgEnableSamlAuditEntry | OrgEnableTwoFactorRequirementAuditEntry | OrgInviteMemberAuditEntry | OrgInviteToBusinessAuditEntry | OrgOauthAppAccessApprovedAuditEntry | OrgOauthAppAccessDeniedAuditEntry | OrgOauthAppAccessRequestedAuditEntry | OrgRemoveBillingManagerAuditEntry | OrgRemoveMemberAuditEntry | OrgRemoveOutsideCollaboratorAuditEntry | OrgRestoreMemberAuditEntry | OrgUnblockUserAuditEntry | OrgUpdateDefaultRepositoryPermissionAuditEntry | OrgUpdateMemberAuditEntry | OrgUpdateMemberRepositoryCreationPermissionAuditEntry | OrgUpdateMemberRepositoryInvitationPermissionAuditEntry | PrivateRepositoryForkingDisableAuditEntry | PrivateRepositoryForkingEnableAuditEntry | RepoAccessAuditEntry | RepoAddMemberAuditEntry | RepoAddTopicAuditEntry | RepoArchivedAuditEntry | RepoChangeMergeSettingAuditEntry | RepoConfigDisableAnonymousGitAccessAuditEntry | RepoConfigDisableCollaboratorsOnlyAuditEntry | RepoConfigDisableContributorsOnlyAuditEntry | RepoConfigDisableSockpuppetDisallowedAuditEntry | RepoConfigEnableAnonymousGitAccessAuditEntry | RepoConfigEnableCollaboratorsOnlyAuditEntry | RepoConfigEnableContributorsOnlyAuditEntry | RepoConfigEnableSockpuppetDisallowedAuditEntry | RepoConfigLockAnonymousGitAccessAuditEntry | RepoConfigUnlockAnonymousGitAccessAuditEntry | RepoCreateAuditEntry | RepoDestroyAuditEntry | RepoRemoveMemberAuditEntry | RepoRemoveTopicAuditEntry | RepositoryVisibilityChangeDisableAuditEntry | RepositoryVisibilityChangeEnableAuditEntry | TeamAddMemberAuditEntry | TeamAddRepositoryAuditEntry | TeamChangeParentTeamAuditEntry | TeamRemoveMemberAuditEntry | TeamRemoveRepositoryAuditEntry - -""" -The connection type for OrganizationAuditEntry. -""" -type OrganizationAuditEntryConnection { - """ - A list of edges. - """ - edges: [OrganizationAuditEntryEdge] - - """ - A list of nodes. - """ - nodes: [OrganizationAuditEntry] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Metadata for an audit entry with action org.* -""" -interface OrganizationAuditEntryData { - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI -} - -""" -An edge in a connection. -""" -type OrganizationAuditEntryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: OrganizationAuditEntry -} - -""" -The connection type for Organization. -""" -type OrganizationConnection { - """ - A list of edges. - """ - edges: [OrganizationEdge] - - """ - A list of nodes. - """ - nodes: [Organization] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type OrganizationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Organization -} - -""" -An Identity Provider configured to provision SAML and SCIM identities for Organizations -""" -type OrganizationIdentityProvider implements Node { - """ - The digest algorithm used to sign SAML requests for the Identity Provider. - """ - digestMethod: URI - - """ - External Identities provisioned by this Identity Provider - """ - externalIdentities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ExternalIdentityConnection! - id: ID! - - """ - The x509 certificate used by the Identity Provider to sign assertions and responses. - """ - idpCertificate: X509Certificate - - """ - The Issuer Entity ID for the SAML Identity Provider - """ - issuer: String - - """ - Organization this Identity Provider belongs to - """ - organization: Organization - - """ - The signature algorithm used to sign SAML requests for the Identity Provider. - """ - signatureMethod: URI - - """ - The URL endpoint for the Identity Provider's SAML SSO. - """ - ssoUrl: URI -} - -""" -An Invitation for a user to an organization. -""" -type OrganizationInvitation implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The email address of the user invited to the organization. - """ - email: String - id: ID! - - """ - The type of invitation that was sent (e.g. email, user). - """ - invitationType: OrganizationInvitationType! - - """ - The user who was invited to the organization. - """ - invitee: User - - """ - The user who created the invitation. - """ - inviter: User! - - """ - The organization the invite is for - """ - organization: Organization! - - """ - The user's pending role in the organization (e.g. member, owner). - """ - role: OrganizationInvitationRole! -} - -""" -The connection type for OrganizationInvitation. -""" -type OrganizationInvitationConnection { - """ - A list of edges. - """ - edges: [OrganizationInvitationEdge] - - """ - A list of nodes. - """ - nodes: [OrganizationInvitation] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type OrganizationInvitationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: OrganizationInvitation -} - -""" -The possible organization invitation roles. -""" -enum OrganizationInvitationRole { - """ - The user is invited to be an admin of the organization. - """ - ADMIN - - """ - The user is invited to be a billing manager of the organization. - """ - BILLING_MANAGER - - """ - The user is invited to be a direct member of the organization. - """ - DIRECT_MEMBER - - """ - The user's previous role will be reinstated. - """ - REINSTATE -} - -""" -The possible organization invitation types. -""" -enum OrganizationInvitationType { - """ - The invitation was to an email address. - """ - EMAIL - - """ - The invitation was to an existing user. - """ - USER -} - -""" -The connection type for User. -""" -type OrganizationMemberConnection { - """ - A list of edges. - """ - edges: [OrganizationMemberEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user within an organization. -""" -type OrganizationMemberEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - Whether the organization member has two factor enabled or not. Returns null if information is not available to viewer. - """ - hasTwoFactorEnabled: Boolean - - """ - The item at the end of the edge. - """ - node: User - - """ - The role this user has in the organization. - """ - role: OrganizationMemberRole -} - -""" -The possible roles within an organization for its members. -""" -enum OrganizationMemberRole { - """ - The user is an administrator of the organization. - """ - ADMIN - - """ - The user is a member of the organization. - """ - MEMBER -} - -""" -Information about pagination in a connection. -""" -type PageInfo { - """ - When paginating forwards, the cursor to continue. - """ - endCursor: String - - """ - When paginating forwards, are there more items? - """ - hasNextPage: Boolean! - - """ - When paginating backwards, are there more items? - """ - hasPreviousPage: Boolean! - - """ - When paginating backwards, the cursor to continue. - """ - startCursor: String -} - -""" -Represents a pending collaborator on a repository. -""" -type PendingCollaboratorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User -} - -""" -Types that can grant permissions on a repository to a user -""" -union PermissionGranter = Organization | Repository | Team - -""" -A level of permission and source for a user's access to a repository. -""" -type PermissionSource { - """ - The organization the repository belongs to. - """ - organization: Organization! - - """ - The level of access this source has granted to the user. - """ - permission: DefaultRepositoryPermissionField! - - """ - The source of this permission. - """ - source: PermissionGranter! -} - -""" -Autogenerated input type of PinIssue -""" -input PinIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the issue to be pinned - """ - issueId: ID! -} - -""" -Types that can be pinned to a profile page. -""" -union PinnableItem = Gist | Repository - -""" -The connection type for PinnableItem. -""" -type PinnableItemConnection { - """ - A list of edges. - """ - edges: [PinnableItemEdge] - - """ - A list of nodes. - """ - nodes: [PinnableItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PinnableItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PinnableItem -} - -""" -Represents items that can be pinned to a profile page or dashboard. -""" -enum PinnableItemType { - """ - A gist. - """ - GIST - - """ - An issue. - """ - ISSUE - - """ - An organization. - """ - ORGANIZATION - - """ - A project. - """ - PROJECT - - """ - A pull request. - """ - PULL_REQUEST - - """ - A repository. - """ - REPOSITORY - - """ - A team. - """ - TEAM - - """ - A user. - """ - USER -} - -""" -Represents a 'pinned' event on a given issue or pull request. -""" -type PinnedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the issue associated with the event. - """ - issue: Issue! -} - -""" -An ISO-8601 encoded UTC date string with millisecond precision. -""" -scalar PreciseDateTime - -""" -Audit log entry for a private_repository_forking.disable event. -""" -type PrivateRepositoryForkingDisableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a private_repository_forking.enable event. -""" -type PrivateRepositoryForkingEnableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -A curatable list of repositories relating to a repository owner, which defaults -to showing the most popular repositories they own. -""" -type ProfileItemShowcase { - """ - Whether or not the owner has pinned any repositories or gists. - """ - hasPinnedItems: Boolean! - - """ - The repositories and gists in the showcase. If the profile owner has any - pinned items, those will be returned. Otherwise, the profile owner's popular - repositories will be returned. - """ - items( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PinnableItemConnection! -} - -""" -Represents any entity on GitHub that has a profile page. -""" -interface ProfileOwner { - """ - Determine if this repository owner has any items that can be pinned to their profile. - """ - anyPinnableItems( - """ - Filter to only a particular kind of pinnable item. - """ - type: PinnableItemType - ): Boolean! - - """ - The public profile email. - """ - email: String - id: ID! - - """ - Showcases a selection of repositories and gists that the profile owner has - either curated or that have been selected automatically based on popularity. - """ - itemShowcase: ProfileItemShowcase! - - """ - The public profile location. - """ - location: String - - """ - The username used to login. - """ - login: String! - - """ - The public profile name. - """ - name: String - - """ - A list of repositories and gists this profile owner can pin to their profile. - """ - pinnableItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinnable items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - A list of repositories and gists this profile owner has pinned to their profile - """ - pinnedItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinned items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - Returns how many more items this profile owner can pin to their profile. - """ - pinnedItemsRemaining: Int! - - """ - Can the viewer pin repositories and gists to the profile? - """ - viewerCanChangePinnedItems: Boolean! - - """ - The public profile website URL. - """ - websiteUrl: URI -} - -""" -Projects manage issues, pull requests and notes within a project owner. -""" -type Project implements Closable & Node & Updatable { - """ - The project's description body. - """ - body: String - - """ - The projects description body rendered to HTML. - """ - bodyHTML: HTML! - - """ - `true` if the object is closed (definition of closed may depend on type) - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - List of columns in the project - """ - columns( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectColumnConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The actor who originally created the project. - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The project's name. - """ - name: String! - - """ - The project's number. - """ - number: Int! - - """ - The project's owner. Currently limited to repositories, organizations, and users. - """ - owner: ProjectOwner! - - """ - List of pending cards in this project - """ - pendingCards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - The HTTP path for this project - """ - resourcePath: URI! - - """ - Whether the project is open or closed. - """ - state: ProjectState! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this project - """ - url: URI! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! -} - -""" -A card in a project. -""" -type ProjectCard implements Node { - """ - The project column this card is associated under. A card may only belong to one - project column at a time. The column field will be null if the card is created - in a pending state and has yet to be associated with a column. Once cards are - associated with a column, they will not become pending in the future. - """ - column: ProjectColumn - - """ - The card content item - """ - content: ProjectCardItem - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The actor who created this card - """ - creator: Actor - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Whether the card is archived - """ - isArchived: Boolean! - - """ - The card note - """ - note: String - - """ - The project that contains this card. - """ - project: Project! - - """ - The HTTP path for this card - """ - resourcePath: URI! - - """ - The state of ProjectCard - """ - state: ProjectCardState - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this card - """ - url: URI! -} - -""" -The possible archived states of a project card. -""" -enum ProjectCardArchivedState { - """ - A project card that is archived - """ - ARCHIVED - - """ - A project card that is not archived - """ - NOT_ARCHIVED -} - -""" -The connection type for ProjectCard. -""" -type ProjectCardConnection { - """ - A list of edges. - """ - edges: [ProjectCardEdge] - - """ - A list of nodes. - """ - nodes: [ProjectCard] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ProjectCardEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ProjectCard -} - -""" -An issue or PR and its owning repository to be used in a project card. -""" -input ProjectCardImport { - """ - The issue or pull request number. - """ - number: Int! - - """ - Repository name with owner (owner/repository). - """ - repository: String! -} - -""" -Types that can be inside Project Cards. -""" -union ProjectCardItem = Issue | PullRequest - -""" -Various content states of a ProjectCard -""" -enum ProjectCardState { - """ - The card has content only. - """ - CONTENT_ONLY - - """ - The card has a note only. - """ - NOTE_ONLY - - """ - The card is redacted. - """ - REDACTED -} - -""" -A column inside a project. -""" -type ProjectColumn implements Node { - """ - List of cards in the column - """ - cards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The project column's name. - """ - name: String! - - """ - The project that contains this column. - """ - project: Project! - - """ - The semantic purpose of the column - """ - purpose: ProjectColumnPurpose - - """ - The HTTP path for this project column - """ - resourcePath: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this project column - """ - url: URI! -} - -""" -The connection type for ProjectColumn. -""" -type ProjectColumnConnection { - """ - A list of edges. - """ - edges: [ProjectColumnEdge] - - """ - A list of nodes. - """ - nodes: [ProjectColumn] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ProjectColumnEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ProjectColumn -} - -""" -A project column and a list of its issues and PRs. -""" -input ProjectColumnImport { - """ - The name of the column. - """ - columnName: String! - - """ - A list of issues and pull requests in the column. - """ - issues: [ProjectCardImport!] - - """ - The position of the column, starting from 0. - """ - position: Int! -} - -""" -The semantic purpose of the column - todo, in progress, or done. -""" -enum ProjectColumnPurpose { - """ - The column contains cards which are complete - """ - DONE - - """ - The column contains cards which are currently being worked on - """ - IN_PROGRESS - - """ - The column contains cards still to be worked on - """ - TODO -} - -""" -A list of projects associated with the owner. -""" -type ProjectConnection { - """ - A list of edges. - """ - edges: [ProjectEdge] - - """ - A list of nodes. - """ - nodes: [Project] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ProjectEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Project -} - -""" -Ways in which lists of projects can be ordered upon return. -""" -input ProjectOrder { - """ - The direction in which to order projects by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order projects by. - """ - field: ProjectOrderField! -} - -""" -Properties by which project connections can be ordered. -""" -enum ProjectOrderField { - """ - Order projects by creation time - """ - CREATED_AT - - """ - Order projects by name - """ - NAME - - """ - Order projects by update time - """ - UPDATED_AT -} - -""" -Represents an owner of a Project. -""" -interface ProjectOwner { - id: ID! - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing owners projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing owners projects - """ - projectsUrl: URI! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! -} - -""" -State of the project; either 'open' or 'closed' -""" -enum ProjectState { - """ - The project is closed. - """ - CLOSED - - """ - The project is open. - """ - OPEN -} - -""" -Represents a connection between a project (parent) and a team (child). -""" -type ProjectTeamEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Team - - """ - The HTTP path for this project's team - """ - projectTeamResourcePath: URI! - - """ - The HTTP URL for this project's team - """ - projectTeamUrl: URI! -} - -""" -GitHub-provided templates for Projects -""" -enum ProjectTemplate { - """ - Create a board with v2 triggers to automatically move cards across To do, In progress and Done columns. - """ - AUTOMATED_KANBAN_V2 - - """ - Create a board with triggers to automatically move cards across columns with review automation. - """ - AUTOMATED_REVIEWS_KANBAN - - """ - Create a board with columns for To do, In progress and Done. - """ - BASIC_KANBAN - - """ - Create a board to triage and prioritize bugs with To do, priority, and Done columns. - """ - BUG_TRIAGE -} - -""" -Represents a user project. -""" -type ProjectUserEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User -} - -""" -A user's public key. -""" -type PublicKey implements Node { - """ - The last time this authorization was used to perform an action. Values will be null for keys not owned by the user. - """ - accessedAt: DateTime - - """ - Identifies the date and time when the key was created. Keys created before - March 5th, 2014 have inaccurate values. Values will be null for keys not owned by the user. - """ - createdAt: DateTime - - """ - The fingerprint for this PublicKey. - """ - fingerprint: String! - id: ID! - - """ - Whether this PublicKey is read-only or not. Values will be null for keys not owned by the user. - """ - isReadOnly: Boolean - - """ - The public key string. - """ - key: String! - - """ - Identifies the date and time when the key was updated. Keys created before - March 5th, 2014 may have inaccurate values. Values will be null for keys not - owned by the user. - """ - updatedAt: DateTime -} - -""" -The connection type for PublicKey. -""" -type PublicKeyConnection { - """ - A list of edges. - """ - edges: [PublicKeyEdge] - - """ - A list of nodes. - """ - nodes: [PublicKey] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PublicKeyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PublicKey -} - -""" -A repository pull request. -""" -type PullRequest implements Assignable & Closable & Comment & Labelable & Lockable & Node & Reactable & RepositoryNode & Subscribable & UniformResourceLocatable & Updatable & UpdatableComment { - """ - Reason that the conversation was locked. - """ - activeLockReason: LockReason - - """ - The number of additions in this pull request. - """ - additions: Int! - - """ - A list of Users assigned to this object. - """ - assignees( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the base Ref associated with the pull request. - """ - baseRef: Ref - - """ - Identifies the name of the base Ref associated with the pull request, even if the ref has been deleted. - """ - baseRefName: String! - - """ - Identifies the oid of the base ref associated with the pull request, even if the ref has been deleted. - """ - baseRefOid: GitObjectID! - - """ - The repository associated with this pull request's base Ref. - """ - baseRepository: Repository - - """ - The body as Markdown. - """ - body: String! - - """ - The body rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body rendered to text. - """ - bodyText: String! - - """ - The number of changed files in this pull request. - """ - changedFiles: Int! - - """ - `true` if the pull request is closed - """ - closed: Boolean! - - """ - Identifies the date and time when the object was closed. - """ - closedAt: DateTime - - """ - A list of comments associated with the pull request. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): IssueCommentConnection! - - """ - A list of commits present in this pull request's head branch not present in the base branch. - """ - commits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestCommitConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The number of deletions in this pull request. - """ - deletions: Int! - - """ - The actor who edited this pull request's body. - """ - editor: Actor - - """ - Lists the files changed within this pull request. - """ - files( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestChangedFileConnection - - """ - Identifies the head Ref associated with the pull request. - """ - headRef: Ref - - """ - Identifies the name of the head Ref associated with the pull request, even if the ref has been deleted. - """ - headRefName: String! - - """ - Identifies the oid of the head ref associated with the pull request, even if the ref has been deleted. - """ - headRefOid: GitObjectID! - - """ - The repository associated with this pull request's head Ref. - """ - headRepository: Repository - - """ - The owner of the repository associated with this pull request's head Ref. - """ - headRepositoryOwner: RepositoryOwner - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The head and base repositories are different. - """ - isCrossRepository: Boolean! - - """ - A list of labels associated with the object. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): LabelConnection - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - `true` if the pull request is locked - """ - locked: Boolean! - - """ - Indicates whether maintainers can modify the pull request. - """ - maintainerCanModify: Boolean! - - """ - The commit that was created when this pull request was merged. - """ - mergeCommit: Commit - - """ - Whether or not the pull request can be merged based on the existence of merge conflicts. - """ - mergeable: MergeableState! - - """ - Whether or not the pull request was merged. - """ - merged: Boolean! - - """ - The date and time that the pull request was merged. - """ - mergedAt: DateTime - - """ - The actor who merged the pull request. - """ - mergedBy: Actor - - """ - Identifies the milestone associated with the pull request. - """ - milestone: Milestone - - """ - Identifies the pull request number. - """ - number: Int! - - """ - A list of Users that are participating in the Pull Request conversation. - """ - participants( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - The permalink to the pull request. - """ - permalink: URI! - - """ - The commit that GitHub automatically generated to test if this pull request - could be merged. This field will not return a value if the pull request is - merged, or if the test merge commit is still being generated. See the - `mergeable` field for more details on the mergeability of the pull request. - """ - potentialMergeCommit: Commit - - """ - List of project cards associated with this pull request. - """ - projectCards( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - A list of archived states to filter the cards by - """ - archivedStates: [ProjectCardArchivedState] = [ARCHIVED, NOT_ARCHIVED] - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ProjectCardConnection! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path for this pull request. - """ - resourcePath: URI! - - """ - The HTTP path for reverting this pull request. - """ - revertResourcePath: URI! - - """ - The HTTP URL for reverting this pull request. - """ - revertUrl: URI! - - """ - A list of review requests associated with the pull request. - """ - reviewRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ReviewRequestConnection - - """ - The list of all review threads for this pull request. - """ - reviewThreads( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestReviewThreadConnection! - - """ - A list of reviews associated with the pull request. - """ - reviews( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Filter by author of the review. - """ - author: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - A list of states to filter the reviews. - """ - states: [PullRequestReviewState!] - ): PullRequestReviewConnection - - """ - Identifies the state of the pull request. - """ - state: PullRequestState! - - """ - A list of reviewer suggestions based on commit history and past review comments. - """ - suggestedReviewers: [SuggestedReviewer]! - - """ - A list of events, comments, commits, etc. associated with the pull request. - """ - timeline( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows filtering timeline events by a `since` timestamp. - """ - since: DateTime - ): PullRequestTimelineConnection! @deprecated(reason: "`timeline` will be removed Use PullRequest.timelineItems instead. Removal on 2019-10-01 UTC.") - - """ - A list of events, comments, commits, etc. associated with the pull request. - """ - timelineItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Filter timeline items by type. - """ - itemTypes: [PullRequestTimelineItemsItemType!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter timeline items by a `since` timestamp. - """ - since: DateTime - - """ - Skips the first _n_ elements in the list. - """ - skip: Int - ): PullRequestTimelineItemsConnection! - - """ - Identifies the pull request title. - """ - title: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this pull request. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Whether or not the viewer can apply suggestion. - """ - viewerCanApplySuggestion: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -A file changed in a pull request. -""" -type PullRequestChangedFile { - """ - The number of additions to the file. - """ - additions: Int! - - """ - The number of deletions to the file. - """ - deletions: Int! - - """ - The path of the file. - """ - path: String! -} - -""" -The connection type for PullRequestChangedFile. -""" -type PullRequestChangedFileConnection { - """ - A list of edges. - """ - edges: [PullRequestChangedFileEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestChangedFile] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestChangedFileEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestChangedFile -} - -""" -Represents a Git commit part of a pull request. -""" -type PullRequestCommit implements Node & UniformResourceLocatable { - """ - The Git commit object - """ - commit: Commit! - id: ID! - - """ - The pull request this commit belongs to - """ - pullRequest: PullRequest! - - """ - The HTTP path for this pull request commit - """ - resourcePath: URI! - - """ - The HTTP URL for this pull request commit - """ - url: URI! -} - -""" -Represents a commit comment thread part of a pull request. -""" -type PullRequestCommitCommentThread implements Node & RepositoryNode { - """ - The comments that exist in this thread. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The commit the comments were made on. - """ - commit: Commit! - id: ID! - - """ - The file the comments were made on. - """ - path: String - - """ - The position in the diff for the commit that the comment was made on. - """ - position: Int - - """ - The pull request this commit comment thread belongs to - """ - pullRequest: PullRequest! - - """ - The repository associated with this node. - """ - repository: Repository! -} - -""" -The connection type for PullRequestCommit. -""" -type PullRequestCommitConnection { - """ - A list of edges. - """ - edges: [PullRequestCommitEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestCommit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestCommitEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestCommit -} - -""" -The connection type for PullRequest. -""" -type PullRequestConnection { - """ - A list of edges. - """ - edges: [PullRequestEdge] - - """ - A list of nodes. - """ - nodes: [PullRequest] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -This aggregates pull requests opened by a user within one repository. -""" -type PullRequestContributionsByRepository { - """ - The pull request contributions. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedPullRequestContributionConnection! - - """ - The repository in which the pull requests were opened. - """ - repository: Repository! -} - -""" -An edge in a connection. -""" -type PullRequestEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequest -} - -""" -Ways in which lists of issues can be ordered upon return. -""" -input PullRequestOrder { - """ - The direction in which to order pull requests by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order pull requests by. - """ - field: PullRequestOrderField! -} - -""" -Properties by which pull_requests connections can be ordered. -""" -enum PullRequestOrderField { - """ - Order pull_requests by creation time - """ - CREATED_AT - - """ - Order pull_requests by update time - """ - UPDATED_AT -} - -""" -The possible PubSub channels for a pull request. -""" -enum PullRequestPubSubTopic { - """ - The channel ID for observing head ref updates. - """ - HEAD_REF - - """ - The channel ID for marking an pull request as read. - """ - MARKASREAD - - """ - The channel ID for observing pull request state updates. - """ - STATE - - """ - The channel ID for updating items on the pull request timeline. - """ - TIMELINE - - """ - The channel ID for observing pull request updates. - """ - UPDATED -} - -""" -A review object for a given pull request. -""" -type PullRequestReview implements Comment & Deletable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - Identifies the pull request review body. - """ - body: String! - - """ - The body of this review rendered to HTML. - """ - bodyHTML: HTML! - - """ - The body of this review rendered as plain text. - """ - bodyText: String! - - """ - A list of review comments for the current pull request review. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestReviewCommentConnection! - - """ - Identifies the commit associated with this pull request review. - """ - commit: Commit - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - A list of teams that this review was made on behalf of. - """ - onBehalfOf( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): TeamConnection! - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - Identifies the pull request associated with this pull request review. - """ - pullRequest: PullRequest! - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path permalink for this PullRequestReview. - """ - resourcePath: URI! - - """ - Identifies the current state of the pull request review. - """ - state: PullRequestReviewState! - - """ - Identifies when the Pull Request Review was submitted - """ - submittedAt: DateTime - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL permalink for this PullRequestReview. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -A review comment associated with a given repository pull request. -""" -type PullRequestReviewComment implements Comment & Deletable & Node & Reactable & RepositoryNode & Updatable & UpdatableComment { - """ - The actor who authored the comment. - """ - author: Actor - - """ - Author's association with the subject of the comment. - """ - authorAssociation: CommentAuthorAssociation! - - """ - The comment body of this review comment. - """ - body: String! - - """ - The comment body of this review comment rendered to HTML. - """ - bodyHTML: HTML! - - """ - The comment body of this review comment rendered as plain text. - """ - bodyText: String! - - """ - Identifies the commit associated with the comment. - """ - commit: Commit! - - """ - Identifies when the comment was created. - """ - createdAt: DateTime! - - """ - Check if this comment was created via an email reply. - """ - createdViaEmail: Boolean! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The diff hunk to which the comment applies. - """ - diffHunk: String! - - """ - Identifies when the comment was created in a draft state. - """ - draftedAt: DateTime! - - """ - The actor who edited the comment. - """ - editor: Actor - id: ID! - - """ - Check if this comment was edited and includes an edit with the creation data - """ - includesCreatedEdit: Boolean! - - """ - Returns whether or not a comment has been minimized. - """ - isMinimized: Boolean! - - """ - The moment the editor made the last edit - """ - lastEditedAt: DateTime - - """ - Returns why the comment was minimized. - """ - minimizedReason: String - - """ - Identifies the original commit associated with the comment. - """ - originalCommit: Commit - - """ - The original line index in the diff to which the comment applies. - """ - originalPosition: Int! - - """ - Identifies when the comment body is outdated - """ - outdated: Boolean! - - """ - The path to which the comment applies. - """ - path: String! - - """ - The line index in the diff to which the comment applies. - """ - position: Int - - """ - Identifies when the comment was published at. - """ - publishedAt: DateTime - - """ - The pull request associated with this review comment. - """ - pullRequest: PullRequest! - - """ - The pull request review associated with this review comment. - """ - pullRequestReview: PullRequestReview - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - The comment this is a reply to. - """ - replyTo: PullRequestReviewComment - - """ - The repository associated with this node. - """ - repository: Repository! - - """ - The HTTP path permalink for this review comment. - """ - resourcePath: URI! - - """ - Identifies the state of the comment. - """ - state: PullRequestReviewCommentState! - - """ - Identifies when the comment was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL permalink for this review comment. - """ - url: URI! - - """ - A list of edits to this content. - """ - userContentEdits( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserContentEditConnection - - """ - Check if the current viewer can delete this object. - """ - viewerCanDelete: Boolean! - - """ - Check if the current viewer can minimize this object. - """ - viewerCanMinimize: Boolean! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! - - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! - - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! - - """ - Did the viewer author this comment. - """ - viewerDidAuthor: Boolean! -} - -""" -The connection type for PullRequestReviewComment. -""" -type PullRequestReviewCommentConnection { - """ - A list of edges. - """ - edges: [PullRequestReviewCommentEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestReviewComment] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestReviewCommentEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestReviewComment -} - -""" -The possible states of a pull request review comment. -""" -enum PullRequestReviewCommentState { - """ - A comment that is part of a pending review - """ - PENDING - - """ - A comment that is part of a submitted review - """ - SUBMITTED -} - -""" -The connection type for PullRequestReview. -""" -type PullRequestReviewConnection { - """ - A list of edges. - """ - edges: [PullRequestReviewEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestReview] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -This aggregates pull request reviews made by a user within one repository. -""" -type PullRequestReviewContributionsByRepository { - """ - The pull request review contributions. - """ - contributions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for contributions returned from the connection. - """ - orderBy: ContributionOrder = {field: OCCURRED_AT, direction: DESC} - ): CreatedPullRequestReviewContributionConnection! - - """ - The repository in which the pull request reviews were made. - """ - repository: Repository! -} - -""" -An edge in a connection. -""" -type PullRequestReviewEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestReview -} - -""" -The possible events to perform on a pull request review. -""" -enum PullRequestReviewEvent { - """ - Submit feedback and approve merging these changes. - """ - APPROVE - - """ - Submit general feedback without explicit approval. - """ - COMMENT - - """ - Dismiss review so it now longer effects merging. - """ - DISMISS - - """ - Submit feedback that must be addressed before merging. - """ - REQUEST_CHANGES -} - -""" -The possible states of a pull request review. -""" -enum PullRequestReviewState { - """ - A review allowing the pull request to merge. - """ - APPROVED - - """ - A review blocking the pull request from merging. - """ - CHANGES_REQUESTED - - """ - An informational review. - """ - COMMENTED - - """ - A review that has been dismissed. - """ - DISMISSED - - """ - A review that has not yet been submitted. - """ - PENDING -} - -""" -A threaded list of comments for a given pull request. -""" -type PullRequestReviewThread implements Node { - """ - A list of pull request comments associated with the thread. - """ - comments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PullRequestReviewCommentConnection! - id: ID! - - """ - Whether this thread has been resolved - """ - isResolved: Boolean! - - """ - Identifies the pull request associated with this thread. - """ - pullRequest: PullRequest! - - """ - Identifies the repository associated with this thread. - """ - repository: Repository! - - """ - The user who resolved this thread - """ - resolvedBy: User - - """ - Whether or not the viewer can resolve this thread - """ - viewerCanResolve: Boolean! - - """ - Whether or not the viewer can unresolve this thread - """ - viewerCanUnresolve: Boolean! -} - -""" -Review comment threads for a pull request review. -""" -type PullRequestReviewThreadConnection { - """ - A list of edges. - """ - edges: [PullRequestReviewThreadEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestReviewThread] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PullRequestReviewThreadEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestReviewThread -} - -""" -Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. -""" -type PullRequestRevisionMarker { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The last commit the viewer has seen. - """ - lastSeenCommit: Commit! - - """ - The pull request to which the marker belongs. - """ - pullRequest: PullRequest! -} - -""" -The possible states of a pull request. -""" -enum PullRequestState { - """ - A pull request that has been closed without being merged. - """ - CLOSED - - """ - A pull request that has been closed by being merged. - """ - MERGED - - """ - A pull request that is still open. - """ - OPEN -} - -""" -The connection type for PullRequestTimelineItem. -""" -type PullRequestTimelineConnection { - """ - A list of edges. - """ - edges: [PullRequestTimelineItemEdge] - - """ - A list of nodes. - """ - nodes: [PullRequestTimelineItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An item in an pull request timeline -""" -union PullRequestTimelineItem = AssignedEvent | BaseRefForcePushedEvent | ClosedEvent | Commit | CommitCommentThread | CrossReferencedEvent | DemilestonedEvent | DeployedEvent | DeploymentEnvironmentChangedEvent | HeadRefDeletedEvent | HeadRefForcePushedEvent | HeadRefRestoredEvent | IssueComment | LabeledEvent | LockedEvent | MergedEvent | MilestonedEvent | PullRequestReview | PullRequestReviewComment | PullRequestReviewThread | ReferencedEvent | RenamedTitleEvent | ReopenedEvent | ReviewDismissedEvent | ReviewRequestRemovedEvent | ReviewRequestedEvent | SubscribedEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -An edge in a connection. -""" -type PullRequestTimelineItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestTimelineItem -} - -""" -An item in a pull request timeline -""" -union PullRequestTimelineItems = AddedToProjectEvent | AssignedEvent | BaseRefChangedEvent | BaseRefForcePushedEvent | ClosedEvent | CommentDeletedEvent | ConvertedNoteToIssueEvent | CrossReferencedEvent | DemilestonedEvent | DeployedEvent | DeploymentEnvironmentChangedEvent | HeadRefDeletedEvent | HeadRefForcePushedEvent | HeadRefRestoredEvent | IssueComment | LabeledEvent | LockedEvent | MarkedAsDuplicateEvent | MentionedEvent | MergedEvent | MilestonedEvent | MovedColumnsInProjectEvent | PinnedEvent | PullRequestCommit | PullRequestCommitCommentThread | PullRequestReview | PullRequestReviewThread | PullRequestRevisionMarker | ReadyForReviewEvent | ReferencedEvent | RemovedFromProjectEvent | RenamedTitleEvent | ReopenedEvent | ReviewDismissedEvent | ReviewRequestRemovedEvent | ReviewRequestedEvent | SubscribedEvent | TransferredEvent | UnassignedEvent | UnlabeledEvent | UnlockedEvent | UnpinnedEvent | UnsubscribedEvent | UserBlockedEvent - -""" -The connection type for PullRequestTimelineItems. -""" -type PullRequestTimelineItemsConnection { - """ - A list of edges. - """ - edges: [PullRequestTimelineItemsEdge] - - """ - Identifies the count of items after applying `before` and `after` filters. - """ - filteredCount: Int! - - """ - A list of nodes. - """ - nodes: [PullRequestTimelineItems] - - """ - Identifies the count of items after applying `before`/`after` filters and `first`/`last`/`skip` slicing. - """ - pageCount: Int! - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Identifies the date and time when the timeline was last updated. - """ - updatedAt: DateTime! -} - -""" -An edge in a connection. -""" -type PullRequestTimelineItemsEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PullRequestTimelineItems -} - -""" -The possible item types found in a timeline. -""" -enum PullRequestTimelineItemsItemType { - """ - Represents a 'added_to_project' event on a given issue or pull request. - """ - ADDED_TO_PROJECT_EVENT - - """ - Represents an 'assigned' event on any assignable object. - """ - ASSIGNED_EVENT - - """ - Represents a 'base_ref_changed' event on a given issue or pull request. - """ - BASE_REF_CHANGED_EVENT - - """ - Represents a 'base_ref_force_pushed' event on a given pull request. - """ - BASE_REF_FORCE_PUSHED_EVENT - - """ - Represents a 'closed' event on any `Closable`. - """ - CLOSED_EVENT - - """ - Represents a 'comment_deleted' event on a given issue or pull request. - """ - COMMENT_DELETED_EVENT - - """ - Represents a 'converted_note_to_issue' event on a given issue or pull request. - """ - CONVERTED_NOTE_TO_ISSUE_EVENT - - """ - Represents a mention made by one issue or pull request to another. - """ - CROSS_REFERENCED_EVENT - - """ - Represents a 'demilestoned' event on a given issue or pull request. - """ - DEMILESTONED_EVENT - - """ - Represents a 'deployed' event on a given pull request. - """ - DEPLOYED_EVENT - - """ - Represents a 'deployment_environment_changed' event on a given pull request. - """ - DEPLOYMENT_ENVIRONMENT_CHANGED_EVENT - - """ - Represents a 'head_ref_deleted' event on a given pull request. - """ - HEAD_REF_DELETED_EVENT - - """ - Represents a 'head_ref_force_pushed' event on a given pull request. - """ - HEAD_REF_FORCE_PUSHED_EVENT - - """ - Represents a 'head_ref_restored' event on a given pull request. - """ - HEAD_REF_RESTORED_EVENT - - """ - Represents a comment on an Issue. - """ - ISSUE_COMMENT - - """ - Represents a 'labeled' event on a given issue or pull request. - """ - LABELED_EVENT - - """ - Represents a 'locked' event on a given issue or pull request. - """ - LOCKED_EVENT - - """ - Represents a 'marked_as_duplicate' event on a given issue or pull request. - """ - MARKED_AS_DUPLICATE_EVENT - - """ - Represents a 'mentioned' event on a given issue or pull request. - """ - MENTIONED_EVENT - - """ - Represents a 'merged' event on a given pull request. - """ - MERGED_EVENT - - """ - Represents a 'milestoned' event on a given issue or pull request. - """ - MILESTONED_EVENT - - """ - Represents a 'moved_columns_in_project' event on a given issue or pull request. - """ - MOVED_COLUMNS_IN_PROJECT_EVENT - - """ - Represents a 'pinned' event on a given issue or pull request. - """ - PINNED_EVENT - - """ - Represents a Git commit part of a pull request. - """ - PULL_REQUEST_COMMIT - - """ - Represents a commit comment thread part of a pull request. - """ - PULL_REQUEST_COMMIT_COMMENT_THREAD - - """ - A review object for a given pull request. - """ - PULL_REQUEST_REVIEW - - """ - A threaded list of comments for a given pull request. - """ - PULL_REQUEST_REVIEW_THREAD - - """ - Represents the latest point in the pull request timeline for which the viewer has seen the pull request's commits. - """ - PULL_REQUEST_REVISION_MARKER - - """ - Represents a 'ready_for_review' event on a given pull request. - """ - READY_FOR_REVIEW_EVENT - - """ - Represents a 'referenced' event on a given `ReferencedSubject`. - """ - REFERENCED_EVENT - - """ - Represents a 'removed_from_project' event on a given issue or pull request. - """ - REMOVED_FROM_PROJECT_EVENT - - """ - Represents a 'renamed' event on a given issue or pull request - """ - RENAMED_TITLE_EVENT - - """ - Represents a 'reopened' event on any `Closable`. - """ - REOPENED_EVENT - - """ - Represents a 'review_dismissed' event on a given issue or pull request. - """ - REVIEW_DISMISSED_EVENT - - """ - Represents an 'review_requested' event on a given pull request. - """ - REVIEW_REQUESTED_EVENT - - """ - Represents an 'review_request_removed' event on a given pull request. - """ - REVIEW_REQUEST_REMOVED_EVENT - - """ - Represents a 'subscribed' event on a given `Subscribable`. - """ - SUBSCRIBED_EVENT - - """ - Represents a 'transferred' event on a given issue or pull request. - """ - TRANSFERRED_EVENT - - """ - Represents an 'unassigned' event on any assignable object. - """ - UNASSIGNED_EVENT - - """ - Represents an 'unlabeled' event on a given issue or pull request. - """ - UNLABELED_EVENT - - """ - Represents an 'unlocked' event on a given issue or pull request. - """ - UNLOCKED_EVENT - - """ - Represents an 'unpinned' event on a given issue or pull request. - """ - UNPINNED_EVENT - - """ - Represents an 'unsubscribed' event on a given `Subscribable`. - """ - UNSUBSCRIBED_EVENT - - """ - Represents a 'user_blocked' event on a given user. - """ - USER_BLOCKED_EVENT -} - -""" -A team, user or app who has the ability to push to a protected branch. -""" -type PushAllowance implements Node { - """ - The actor that can push. - """ - actor: PushAllowanceActor - - """ - Identifies the branch protection rule associated with the allowed user or team. - """ - branchProtectionRule: BranchProtectionRule - id: ID! -} - -""" -Types that can be an actor. -""" -union PushAllowanceActor = App | Team | User - -""" -The connection type for PushAllowance. -""" -type PushAllowanceConnection { - """ - A list of edges. - """ - edges: [PushAllowanceEdge] - - """ - A list of nodes. - """ - nodes: [PushAllowance] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type PushAllowanceEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: PushAllowance -} - -""" -The query root of GitHub's GraphQL interface. -""" -type Query { - """ - Look up a code of conduct by its key - """ - codeOfConduct( - """ - The code of conduct's key - """ - key: String! - ): CodeOfConduct - - """ - Look up a code of conduct by its key - """ - codesOfConduct: [CodeOfConduct] - - """ - Look up an open source license by its key - """ - license( - """ - The license's downcased SPDX ID - """ - key: String! - ): License - - """ - Return a list of known open source licenses - """ - licenses: [License]! - - """ - Get alphabetically sorted list of Marketplace categories - """ - marketplaceCategories( - """ - Exclude categories with no listings. - """ - excludeEmpty: Boolean - - """ - Returns top level categories only, excluding any subcategories. - """ - excludeSubcategories: Boolean - - """ - Return only the specified categories. - """ - includeCategories: [String!] - ): [MarketplaceCategory!]! - - """ - Look up a Marketplace category by its slug. - """ - marketplaceCategory( - """ - The URL slug of the category. - """ - slug: String! - - """ - Also check topic aliases for the category slug - """ - useTopicAliases: Boolean - ): MarketplaceCategory - - """ - Look up a single Marketplace listing - """ - marketplaceListing( - """ - Select the listing that matches this slug. It's the short name of the listing used in its URL. - """ - slug: String! - ): MarketplaceListing - - """ - Look up Marketplace listings - """ - marketplaceListings( - """ - Select listings that can be administered by the specified user. - """ - adminId: ID - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Select listings visible to the viewer even if they are not approved. If omitted or - false, only approved listings will be returned. - """ - allStates: Boolean - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Select only listings with the given category. - """ - categorySlug: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Select listings for products owned by the specified organization. - """ - organizationId: ID - - """ - Select only listings where the primary category matches the given category slug. - """ - primaryCategoryOnly: Boolean = false - - """ - Select the listings with these slugs, if they are visible to the viewer. - """ - slugs: [String] - - """ - Also check topic aliases for the category slug - """ - useTopicAliases: Boolean - - """ - Select listings to which user has admin access. If omitted, listings visible to the - viewer are returned. - """ - viewerCanAdmin: Boolean - - """ - Select only listings that offer a free trial. - """ - withFreeTrialsOnly: Boolean = false - ): MarketplaceListingConnection! - - """ - Return information about the GitHub instance - """ - meta: GitHubMetadata! - - """ - Fetches an object given its ID. - """ - node( - """ - ID of the object. - """ - id: ID! - ): Node - - """ - Lookup nodes by a list of IDs. - """ - nodes( - """ - The list of node IDs. - """ - ids: [ID!]! - ): [Node]! - - """ - Lookup a organization by login. - """ - organization( - """ - The organization's login. - """ - login: String! - ): Organization - - """ - The client's rate limit information. - """ - rateLimit( - """ - If true, calculate the cost for the query without evaluating it - """ - dryRun: Boolean = false - ): RateLimit - - """ - Hack to workaround https://github.com/facebook/relay/issues/112 re-exposing the root query object - """ - relay: Query! - - """ - Lookup a given repository by the owner and repository name. - """ - repository( - """ - The name of the repository - """ - name: String! - - """ - The login field of a user or organization - """ - owner: String! - ): Repository - - """ - Lookup a repository owner (ie. either a User or an Organization) by login. - """ - repositoryOwner( - """ - The username to lookup the owner by. - """ - login: String! - ): RepositoryOwner - - """ - Lookup resource by a URL. - """ - resource( - """ - The URL. - """ - url: URI! - ): UniformResourceLocatable - - """ - Perform a search across resources. - """ - search( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - The search string to look for. - """ - query: String! - - """ - The types of search items to search within. - """ - type: SearchType! - ): SearchResultItemConnection! - - """ - GitHub Security Advisories - """ - securityAdvisories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Filter advisories by identifier, e.g. GHSA or CVE. - """ - identifier: SecurityAdvisoryIdentifierFilter - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned topics. - """ - orderBy: SecurityAdvisoryOrder = {field: UPDATED_AT, direction: DESC} - - """ - Filter advisories to those published since a time in the past. - """ - publishedSince: DateTime - - """ - Filter advisories to those updated since a time in the past. - """ - updatedSince: DateTime - ): SecurityAdvisoryConnection! - - """ - Fetch a Security Advisory by its GHSA ID - """ - securityAdvisory( - """ - GitHub Security Advisory ID. - """ - ghsaId: String! - ): SecurityAdvisory - - """ - Software Vulnerabilities documented by GitHub Security Advisories - """ - securityVulnerabilities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - An ecosystem to filter vulnerabilities by. - """ - ecosystem: SecurityAdvisoryEcosystem - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned topics. - """ - orderBy: SecurityVulnerabilityOrder = {field: UPDATED_AT, direction: DESC} - - """ - A package name to filter vulnerabilities by. - """ - package: String - - """ - A list of severities to filter vulnerabilities by. - """ - severities: [SecurityAdvisorySeverity!] - ): SecurityVulnerabilityConnection! - - """ - Look up a single Sponsors Listing - """ - sponsorsListing( - """ - Select the Sponsors listing which matches this slug - """ - slug: String! - ): SponsorsListing - - """ - Look up a topic by name. - """ - topic( - """ - The topic's name. - """ - name: String! - ): Topic - - """ - Lookup a user by login. - """ - user( - """ - The user's login. - """ - login: String! - ): User - - """ - The currently authenticated user. - """ - viewer: User! -} - -""" -Represents the client's rate limit. -""" -type RateLimit { - """ - The point cost for the current query counting against the rate limit. - """ - cost: Int! - - """ - The maximum number of points the client is permitted to consume in a 60 minute window. - """ - limit: Int! - - """ - The maximum number of nodes this query may return - """ - nodeCount: Int! - - """ - The number of points remaining in the current rate limit window. - """ - remaining: Int! - - """ - The time at which the current rate limit window resets in UTC epoch seconds. - """ - resetAt: DateTime! -} - -""" -Represents a subject that can be reacted on. -""" -interface Reactable { - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - A list of reactions grouped by content left on the subject. - """ - reactionGroups: [ReactionGroup!] - - """ - A list of Reactions left on the Issue. - """ - reactions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Allows filtering Reactions by emoji. - """ - content: ReactionContent - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Allows specifying the order in which reactions are returned. - """ - orderBy: ReactionOrder - ): ReactionConnection! - - """ - Can user react to this subject - """ - viewerCanReact: Boolean! -} - -""" -The connection type for User. -""" -type ReactingUserConnection { - """ - A list of edges. - """ - edges: [ReactingUserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user that's made a reaction. -""" -type ReactingUserEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: User! - - """ - The moment when the user made the reaction. - """ - reactedAt: DateTime! -} - -""" -An emoji reaction to a particular piece of content. -""" -type Reaction implements Node { - """ - Identifies the emoji reaction. - """ - content: ReactionContent! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The reactable piece of content - """ - reactable: Reactable! - - """ - Identifies the user who created this reaction. - """ - user: User -} - -""" -A list of reactions that have been left on the subject. -""" -type ReactionConnection { - """ - A list of edges. - """ - edges: [ReactionEdge] - - """ - A list of nodes. - """ - nodes: [Reaction] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - Whether or not the authenticated user has left a reaction on the subject. - """ - viewerHasReacted: Boolean! -} - -""" -Emojis that can be attached to Issues, Pull Requests and Comments. -""" -enum ReactionContent { - """ - Represents the `:confused:` emoji. - """ - CONFUSED - - """ - Represents the `:eyes:` emoji. - """ - EYES - - """ - Represents the `:heart:` emoji. - """ - HEART - - """ - Represents the `:hooray:` emoji. - """ - HOORAY - - """ - Represents the `:laugh:` emoji. - """ - LAUGH - - """ - Represents the `:rocket:` emoji. - """ - ROCKET - - """ - Represents the `:-1:` emoji. - """ - THUMBS_DOWN - - """ - Represents the `:+1:` emoji. - """ - THUMBS_UP -} - -""" -An edge in a connection. -""" -type ReactionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Reaction -} - -""" -A group of emoji reactions to a particular piece of content. -""" -type ReactionGroup { - """ - Identifies the emoji reaction. - """ - content: ReactionContent! - - """ - Identifies when the reaction was created. - """ - createdAt: DateTime - - """ - The subject that was reacted to. - """ - subject: Reactable! - - """ - Users who have reacted to the reaction subject with the emotion represented by this reaction group - """ - users( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): ReactingUserConnection! - - """ - Whether or not the authenticated user has left a reaction on the subject. - """ - viewerHasReacted: Boolean! -} - -""" -Ways in which lists of reactions can be ordered upon return. -""" -input ReactionOrder { - """ - The direction in which to order reactions by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order reactions by. - """ - field: ReactionOrderField! -} - -""" -A list of fields that reactions can be ordered by. -""" -enum ReactionOrderField { - """ - Allows ordering a list of reactions by when they were created. - """ - CREATED_AT -} - -""" -Represents a 'ready_for_review' event on a given pull request. -""" -type ReadyForReviewEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - The HTTP path for this ready for review event. - """ - resourcePath: URI! - - """ - The HTTP URL for this ready for review event. - """ - url: URI! -} - -""" -Represents a Git reference. -""" -type Ref implements Node { - """ - A list of pull requests with this ref as the head ref. - """ - associatedPullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - id: ID! - - """ - The ref name. - """ - name: String! - - """ - The ref's prefix, such as `refs/heads/` or `refs/tags/`. - """ - prefix: String! - - """ - The repository the ref belongs to. - """ - repository: Repository! - - """ - The object the ref points to. - """ - target: GitObject! -} - -""" -The connection type for Ref. -""" -type RefConnection { - """ - A list of edges. - """ - edges: [RefEdge] - - """ - A list of nodes. - """ - nodes: [Ref] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RefEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Ref -} - -""" -Ways in which lists of git refs can be ordered upon return. -""" -input RefOrder { - """ - The direction in which to order refs by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order refs by. - """ - field: RefOrderField! -} - -""" -Properties by which ref connections can be ordered. -""" -enum RefOrderField { - """ - Order refs by their alphanumeric name - """ - ALPHABETICAL - - """ - Order refs by underlying commit date if the ref prefix is refs/tags/ - """ - TAG_COMMIT_DATE -} - -""" -Represents a 'referenced' event on a given `ReferencedSubject`. -""" -type ReferencedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the commit associated with the 'referenced' event. - """ - commit: Commit - - """ - Identifies the repository associated with the 'referenced' event. - """ - commitRepository: Repository! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Reference originated in a different repository. - """ - isCrossRepository: Boolean! - - """ - Checks if the commit message itself references the subject. Can be false in the case of a commit comment reference. - """ - isDirectReference: Boolean! - - """ - Object referenced by event. - """ - subject: ReferencedSubject! -} - -""" -Any referenceable object -""" -union ReferencedSubject = Issue | PullRequest - -""" -Autogenerated input type of RegenerateEnterpriseIdentityProviderRecoveryCodes -""" -input RegenerateEnterpriseIdentityProviderRecoveryCodesInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set an identity provider. - """ - enterpriseId: ID! -} - -""" -A registry package contains the content for an uploaded package. -""" -type RegistryPackage implements Node { - """ - The package type color - """ - color: String! - id: ID! - - """ - Find the latest version for the package. - """ - latestVersion: RegistryPackageVersion - - """ - Identifies the title of the package. - """ - name: String! - - """ - Identifies the title of the package, with the owner prefixed. - """ - nameWithOwner: String! - - """ - Find the package file identified by the guid. - """ - packageFileByGuid( - """ - The unique identifier of the package_file - """ - guid: String! - ): RegistryPackageFile - - """ - Find the package file identified by the sha256. - """ - packageFileBySha256( - """ - The SHA256 of the package_file - """ - sha256: String! - ): RegistryPackageFile - - """ - Identifies the type of the package. - """ - packageType: RegistryPackageType! - - """ - List the prerelease versions for this package. - """ - preReleaseVersions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RegistryPackageVersionConnection - - """ - The type of the package. - """ - registryPackageType: String - - """ - repository that the release is associated with - """ - repository: Repository - - """ - Statistics about package activity. - """ - statistics: RegistryPackageStatistics - - """ - list of tags for this package - """ - tags( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RegistryPackageTagConnection! - - """ - List the topics for this package. - """ - topics( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): TopicConnection - - """ - Find package version by version string. - """ - version( - """ - The package version. - """ - version: String! - ): RegistryPackageVersion - - """ - Find package version by version string. - """ - versionByPlatform( - """ - Find a registry package for a specific platform. - """ - platform: String! - - """ - The package version. - """ - version: String! - ): RegistryPackageVersion - - """ - Find package version by manifest SHA256. - """ - versionBySha256( - """ - The package SHA256 digest. - """ - sha256: String! - ): RegistryPackageVersion - - """ - list of versions for this package - """ - versions( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RegistryPackageVersionConnection! - - """ - List package versions with a specific metadatum. - """ - versionsByMetadatum( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter on a specific metadatum. - """ - metadatum: RegistryPackageMetadatum! - ): RegistryPackageVersionConnection -} - -""" -The connection type for RegistryPackage. -""" -type RegistryPackageConnection { - """ - A list of edges. - """ - edges: [RegistryPackageEdge] - - """ - A list of nodes. - """ - nodes: [RegistryPackage] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -A package dependency contains the information needed to satisfy a dependency. -""" -type RegistryPackageDependency implements Node { - """ - Identifies the type of dependency. - """ - dependencyType: RegistryPackageDependencyType! - id: ID! - - """ - Identifies the name of the dependency. - """ - name: String! - - """ - Identifies the version of the dependency. - """ - version: String! -} - -""" -The connection type for RegistryPackageDependency. -""" -type RegistryPackageDependencyConnection { - """ - A list of edges. - """ - edges: [RegistryPackageDependencyEdge] - - """ - A list of nodes. - """ - nodes: [RegistryPackageDependency] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RegistryPackageDependencyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RegistryPackageDependency -} - -""" -The possible types of a registry package dependency. -""" -enum RegistryPackageDependencyType { - """ - An optional registry package dependency type. - """ - BUNDLED - - """ - A default registry package dependency type. - """ - DEFAULT - - """ - A dev registry package dependency type. - """ - DEV - - """ - An optional registry package dependency type. - """ - OPTIONAL - - """ - A peer registry package dependency type. - """ - PEER - - """ - A test registry package dependency type. - """ - TEST -} - -""" -An edge in a connection. -""" -type RegistryPackageEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RegistryPackage -} - -""" -A file in a specific registry package version. -""" -type RegistryPackageFile implements Node { - """ - A unique identifier for this file. - """ - guid: String - id: ID! - - """ - Identifies the md5. - """ - md5: String - - """ - URL to download the asset metadata. - """ - metadataUrl: URI! - - """ - Name of the file - """ - name: String! - - """ - The package version this file belongs to. - """ - packageVersion: RegistryPackageVersion! - - """ - Identifies the sha1. - """ - sha1: String - - """ - Identifies the sha256. - """ - sha256: String - - """ - Identifies the size. - """ - size: Int - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - URL to download the asset. - """ - url: URI! -} - -""" -The connection type for RegistryPackageFile. -""" -type RegistryPackageFileConnection { - """ - A list of edges. - """ - edges: [RegistryPackageFileEdge] - - """ - A list of nodes. - """ - nodes: [RegistryPackageFile] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RegistryPackageFileEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RegistryPackageFile -} - -""" -The possible states of a registry package file. -""" -enum RegistryPackageFileState { - """ - Package file doesn't have a blob backing it. - """ - NEW - - """ - All Package file contents have been uploaded. - """ - UPLOADED -} - -""" -Represents a single registry metadatum -""" -input RegistryPackageMetadatum { - """ - Name of the metadatum. - """ - name: String! - - """ - True, if the metadatum can be updated if it already exists - """ - update: Boolean - - """ - Value of the metadatum. - """ - value: String! -} - -""" -Represents an owner of a registry package. -""" -interface RegistryPackageOwner { - id: ID! - - """ - A list of registry packages under the owner. - """ - registryPackages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find registry package by name. - """ - name: String - - """ - Find registry packages by their names. - """ - names: [String] - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Filter registry package by whether it is publicly visible - """ - publicOnly: Boolean = false - - """ - Filter registry package by type (string). - """ - registryPackageType: String - - """ - Find registry packages in a repository. - """ - repositoryId: ID - ): RegistryPackageConnection! -} - -""" -Represents an interface to search packages on an object. -""" -interface RegistryPackageSearch { - id: ID! - - """ - A list of registry packages for a particular search query. - """ - registryPackagesForQuery( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Find registry package by search query. - """ - query: String - ): RegistryPackageConnection! -} - -""" -Represents a object that contains package activity statistics such as downloads. -""" -type RegistryPackageStatistics { - """ - Number of times the package was downloaded this month. - """ - downloadsThisMonth: Int! - - """ - Number of times the package was downloaded this week. - """ - downloadsThisWeek: Int! - - """ - Number of times the package was downloaded this year. - """ - downloadsThisYear: Int! - - """ - Number of times the package was downloaded today. - """ - downloadsToday: Int! - - """ - Number of times the package was downloaded since it was created. - """ - downloadsTotalCount: Int! -} - -""" -A version tag contains the mapping between a tag name and a version. -""" -type RegistryPackageTag implements Node { - id: ID! - - """ - Identifies the tag name of the version. - """ - name: String! - - """ - version that the tag is associated with - """ - version: RegistryPackageVersion -} - -""" -The connection type for RegistryPackageTag. -""" -type RegistryPackageTagConnection { - """ - A list of edges. - """ - edges: [RegistryPackageTagEdge] - - """ - A list of nodes. - """ - nodes: [RegistryPackageTag] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RegistryPackageTagEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RegistryPackageTag -} - -""" -The possible types of a registry package. -""" -enum RegistryPackageType { - """ - A debian package. - """ - DEBIAN - - """ - A docker image. - """ - DOCKER - - """ - A maven registry package. - """ - MAVEN - - """ - An npm registry package. - """ - NPM - - """ - A nuget package. - """ - NUGET - - """ - A python package. - """ - PYTHON - - """ - A rubygems registry package. - """ - RUBYGEMS -} - -""" -A package version contains the information about a specific package version. -""" -type RegistryPackageVersion implements Node { - """ - list of dependencies for this package - """ - dependencies( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find dependencies by type. - """ - type: RegistryPackageDependencyType - ): RegistryPackageDependencyConnection! - - """ - A file associated with this registry package version - """ - fileByName( - """ - A specific file to find. - """ - filename: String! - ): RegistryPackageFile - - """ - List of files associated with this registry package version - """ - files( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RegistryPackageFileConnection! - id: ID! - - """ - A single line of text to install this package version. - """ - installationCommand: String - - """ - Identifies the package manifest for this package version. - """ - manifest: String - - """ - Identifies the platform this version was built for. - """ - platform: String - - """ - Indicates whether this version is a pre-release. - """ - preRelease: Boolean! - - """ - The README of this package version - """ - readme: String - - """ - The HTML README of this package version - """ - readmeHtml: HTML - - """ - Registry package associated with this version. - """ - registryPackage: RegistryPackage - - """ - Release associated with this package. - """ - release: Release - - """ - Identifies the sha256. - """ - sha256: String - - """ - Identifies the size. - """ - size: Int - - """ - Statistics about package activity. - """ - statistics: RegistryPackageVersionStatistics - - """ - Identifies the package version summary. - """ - summary: String - - """ - Time at which the most recent file upload for this package version finished - """ - updatedAt: DateTime! - - """ - Identifies the version number. - """ - version: String! - - """ - Can the current viewer edit this Package version. - """ - viewerCanEdit: Boolean! -} - -""" -The connection type for RegistryPackageVersion. -""" -type RegistryPackageVersionConnection { - """ - A list of edges. - """ - edges: [RegistryPackageVersionEdge] - - """ - A list of nodes. - """ - nodes: [RegistryPackageVersion] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RegistryPackageVersionEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RegistryPackageVersion -} - -""" -Represents a object that contains package version activity statistics such as downloads. -""" -type RegistryPackageVersionStatistics { - """ - Number of times the package was downloaded this month. - """ - downloadsThisMonth: Int! - - """ - Number of times the package was downloaded this week. - """ - downloadsThisWeek: Int! - - """ - Number of times the package was downloaded this year. - """ - downloadsThisYear: Int! - - """ - Number of times the package was downloaded today. - """ - downloadsToday: Int! - - """ - Number of times the package was downloaded since it was created. - """ - downloadsTotalCount: Int! -} - -""" -A release contains the content for a release. -""" -type Release implements Node & UniformResourceLocatable { - """ - The author of the release - """ - author: User - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The description of the release. - """ - description: String - - """ - The description of this release rendered to HTML. - """ - descriptionHTML: HTML - id: ID! - - """ - Whether or not the release is a draft - """ - isDraft: Boolean! - - """ - Whether or not the release is a prerelease - """ - isPrerelease: Boolean! - - """ - The title of the release. - """ - name: String - - """ - Identifies the date and time when the release was created. - """ - publishedAt: DateTime - - """ - List of releases assets which are dependent on this release. - """ - releaseAssets( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - A list of names to filter the assets by. - """ - name: String - ): ReleaseAssetConnection! - - """ - The HTTP path for this issue - """ - resourcePath: URI! - - """ - A description of the release, rendered to HTML without any links in it. - """ - shortDescriptionHTML( - """ - How many characters to return. - """ - limit: Int = 200 - ): HTML - - """ - The Git tag the release points to - """ - tag: Ref - - """ - The name of the release's Git tag - """ - tagName: String! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this issue - """ - url: URI! -} - -""" -A release asset contains the content for a release asset. -""" -type ReleaseAsset implements Node { - """ - The asset's content-type - """ - contentType: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The number of times this asset was downloaded - """ - downloadCount: Int! - - """ - Identifies the URL where you can download the release asset via the browser. - """ - downloadUrl: URI! - id: ID! - - """ - Identifies the title of the release asset. - """ - name: String! - - """ - Release that the asset is associated with - """ - release: Release - - """ - The size (in bytes) of the asset - """ - size: Int! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The user that performed the upload - """ - uploadedBy: User! - - """ - Identifies the URL of the release asset. - """ - url: URI! -} - -""" -The connection type for ReleaseAsset. -""" -type ReleaseAssetConnection { - """ - A list of edges. - """ - edges: [ReleaseAssetEdge] - - """ - A list of nodes. - """ - nodes: [ReleaseAsset] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReleaseAssetEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ReleaseAsset -} - -""" -The connection type for Release. -""" -type ReleaseConnection { - """ - A list of edges. - """ - edges: [ReleaseEdge] - - """ - A list of nodes. - """ - nodes: [Release] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReleaseEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Release -} - -""" -Ways in which lists of releases can be ordered upon return. -""" -input ReleaseOrder { - """ - The direction in which to order releases by the specified field. - """ - direction: OrderDirection! - - """ - The field in which to order releases by. - """ - field: ReleaseOrderField! -} - -""" -Properties by which release connections can be ordered. -""" -enum ReleaseOrderField { - """ - Order releases by creation time - """ - CREATED_AT - - """ - Order releases alphabetically by name - """ - NAME -} - -""" -Autogenerated input type of RemoveAssigneesFromAssignable -""" -input RemoveAssigneesFromAssignableInput { - """ - The id of the assignable object to remove assignees from. - """ - assignableId: ID! - - """ - The id of users to remove as assignees. - """ - assigneeIds: [ID!]! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated return type of RemoveAssigneesFromAssignable -""" -type RemoveAssigneesFromAssignablePayload { - """ - The item that was unassigned. - """ - assignable: Assignable - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of RemoveEnterpriseAdmin -""" -input RemoveEnterpriseAdminInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Enterprise ID from which to remove the administrator. - """ - enterpriseId: ID! - - """ - The login of the user to remove as an administrator. - """ - login: String! -} - -""" -Autogenerated input type of RemoveEnterpriseOrganization -""" -input RemoveEnterpriseOrganizationInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise from which the organization should be removed. - """ - enterpriseId: ID! - - """ - The ID of the organization to remove from the enterprise. - """ - organizationId: ID! -} - -""" -Autogenerated input type of RemoveLabelsFromLabelable -""" -input RemoveLabelsFromLabelableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ids of labels to remove. - """ - labelIds: [ID!]! - - """ - The id of the Labelable to remove labels from. - """ - labelableId: ID! -} - -""" -Autogenerated return type of RemoveLabelsFromLabelable -""" -type RemoveLabelsFromLabelablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Labelable the labels were removed from. - """ - labelable: Labelable -} - -""" -Autogenerated input type of RemoveOutsideCollaborator -""" -input RemoveOutsideCollaboratorInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the organization to remove the outside collaborator from. - """ - organizationId: ID! - - """ - The ID of the outside collaborator to remove. - """ - userId: ID! -} - -""" -Autogenerated return type of RemoveOutsideCollaborator -""" -type RemoveOutsideCollaboratorPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The user that was removed as an outside collaborator. - """ - removedUser: User -} - -""" -Autogenerated input type of RemoveReaction -""" -input RemoveReactionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of the emoji reaction to remove. - """ - content: ReactionContent! - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! -} - -""" -Autogenerated return type of RemoveReaction -""" -type RemoveReactionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The reaction object. - """ - reaction: Reaction - - """ - The reactable subject. - """ - subject: Reactable -} - -""" -Autogenerated input type of RemoveStar -""" -input RemoveStarInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Starrable ID to unstar. - """ - starrableId: ID! -} - -""" -Autogenerated return type of RemoveStar -""" -type RemoveStarPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The starrable. - """ - starrable: Starrable -} - -""" -Represents a 'removed_from_project' event on a given issue or pull request. -""" -type RemovedFromProjectEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! -} - -""" -Represents a 'renamed' event on a given issue or pull request -""" -type RenamedTitleEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the current title of the issue or pull request. - """ - currentTitle: String! - id: ID! - - """ - Identifies the previous title of the issue or pull request. - """ - previousTitle: String! - - """ - Subject that was renamed. - """ - subject: RenamedTitleSubject! -} - -""" -An object which has a renamable title -""" -union RenamedTitleSubject = Issue | PullRequest - -""" -Autogenerated input type of ReopenIssue -""" -input ReopenIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue to be opened. - """ - issueId: ID! -} - -""" -Autogenerated return type of ReopenIssue -""" -type ReopenIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was opened. - """ - issue: Issue -} - -""" -Autogenerated input type of ReopenPullRequest -""" -input ReopenPullRequestInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the pull request to be reopened. - """ - pullRequestId: ID! -} - -""" -Autogenerated return type of ReopenPullRequest -""" -type ReopenPullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that was reopened. - """ - pullRequest: PullRequest -} - -""" -Represents a 'reopened' event on any `Closable`. -""" -type ReopenedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Object that was reopened. - """ - closable: Closable! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! -} - -""" -Audit log entry for a repo.access event. -""" -type RepoAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoAccessAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoAccessAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.add_member event. -""" -type RepoAddMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoAddMemberAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoAddMemberAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.add_topic event. -""" -type RepoAddTopicAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TopicAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The name of the topic added to the repository - """ - topic: Topic - - """ - The name of the topic added to the repository - """ - topicName: String - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.archived event. -""" -type RepoArchivedAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoArchivedAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoArchivedAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.change_merge_setting event. -""" -type RepoChangeMergeSettingAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the change was to enable (true) or disable (false) the merge type - """ - isEnabled: Boolean - - """ - The merge method affected by the change - """ - mergeType: RepoChangeMergeSettingAuditEntryMergeType - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The merge options available for pull requests to this repository. -""" -enum RepoChangeMergeSettingAuditEntryMergeType { - """ - The pull request is added to the base branch in a merge commit. - """ - MERGE - - """ - Commits from the pull request are added onto the base branch individually without a merge commit. - """ - REBASE - - """ - The pull request's commits are squashed into a single commit before they are merged to the base branch. - """ - SQUASH -} - -""" -Audit log entry for a repo.config.disable_anonymous_git_access event. -""" -type RepoConfigDisableAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.disable_collaborators_only event. -""" -type RepoConfigDisableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.disable_contributors_only event. -""" -type RepoConfigDisableContributorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.disable_sockpuppet_disallowed event. -""" -type RepoConfigDisableSockpuppetDisallowedAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_anonymous_git_access event. -""" -type RepoConfigEnableAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_collaborators_only event. -""" -type RepoConfigEnableCollaboratorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_contributors_only event. -""" -type RepoConfigEnableContributorsOnlyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.enable_sockpuppet_disallowed event. -""" -type RepoConfigEnableSockpuppetDisallowedAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.lock_anonymous_git_access event. -""" -type RepoConfigLockAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.config.unlock_anonymous_git_access event. -""" -type RepoConfigUnlockAnonymousGitAccessAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repo.create event. -""" -type RepoCreateAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The name of the parent repository for this forked repository. - """ - forkParentName: String - - """ - The name of the root repository for this netork. - """ - forkSourceName: String - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoCreateAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoCreateAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.destroy event. -""" -type RepoDestroyAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoDestroyAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoDestroyAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.remove_member event. -""" -type RepoRemoveMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI - - """ - The visibility of the repository - """ - visibility: RepoRemoveMemberAuditEntryVisibility -} - -""" -The privacy of a repository -""" -enum RepoRemoveMemberAuditEntryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repo.remove_topic event. -""" -type RepoRemoveTopicAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TopicAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The name of the topic added to the repository - """ - topic: Topic - - """ - The name of the topic added to the repository - """ - topicName: String - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The reasons a piece of content can be reported or minimized. -""" -enum ReportedContentClassifiers { - """ - An abusive or harassing piece of content - """ - ABUSE - - """ - An irrelevant piece of content - """ - OFF_TOPIC - - """ - An outdated piece of content - """ - OUTDATED - - """ - The content has been resolved - """ - RESOLVED - - """ - A spammy piece of content - """ - SPAM -} - -""" -A repository contains the content for a project. -""" -type Repository implements Node & ProjectOwner & RegistryPackageOwner & RepositoryInfo & Starrable & Subscribable & UniformResourceLocatable { - """ - A list of users that can be assigned to issues in this repository. - """ - assignableUsers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - A list of branch protection rules for this repository. - """ - branchProtectionRules( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): BranchProtectionRuleConnection! - - """ - Returns the code of conduct for this repository - """ - codeOfConduct: CodeOfConduct - - """ - A list of collaborators associated with the repository. - """ - collaborators( - """ - Collaborators affiliation level with a repository. - """ - affiliation: CollaboratorAffiliation - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RepositoryCollaboratorConnection - - """ - A list of commit comments associated with the repository. - """ - commitComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The Ref associated with the repository's default branch. - """ - defaultBranchRef: Ref - - """ - A list of deploy keys that are on this repository. - """ - deployKeys( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): DeployKeyConnection! - - """ - Deployments associated with the repository - """ - deployments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Environments to list deployments for - """ - environments: [String!] - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for deployments returned from the connection. - """ - orderBy: DeploymentOrder = {field: CREATED_AT, direction: ASC} - ): DeploymentConnection! - - """ - The description of the repository. - """ - description: String - - """ - The description of the repository rendered to HTML. - """ - descriptionHTML: HTML! - - """ - The number of kilobytes this repository occupies on disk. - """ - diskUsage: Int - - """ - Returns how many forks there are of this repository in the whole network. - """ - forkCount: Int! - - """ - A list of direct forked repositories. - """ - forks( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Indicates if the repository has issues feature enabled. - """ - hasIssuesEnabled: Boolean! - - """ - Indicates if the repository has wiki feature enabled. - """ - hasWikiEnabled: Boolean! - - """ - The repository's URL. - """ - homepageUrl: URI - id: ID! - - """ - Indicates if the repository is unmaintained. - """ - isArchived: Boolean! - - """ - Returns whether or not this repository disabled. - """ - isDisabled: Boolean! - - """ - Identifies if the repository is a fork. - """ - isFork: Boolean! - - """ - Indicates if the repository has been locked or not. - """ - isLocked: Boolean! - - """ - Identifies if the repository is a mirror. - """ - isMirror: Boolean! - - """ - Identifies if the repository is private. - """ - isPrivate: Boolean! - - """ - Identifies if the repository is a template that can be used to generate new repositories. - """ - isTemplate: Boolean! - - """ - Returns a single issue from the current repository by number. - """ - issue( - """ - The number for the issue to be returned. - """ - number: Int! - ): Issue - - """ - Returns a single issue-like object from the current repository by number. - """ - issueOrPullRequest( - """ - The number for the issue to be returned. - """ - number: Int! - ): IssueOrPullRequest - - """ - A list of issues that have been opened in the repository. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Returns a single label by name - """ - label( - """ - Label name - """ - name: String! - ): Label - - """ - A list of labels associated with the repository. - """ - labels( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - If provided, searches labels by name and description. - """ - query: String - ): LabelConnection - - """ - A list containing a breakdown of the language composition of the repository. - """ - languages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: LanguageOrder - ): LanguageConnection - - """ - The license associated with the repository - """ - licenseInfo: License - - """ - The reason the repository has been locked. - """ - lockReason: RepositoryLockReason - - """ - A list of Users that can be mentioned in the context of the repository. - """ - mentionableUsers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! - - """ - Whether or not PRs are merged with a merge commit on this repository. - """ - mergeCommitAllowed: Boolean! - - """ - Returns a single milestone from the current repository by number. - """ - milestone( - """ - The number for the milestone to be returned. - """ - number: Int! - ): Milestone - - """ - A list of milestones associated with the repository. - """ - milestones( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for milestones. - """ - orderBy: MilestoneOrder - - """ - Filter by the state of the milestones. - """ - states: [MilestoneState!] - ): MilestoneConnection - - """ - The repository's original mirror URL. - """ - mirrorUrl: URI - - """ - The name of the repository. - """ - name: String! - - """ - The repository's name with owner. - """ - nameWithOwner: String! - - """ - A Git object in the repository - """ - object( - """ - A Git revision expression suitable for rev-parse - """ - expression: String - - """ - The Git object ID - """ - oid: GitObjectID - ): GitObject - - """ - The image used to represent this repository in Open Graph data. - """ - openGraphImageUrl: URI! - - """ - The User owner of the repository. - """ - owner: RepositoryOwner! - - """ - The repository parent, if this is a fork. - """ - parent: Repository - - """ - The primary language of the repository's code. - """ - primaryLanguage: Language - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing the repository's projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing the repository's projects - """ - projectsUrl: URI! - - """ - Returns a single pull request from the current repository by number. - """ - pullRequest( - """ - The number for the pull request to be returned. - """ - number: Int! - ): PullRequest - - """ - A list of pull requests that have been opened in the repository. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - Identifies when the repository was last pushed to. - """ - pushedAt: DateTime - - """ - Whether or not rebase-merging is enabled on this repository. - """ - rebaseMergeAllowed: Boolean! - - """ - Fetch a given ref from the repository - """ - ref( - """ - The ref to retrieve. Fully qualified matches are checked in order - (`refs/heads/master`) before falling back onto checks for short name matches (`master`). - """ - qualifiedName: String! - ): Ref - - """ - Fetch a list of refs from the repository - """ - refs( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - DEPRECATED: use orderBy. The ordering direction. - """ - direction: OrderDirection - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for refs returned from the connection. - """ - orderBy: RefOrder - - """ - A ref name prefix like `refs/heads/`, `refs/tags/`, etc. - """ - refPrefix: String! - ): RefConnection - - """ - A list of registry packages under the owner. - """ - registryPackages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find registry package by name. - """ - name: String - - """ - Find registry packages by their names. - """ - names: [String] - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Filter registry package by whether it is publicly visible - """ - publicOnly: Boolean = false - - """ - Filter registry package by type (string). - """ - registryPackageType: String - - """ - Find registry packages in a repository. - """ - repositoryId: ID - ): RegistryPackageConnection! - - """ - Lookup a single release given various criteria. - """ - release( - """ - The name of the Tag the Release was created from - """ - tagName: String! - ): Release - - """ - List of releases which are dependent on this repository. - """ - releases( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: ReleaseOrder - ): ReleaseConnection! - - """ - A list of applied repository-topic associations for this repository. - """ - repositoryTopics( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): RepositoryTopicConnection! - - """ - The HTTP path for this repository - """ - resourcePath: URI! - - """ - A description of the repository, rendered to HTML without any links in it. - """ - shortDescriptionHTML( - """ - How many characters to return. - """ - limit: Int = 200 - ): HTML! - - """ - Whether or not squash-merging is enabled on this repository. - """ - squashMergeAllowed: Boolean! - - """ - The SSH URL to clone this repository - """ - sshUrl: GitSSHRemote! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - The repository from which this repository was generated, if any. - """ - templateRepository: Repository - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this repository - """ - url: URI! - - """ - Whether this repository has a custom image to use with Open Graph as opposed to being represented by the owner's avatar. - """ - usesCustomOpenGraphImage: Boolean! - - """ - Indicates whether the viewer has admin permissions on this repository. - """ - viewerCanAdminister: Boolean! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Indicates whether the viewer can update the topics of this repository. - """ - viewerCanUpdateTopics: Boolean! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! - - """ - The users permission level on the repository. Will return null if authenticated as an GitHub App. - """ - viewerPermission: RepositoryPermission - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState - - """ - A list of users watching the repository. - """ - watchers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): UserConnection! -} - -""" -The affiliation of a user to a repository -""" -enum RepositoryAffiliation { - """ - Repositories that the user has been added to as a collaborator. - """ - COLLABORATOR - - """ - Repositories that the user has access to through being a member of an - organization. This includes every repository on every team that the user is on. - """ - ORGANIZATION_MEMBER - - """ - Repositories that are owned by the authenticated user. - """ - OWNER -} - -""" -Metadata for an audit entry with action repo.* -""" -interface RepositoryAuditEntryData { - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI -} - -""" -The affiliation type between collaborator and repository. -""" -enum RepositoryCollaboratorAffiliation { - """ - All collaborators of the repository. - """ - ALL - - """ - All outside collaborators of an organization-owned repository. - """ - OUTSIDE -} - -""" -The connection type for User. -""" -type RepositoryCollaboratorConnection { - """ - A list of edges. - """ - edges: [RepositoryCollaboratorEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user who is a collaborator of a repository. -""" -type RepositoryCollaboratorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: User! - - """ - The permission the user has on the repository. - """ - permission: RepositoryPermission! - - """ - A list of sources for the user's access to the repository. - """ - permissionSources: [PermissionSource!] -} - -""" -A list of repositories owned by the subject. -""" -type RepositoryConnection { - """ - A list of edges. - """ - edges: [RepositoryEdge] - - """ - A list of nodes. - """ - nodes: [Repository] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! - - """ - The total size in kilobytes of all repositories in the connection. - """ - totalDiskUsage: Int! -} - -""" -The reason a repository is listed as 'contributed'. -""" -enum RepositoryContributionType { - """ - Created a commit - """ - COMMIT - - """ - Created an issue - """ - ISSUE - - """ - Created a pull request - """ - PULL_REQUEST - - """ - Reviewed a pull request - """ - PULL_REQUEST_REVIEW - - """ - Created the repository - """ - REPOSITORY -} - -""" -A user who has contributed to a repository. -""" -type RepositoryContributorEdge { - """ - The number of contributions the user has made in the repository. - """ - contributionsCount: Int! - - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User -} - -""" -An edge in a connection. -""" -type RepositoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Repository -} - -""" -A subset of repository info. -""" -interface RepositoryInfo { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The description of the repository. - """ - description: String - - """ - The description of the repository rendered to HTML. - """ - descriptionHTML: HTML! - - """ - Returns how many forks there are of this repository in the whole network. - """ - forkCount: Int! - - """ - Indicates if the repository has issues feature enabled. - """ - hasIssuesEnabled: Boolean! - - """ - Indicates if the repository has wiki feature enabled. - """ - hasWikiEnabled: Boolean! - - """ - The repository's URL. - """ - homepageUrl: URI - - """ - Indicates if the repository is unmaintained. - """ - isArchived: Boolean! - - """ - Identifies if the repository is a fork. - """ - isFork: Boolean! - - """ - Indicates if the repository has been locked or not. - """ - isLocked: Boolean! - - """ - Identifies if the repository is a mirror. - """ - isMirror: Boolean! - - """ - Identifies if the repository is private. - """ - isPrivate: Boolean! - - """ - Identifies if the repository is a template that can be used to generate new repositories. - """ - isTemplate: Boolean! - - """ - The license associated with the repository - """ - licenseInfo: License - - """ - The reason the repository has been locked. - """ - lockReason: RepositoryLockReason - - """ - The repository's original mirror URL. - """ - mirrorUrl: URI - - """ - The name of the repository. - """ - name: String! - - """ - The repository's name with owner. - """ - nameWithOwner: String! - - """ - The image used to represent this repository in Open Graph data. - """ - openGraphImageUrl: URI! - - """ - The User owner of the repository. - """ - owner: RepositoryOwner! - - """ - Identifies when the repository was last pushed to. - """ - pushedAt: DateTime - - """ - The HTTP path for this repository - """ - resourcePath: URI! - - """ - A description of the repository, rendered to HTML without any links in it. - """ - shortDescriptionHTML( - """ - How many characters to return. - """ - limit: Int = 200 - ): HTML! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this repository - """ - url: URI! - - """ - Whether this repository has a custom image to use with Open Graph as opposed to being represented by the owner's avatar. - """ - usesCustomOpenGraphImage: Boolean! -} - -""" -An invitation for a user to be added to a repository. -""" -type RepositoryInvitation implements Node { - id: ID! - - """ - The user who received the invitation. - """ - invitee: User! - - """ - The user who created the invitation. - """ - inviter: User! - - """ - The permission granted on this repository by this invitation. - """ - permission: RepositoryPermission! - - """ - The Repository the user is invited to. - """ - repository: RepositoryInfo -} - -""" -An edge in a connection. -""" -type RepositoryInvitationEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RepositoryInvitation -} - -""" -The possible reasons a given repository could be in a locked state. -""" -enum RepositoryLockReason { - """ - The repository is locked due to a billing related reason. - """ - BILLING - - """ - The repository is locked due to a migration. - """ - MIGRATING - - """ - The repository is locked due to a move. - """ - MOVING - - """ - The repository is locked due to a rename. - """ - RENAME -} - -""" -Represents a object that belongs to a repository. -""" -interface RepositoryNode { - """ - The repository associated with this node. - """ - repository: Repository! -} - -""" -Ordering options for repository connections -""" -input RepositoryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repositories by. - """ - field: RepositoryOrderField! -} - -""" -Properties by which repository connections can be ordered. -""" -enum RepositoryOrderField { - """ - Order repositories by creation time - """ - CREATED_AT - - """ - Order repositories by name - """ - NAME - - """ - Order repositories by push time - """ - PUSHED_AT - - """ - Order repositories by number of stargazers - """ - STARGAZERS - - """ - Order repositories by update time - """ - UPDATED_AT -} - -""" -Represents an owner of a Repository. -""" -interface RepositoryOwner { - """ - A URL pointing to the owner's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - id: ID! - - """ - The username used to login. - """ - login: String! - - """ - A list of repositories this user has pinned to their profile - """ - pinnedRepositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! @deprecated(reason: "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-10-01 UTC.") - - """ - A list of repositories that the user owns. - """ - repositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they are forks of another repository - """ - isFork: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Find Repository. - """ - repository( - """ - Name of Repository to find. - """ - name: String! - ): Repository - - """ - The HTTP URL for the owner. - """ - resourcePath: URI! - - """ - The HTTP URL for the owner. - """ - url: URI! -} - -""" -The access level to a repository -""" -enum RepositoryPermission { - """ - Can read, clone, and push to this repository. Can also manage issues, pull - requests, and repository settings, including adding collaborators - """ - ADMIN - - """ - Can read, clone, and push to this repository. They can also manage issues, pull requests, and some repository settings - """ - MAINTAIN - - """ - Can read and clone this repository. Can also open and comment on issues and pull requests - """ - READ - - """ - Can read and clone this repository. Can also manage issues and pull requests - """ - TRIAGE - - """ - Can read, clone, and push to this repository. Can also manage issues and pull requests - """ - WRITE -} - -""" -The privacy of a repository -""" -enum RepositoryPrivacy { - """ - Private - """ - PRIVATE - - """ - Public - """ - PUBLIC -} - -""" -A repository-topic connects a repository to a topic. -""" -type RepositoryTopic implements Node & UniformResourceLocatable { - id: ID! - - """ - The HTTP path for this repository-topic. - """ - resourcePath: URI! - - """ - The topic. - """ - topic: Topic! - - """ - The HTTP URL for this repository-topic. - """ - url: URI! -} - -""" -The connection type for RepositoryTopic. -""" -type RepositoryTopicConnection { - """ - A list of edges. - """ - edges: [RepositoryTopicEdge] - - """ - A list of nodes. - """ - nodes: [RepositoryTopic] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type RepositoryTopicEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: RepositoryTopic -} - -""" -The repository's visibility level. -""" -enum RepositoryVisibility { - """ - The repository is visible only to users in the same business. - """ - INTERNAL - - """ - The repository is visible only to those with explicit access. - """ - PRIVATE - - """ - The repository is visible to everyone. - """ - PUBLIC -} - -""" -Audit log entry for a repository_visibility_change.disable event. -""" -type RepositoryVisibilityChangeDisableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a repository_visibility_change.enable event. -""" -type RepositoryVisibilityChangeEnableAuditEntry implements AuditEntry & EnterpriseAuditEntryData & Node & OrganizationAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - - """ - The HTTP path for this enterprise. - """ - enterpriseResourcePath: URI - - """ - The slug of the enterprise. - """ - enterpriseSlug: String - - """ - The HTTP URL for this enterprise. - """ - enterpriseUrl: URI - id: ID! - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Autogenerated input type of RequestReviews -""" -input RequestReviewsInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pull request to modify. - """ - pullRequestId: ID! - - """ - The Node IDs of the team to request. - """ - teamIds: [ID!] - - """ - Add users to the set rather than replace. - """ - union: Boolean - - """ - The Node IDs of the user to request. - """ - userIds: [ID!] -} - -""" -Autogenerated return type of RequestReviews -""" -type RequestReviewsPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The pull request that is getting requests. - """ - pullRequest: PullRequest - - """ - The edge from the pull request to the requested reviewers. - """ - requestedReviewersEdge: UserEdge -} - -""" -Types that can be requested reviewers. -""" -union RequestedReviewer = Mannequin | Team | User - -""" -Autogenerated input type of ResolveReviewThread -""" -input ResolveReviewThreadInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the thread to resolve - """ - threadId: ID! -} - -""" -Autogenerated return type of ResolveReviewThread -""" -type ResolveReviewThreadPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The thread to resolve. - """ - thread: PullRequestReviewThread -} - -""" -Represents a private contribution a user made on GitHub. -""" -type RestrictedContribution implements Contribution { - """ - Whether this contribution is associated with a record you do not have access to. For - example, your own 'first issue' contribution may have been made on a repository you can no - longer access. - """ - isRestricted: Boolean! - - """ - When this contribution was made. - """ - occurredAt: DateTime! - - """ - The HTTP path for this contribution. - """ - resourcePath: URI! - - """ - The HTTP URL for this contribution. - """ - url: URI! - - """ - The user who made this contribution. - """ - user: User! -} - -""" -A team or user who has the ability to dismiss a review on a protected branch. -""" -type ReviewDismissalAllowance implements Node { - """ - The actor that can dismiss. - """ - actor: ReviewDismissalAllowanceActor - - """ - Identifies the branch protection rule associated with the allowed user or team. - """ - branchProtectionRule: BranchProtectionRule - id: ID! -} - -""" -Types that can be an actor. -""" -union ReviewDismissalAllowanceActor = Team | User - -""" -The connection type for ReviewDismissalAllowance. -""" -type ReviewDismissalAllowanceConnection { - """ - A list of edges. - """ - edges: [ReviewDismissalAllowanceEdge] - - """ - A list of nodes. - """ - nodes: [ReviewDismissalAllowance] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReviewDismissalAllowanceEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ReviewDismissalAllowance -} - -""" -Represents a 'review_dismissed' event on a given issue or pull request. -""" -type ReviewDismissedEvent implements Node & UniformResourceLocatable { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - Identifies the optional message associated with the 'review_dismissed' event. - """ - dismissalMessage: String - - """ - Identifies the optional message associated with the event, rendered to HTML. - """ - dismissalMessageHTML: String - id: ID! - - """ - Identifies the previous state of the review with the 'review_dismissed' event. - """ - previousReviewState: PullRequestReviewState! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the commit which caused the review to become stale. - """ - pullRequestCommit: PullRequestCommit - - """ - The HTTP path for this review dismissed event. - """ - resourcePath: URI! - - """ - Identifies the review associated with the 'review_dismissed' event. - """ - review: PullRequestReview - - """ - The HTTP URL for this review dismissed event. - """ - url: URI! -} - -""" -A request for a user to review a pull request. -""" -type ReviewRequest implements Node { - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - Identifies the pull request associated with this review request. - """ - pullRequest: PullRequest! - - """ - The reviewer that is requested. - """ - requestedReviewer: RequestedReviewer -} - -""" -The connection type for ReviewRequest. -""" -type ReviewRequestConnection { - """ - A list of edges. - """ - edges: [ReviewRequestEdge] - - """ - A list of nodes. - """ - nodes: [ReviewRequest] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type ReviewRequestEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: ReviewRequest -} - -""" -Represents an 'review_request_removed' event on a given pull request. -""" -type ReviewRequestRemovedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the reviewer whose review request was removed. - """ - requestedReviewer: RequestedReviewer -} - -""" -Represents an 'review_requested' event on a given pull request. -""" -type ReviewRequestedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - PullRequest referenced by event. - """ - pullRequest: PullRequest! - - """ - Identifies the reviewer whose review was requested. - """ - requestedReviewer: RequestedReviewer -} - -""" -A Saved Reply is text a user can use to reply quickly. -""" -type SavedReply implements Node { - """ - The body of the saved reply. - """ - body: String! - - """ - The saved reply body rendered to HTML. - """ - bodyHTML: HTML! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - id: ID! - - """ - The title of the saved reply. - """ - title: String! - - """ - The user that saved this reply. - """ - user: Actor -} - -""" -The connection type for SavedReply. -""" -type SavedReplyConnection { - """ - A list of edges. - """ - edges: [SavedReplyEdge] - - """ - A list of nodes. - """ - nodes: [SavedReply] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SavedReplyEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SavedReply -} - -""" -Ordering options for saved reply connections. -""" -input SavedReplyOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order saved replies by. - """ - field: SavedReplyOrderField! -} - -""" -Properties by which saved reply connections can be ordered. -""" -enum SavedReplyOrderField { - """ - Order saved reply by when they were updated. - """ - UPDATED_AT -} - -""" -The results of a search. -""" -union SearchResultItem = App | Issue | MarketplaceListing | Organization | PullRequest | Repository | User - -""" -A list of results that matched against a search query. -""" -type SearchResultItemConnection { - """ - The number of pieces of code that matched the search query. - """ - codeCount: Int! - - """ - A list of edges. - """ - edges: [SearchResultItemEdge] - - """ - The number of issues that matched the search query. - """ - issueCount: Int! - - """ - A list of nodes. - """ - nodes: [SearchResultItem] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - The number of repositories that matched the search query. - """ - repositoryCount: Int! - - """ - The number of users that matched the search query. - """ - userCount: Int! - - """ - The number of wiki pages that matched the search query. - """ - wikiCount: Int! -} - -""" -An edge in a connection. -""" -type SearchResultItemEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SearchResultItem - - """ - Text matches on the result found. - """ - textMatches: [TextMatch] -} - -""" -Represents the individual results of a search. -""" -enum SearchType { - """ - Returns results matching issues in repositories. - """ - ISSUE - - """ - Returns results matching repositories. - """ - REPOSITORY - - """ - Returns results matching users and organizations on GitHub. - """ - USER -} - -""" -A GitHub Security Advisory -""" -type SecurityAdvisory implements Node { - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - This is a long plaintext description of the advisory - """ - description: String! - - """ - The GitHub Security Advisory ID - """ - ghsaId: String! - id: ID! - - """ - A list of identifiers for this advisory - """ - identifiers: [SecurityAdvisoryIdentifier!]! - - """ - The organization that originated the advisory - """ - origin: String! - - """ - When the advisory was published - """ - publishedAt: DateTime! - - """ - A list of references for this advisory - """ - references: [SecurityAdvisoryReference!]! - - """ - The severity of the advisory - """ - severity: SecurityAdvisorySeverity! - - """ - A short plaintext summary of the advisory - """ - summary: String! - - """ - When the advisory was last updated - """ - updatedAt: DateTime! - - """ - Vulnerabilities associated with this Advisory - """ - vulnerabilities( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - An ecosystem to filter vulnerabilities by. - """ - ecosystem: SecurityAdvisoryEcosystem - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for the returned topics. - """ - orderBy: SecurityVulnerabilityOrder = {field: UPDATED_AT, direction: DESC} - - """ - A package name to filter vulnerabilities by. - """ - package: String - - """ - A list of severities to filter vulnerabilities by. - """ - severities: [SecurityAdvisorySeverity!] - ): SecurityVulnerabilityConnection! - - """ - When the advisory was withdrawn, if it has been withdrawn - """ - withdrawnAt: DateTime -} - -""" -The connection type for SecurityAdvisory. -""" -type SecurityAdvisoryConnection { - """ - A list of edges. - """ - edges: [SecurityAdvisoryEdge] - - """ - A list of nodes. - """ - nodes: [SecurityAdvisory] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -The possible ecosystems of a security vulnerability's package. -""" -enum SecurityAdvisoryEcosystem { - """ - Java artifacts hosted at the Maven central repository - """ - MAVEN - - """ - JavaScript packages hosted at npmjs.com - """ - NPM - - """ - .NET packages hosted at the NuGet Gallery - """ - NUGET - - """ - Python packages hosted at PyPI.org - """ - PIP - - """ - Ruby gems hosted at RubyGems.org - """ - RUBYGEMS -} - -""" -An edge in a connection. -""" -type SecurityAdvisoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SecurityAdvisory -} - -""" -A GitHub Security Advisory Identifier -""" -type SecurityAdvisoryIdentifier { - """ - The identifier type, e.g. GHSA, CVE - """ - type: String! - - """ - The identifier - """ - value: String! -} - -""" -An advisory identifier to filter results on. -""" -input SecurityAdvisoryIdentifierFilter { - """ - The identifier type. - """ - type: SecurityAdvisoryIdentifierType! - - """ - The identifier string. Supports exact or partial matching. - """ - value: String! -} - -""" -Identifier formats available for advisories. -""" -enum SecurityAdvisoryIdentifierType { - """ - Common Vulnerabilities and Exposures Identifier. - """ - CVE - - """ - GitHub Security Advisory ID. - """ - GHSA -} - -""" -Ordering options for security advisory connections -""" -input SecurityAdvisoryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order security advisories by. - """ - field: SecurityAdvisoryOrderField! -} - -""" -Properties by which security advisory connections can be ordered. -""" -enum SecurityAdvisoryOrderField { - """ - Order advisories by publication time - """ - PUBLISHED_AT - - """ - Order advisories by update time - """ - UPDATED_AT -} - -""" -An individual package -""" -type SecurityAdvisoryPackage { - """ - The ecosystem the package belongs to, e.g. RUBYGEMS, NPM - """ - ecosystem: SecurityAdvisoryEcosystem! - - """ - The package name - """ - name: String! -} - -""" -An individual package version -""" -type SecurityAdvisoryPackageVersion { - """ - The package name or version - """ - identifier: String! -} - -""" -A GitHub Security Advisory Reference -""" -type SecurityAdvisoryReference { - """ - A publicly accessible reference - """ - url: URI! -} - -""" -Severity of the vulnerability. -""" -enum SecurityAdvisorySeverity { - """ - Critical. - """ - CRITICAL - - """ - High. - """ - HIGH - - """ - Low. - """ - LOW - - """ - Moderate. - """ - MODERATE -} - -""" -An individual vulnerability within an Advisory -""" -type SecurityVulnerability { - """ - The Advisory associated with this Vulnerability - """ - advisory: SecurityAdvisory! - - """ - The first version containing a fix for the vulnerability - """ - firstPatchedVersion: SecurityAdvisoryPackageVersion - - """ - A description of the vulnerable package - """ - package: SecurityAdvisoryPackage! - - """ - The severity of the vulnerability within this package - """ - severity: SecurityAdvisorySeverity! - - """ - When the vulnerability was last updated - """ - updatedAt: DateTime! - - """ - A string that describes the vulnerable package versions. - This string follows a basic syntax with a few forms. - + `= 0.2.0` denotes a single vulnerable version. - + `<= 1.0.8` denotes a version range up to and including the specified version - + `< 0.1.11` denotes a version range up to, but excluding, the specified version - + `>= 4.3.0, < 4.3.5` denotes a version range with a known minimum and maximum version. - + `>= 0.0.1` denotes a version range with a known minimum, but no known maximum - """ - vulnerableVersionRange: String! -} - -""" -The connection type for SecurityVulnerability. -""" -type SecurityVulnerabilityConnection { - """ - A list of edges. - """ - edges: [SecurityVulnerabilityEdge] - - """ - A list of nodes. - """ - nodes: [SecurityVulnerability] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SecurityVulnerabilityEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: SecurityVulnerability -} - -""" -Ordering options for security vulnerability connections -""" -input SecurityVulnerabilityOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order security vulnerabilities by. - """ - field: SecurityVulnerabilityOrderField! -} - -""" -Properties by which security vulnerability connections can be ordered. -""" -enum SecurityVulnerabilityOrderField { - """ - Order vulnerability by update time - """ - UPDATED_AT -} - -""" -Represents an S/MIME signature on a Commit or Tag. -""" -type SmimeSignature implements GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -Represents a sponsor. -""" -type SponsorEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User -} - -""" -Entities that can be sponsored through GitHub Sponsors -""" -interface Sponsorable { - """ - This object's sponsorships as the maintainer. - """ - sponsorshipsAsMaintainer( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether or not to include private sponsorships in the result set - """ - includePrivate: Boolean = false - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - This object's sponsorships as the sponsor. - """ - sponsorshipsAsSponsor( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! -} - -""" -A GitHub Sponsors listing. -""" -type SponsorsListing implements Node { - """ - The full description of the listing. - """ - fullDescription: String! - id: ID! - - """ - The short description of the listing. - """ - shortDescription: String! - - """ - The short name of the listing. - """ - slug: String! -} - -""" -A sponsorship relationship between a sponsor and a maintainer -""" -type Sponsorship implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The entity that is being sponsored - """ - maintainer: User! - - """ - The privacy level for this sponsorship. - """ - privacyLevel: SponsorshipPrivacy! - - """ - The entity that is sponsoring. Returns null if the sponsorship is private - """ - sponsor: User -} - -""" -The connection type for Sponsorship. -""" -type SponsorshipConnection { - """ - A list of edges. - """ - edges: [SponsorshipEdge] - - """ - A list of nodes. - """ - nodes: [Sponsorship] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type SponsorshipEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Sponsorship -} - -""" -Ordering options for sponsorship connections. -""" -input SponsorshipOrder { - """ - The ordering direction. - """ - direction: OrderDirection! -} - -""" -The privacy of a sponsorship -""" -enum SponsorshipPrivacy { - """ - Private - """ - PRIVATE - - """ - Public - """ - PUBLIC -} - -""" -Ways in which star connections can be ordered. -""" -input StarOrder { - """ - The direction in which to order nodes. - """ - direction: OrderDirection! - - """ - The field in which to order nodes by. - """ - field: StarOrderField! -} - -""" -Properties by which star connections can be ordered. -""" -enum StarOrderField { - """ - Allows ordering a list of stars by when they were created. - """ - STARRED_AT -} - -""" -The connection type for User. -""" -type StargazerConnection { - """ - A list of edges. - """ - edges: [StargazerEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user that's starred a repository. -""" -type StargazerEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: User! - - """ - Identifies when the item was starred. - """ - starredAt: DateTime! -} - -""" -Things that can be starred. -""" -interface Starrable { - id: ID! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! -} - -""" -The connection type for Repository. -""" -type StarredRepositoryConnection { - """ - A list of edges. - """ - edges: [StarredRepositoryEdge] - - """ - A list of nodes. - """ - nodes: [Repository] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a starred repository. -""" -type StarredRepositoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: Repository! - - """ - Identifies when the item was starred. - """ - starredAt: DateTime! -} - -""" -Represents a starred topic. -""" -type StarredTopicEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: Topic! - - """ - Identifies when the item was starred. - """ - starredAt: DateTime! -} - -""" -Represents a commit status. -""" -type Status implements Node { - """ - The commit this status is attached to. - """ - commit: Commit - - """ - Looks up an individual status context by context name. - """ - context( - """ - The context name. - """ - name: String! - ): StatusContext - - """ - The individual status contexts for this commit. - """ - contexts: [StatusContext!]! - id: ID! - - """ - The combined commit status. - """ - state: StatusState! -} - -""" -Represents an individual commit status context -""" -type StatusContext implements Node { - """ - The avatar of the OAuth application or the user that created the status - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int = 40 - ): URI - - """ - This commit this status context is attached to. - """ - commit: Commit - - """ - The name of this status context. - """ - context: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The actor who created this status context. - """ - creator: Actor - - """ - The description for this status context. - """ - description: String - id: ID! - - """ - The state of this status context. - """ - state: StatusState! - - """ - The URL for this status context. - """ - targetUrl: URI -} - -""" -The possible commit status states. -""" -enum StatusState { - """ - Status is errored. - """ - ERROR - - """ - Status is expected. - """ - EXPECTED - - """ - Status is failing. - """ - FAILURE - - """ - Status is pending. - """ - PENDING - - """ - Status is successful. - """ - SUCCESS -} - -""" -Autogenerated input type of SubmitPullRequestReview -""" -input SubmitPullRequestReviewInput { - """ - The text field to set on the Pull Request Review. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The event to send to the Pull Request Review. - """ - event: PullRequestReviewEvent! - - """ - The Pull Request Review ID to submit. - """ - pullRequestReviewId: ID! -} - -""" -Autogenerated return type of SubmitPullRequestReview -""" -type SubmitPullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The submitted pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Entities that can be subscribed to for web and email notifications. -""" -interface Subscribable { - id: ID! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -Represents a 'subscribed' event on a given `Subscribable`. -""" -type SubscribedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Object referenced by event. - """ - subscribable: Subscribable! -} - -""" -The possible states of a subscription. -""" -enum SubscriptionState { - """ - The User is never notified. - """ - IGNORED - - """ - The User is notified of all conversations. - """ - SUBSCRIBED - - """ - The User is only notified when participating or @mentioned. - """ - UNSUBSCRIBED -} - -""" -A suggestion to review a pull request based on a user's commit history and review comments. -""" -type SuggestedReviewer { - """ - Is this suggestion based on past commits? - """ - isAuthor: Boolean! - - """ - Is this suggestion based on past review comments? - """ - isCommenter: Boolean! - - """ - Identifies the user suggested to review the pull request. - """ - reviewer: User! -} - -""" -Represents a Git tag. -""" -type Tag implements GitObject & Node { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - id: ID! - - """ - The Git tag message. - """ - message: String - - """ - The Git tag name. - """ - name: String! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! - - """ - Details about the tag author. - """ - tagger: GitActor - - """ - The Git object the tag points to. - """ - target: GitObject! -} - -""" -A team of users in an organization. -""" -type Team implements MemberStatusable & Node & Subscribable { - """ - A list of teams that are ancestors of this team. - """ - ancestors( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): TeamConnection! - - """ - A URL pointing to the team's avatar. - """ - avatarUrl( - """ - The size in pixels of the resulting square image. - """ - size: Int = 400 - ): URI - - """ - List of child teams belonging to this team - """ - childTeams( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether to list immediate child teams or all descendant child teams. - """ - immediateOnly: Boolean = true - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: TeamOrder - - """ - User logins to filter by - """ - userLogins: [String!] - ): TeamConnection! - - """ - The slug corresponding to the organization and team. - """ - combinedSlug: String! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The description of the team. - """ - description: String - - """ - The HTTP path for editing this team - """ - editTeamResourcePath: URI! - - """ - The HTTP URL for editing this team - """ - editTeamUrl: URI! - id: ID! - - """ - A list of pending invitations for users to this team - """ - invitations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationInvitationConnection - - """ - Get the status messages members of this entity have set that are either public or visible only to the organization. - """ - memberStatuses( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for user statuses returned from the connection. - """ - orderBy: UserStatusOrder = {field: UPDATED_AT, direction: DESC} - ): UserStatusConnection! - - """ - A list of users who are members of this team. - """ - members( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter by membership type - """ - membership: TeamMembershipType = ALL - - """ - Order for the connection. - """ - orderBy: TeamMemberOrder - - """ - The search string to look for. - """ - query: String - - """ - Filter by team member role - """ - role: TeamMemberRole - ): TeamMemberConnection! - - """ - The HTTP path for the team' members - """ - membersResourcePath: URI! - - """ - The HTTP URL for the team' members - """ - membersUrl: URI! - - """ - The name of the team. - """ - name: String! - - """ - The HTTP path creating a new team - """ - newTeamResourcePath: URI! - - """ - The HTTP URL creating a new team - """ - newTeamUrl: URI! - - """ - The organization that owns this team. - """ - organization: Organization! - - """ - The parent team of the team. - """ - parentTeam: Team - - """ - The level of privacy the team has. - """ - privacy: TeamPrivacy! - - """ - A list of repositories this team has access to. - """ - repositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for the connection. - """ - orderBy: TeamRepositoryOrder - - """ - The search string to look for. - """ - query: String - ): TeamRepositoryConnection! - - """ - The HTTP path for this team's repositories - """ - repositoriesResourcePath: URI! - - """ - The HTTP URL for this team's repositories - """ - repositoriesUrl: URI! - - """ - The HTTP path for this team - """ - resourcePath: URI! - - """ - The slug corresponding to the team. - """ - slug: String! - - """ - The HTTP path for this team's teams - """ - teamsResourcePath: URI! - - """ - The HTTP URL for this team's teams - """ - teamsUrl: URI! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this team - """ - url: URI! - - """ - Team is adminable by the viewer. - """ - viewerCanAdminister: Boolean! - - """ - Check if the viewer is able to change their subscription status for the repository. - """ - viewerCanSubscribe: Boolean! - - """ - Identifies if the viewer is watching, not watching, or ignoring the subscribable entity. - """ - viewerSubscription: SubscriptionState -} - -""" -Audit log entry for a team.add_member event. -""" -type TeamAddMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a team.add_repository event. -""" -type TeamAddRepositoryAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Metadata for an audit entry with action team.* -""" -interface TeamAuditEntryData { - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI -} - -""" -Audit log entry for a team.change_parent_team event. -""" -type TeamChangeParentTeamAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The new parent team. - """ - parentTeam: Team - - """ - The name of the new parent team - """ - parentTeamName: String - - """ - The name of the former parent team - """ - parentTeamNameWas: String - - """ - The HTTP path for the parent team - """ - parentTeamResourcePath: URI - - """ - The HTTP URL for the parent team - """ - parentTeamUrl: URI - - """ - The former parent team. - """ - parentTeamWas: Team - - """ - The HTTP path for the previous parent team - """ - parentTeamWasResourcePath: URI - - """ - The HTTP URL for the previous parent team - """ - parentTeamWasUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The connection type for Team. -""" -type TeamConnection { - """ - A list of edges. - """ - edges: [TeamEdge] - - """ - A list of nodes. - """ - nodes: [Team] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type TeamEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Team -} - -""" -Represents a team's eligibility to be a child team of another -""" -type TeamEligibilityEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Team -} - -""" -The connection type for User. -""" -type TeamMemberConnection { - """ - A list of edges. - """ - edges: [TeamMemberEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a user who is a member of a team. -""" -type TeamMemberEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The HTTP path to the organization's member access page. - """ - memberAccessResourcePath: URI! - - """ - The HTTP URL to the organization's member access page. - """ - memberAccessUrl: URI! - node: User! - - """ - The role the member has on the team. - """ - role: TeamMemberRole! -} - -""" -Ordering options for team member connections -""" -input TeamMemberOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order team members by. - """ - field: TeamMemberOrderField! -} - -""" -Properties by which team member connections can be ordered. -""" -enum TeamMemberOrderField { - """ - Order team members by creation time - """ - CREATED_AT - - """ - Order team members by login - """ - LOGIN -} - -""" -The possible team member roles; either 'maintainer' or 'member'. -""" -enum TeamMemberRole { - """ - A team maintainer has permission to add and remove team members. - """ - MAINTAINER - - """ - A team member has no administrative permissions on the team. - """ - MEMBER -} - -""" -Defines which types of team members are included in the returned list. Can be one of IMMEDIATE, CHILD_TEAM or ALL. -""" -enum TeamMembershipType { - """ - Includes immediate and child team members for the team. - """ - ALL - - """ - Includes only child team members for the team. - """ - CHILD_TEAM - - """ - Includes only immediate members of the team. - """ - IMMEDIATE -} - -""" -Ways in which team connections can be ordered. -""" -input TeamOrder { - """ - The direction in which to order nodes. - """ - direction: OrderDirection! - - """ - The field in which to order nodes by. - """ - field: TeamOrderField! -} - -""" -Properties by which team connections can be ordered. -""" -enum TeamOrderField { - """ - Allows ordering a list of teams by name. - """ - NAME -} - -""" -The possible team privacy values. -""" -enum TeamPrivacy { - """ - A secret team can only be seen by its members. - """ - SECRET - - """ - A visible team can be seen and @mentioned by every member of the organization. - """ - VISIBLE -} - -""" -Represents a connection between a team (parent) and a project (child). -""" -type TeamProjectEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The parent team that grants inherited permission to this project - """ - inheritedPermissionOrigin: Team - - """ - The item at the end of the edge. - """ - node: Project - - """ - The HTTP path for this team's project - """ - teamProjectResourcePath: URI! - - """ - The HTTP URL for this team's project - """ - teamProjectUrl: URI! -} - -""" -Audit log entry for a team.remove_member event. -""" -type TeamRemoveMemberAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -Audit log entry for a team.remove_repository event. -""" -type TeamRemoveRepositoryAuditEntry implements AuditEntry & Node & OrganizationAuditEntryData & RepositoryAuditEntryData & TeamAuditEntryData { - """ - The action name - """ - action: String! - - """ - The user who initiated the action - """ - actor: AuditEntryActor - - """ - The IP address of the actor - """ - actorIp: String - - """ - A readable representation of the actor's location - """ - actorLocation: ActorLocation - - """ - The username of the user who initiated the action - """ - actorLogin: String - - """ - The HTTP path for the actor. - """ - actorResourcePath: URI - - """ - The HTTP URL for the actor. - """ - actorUrl: URI - - """ - The time the action was initiated - """ - createdAt: PreciseDateTime! - id: ID! - - """ - Whether the team was mapped to an LDAP Group. - """ - isLdapMapped: Boolean - - """ - The Organization associated with the Audit Entry. - """ - organization: Organization - - """ - The name of the Organization. - """ - organizationName: String - - """ - The HTTP path for the organization - """ - organizationResourcePath: URI - - """ - The HTTP URL for the organization - """ - organizationUrl: URI - - """ - The repository associated with the action - """ - repository: Repository - - """ - The name of the repository - """ - repositoryName: String - - """ - The HTTP path for the repository - """ - repositoryResourcePath: URI - - """ - The HTTP URL for the repository - """ - repositoryUrl: URI - - """ - The team associated with the action - """ - team: Team - - """ - The name of the team - """ - teamName: String - - """ - The HTTP path for this team - """ - teamResourcePath: URI - - """ - The HTTP URL for this team - """ - teamUrl: URI - - """ - The user affected by the action - """ - user: User - - """ - For actions involving two users, the actor is the initiator and the user is the affected user. - """ - userLogin: String - - """ - The HTTP path for the user. - """ - userResourcePath: URI - - """ - The HTTP URL for the user. - """ - userUrl: URI -} - -""" -The connection type for Repository. -""" -type TeamRepositoryConnection { - """ - A list of edges. - """ - edges: [TeamRepositoryEdge] - - """ - A list of nodes. - """ - nodes: [Repository] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -Represents a team repository. -""" -type TeamRepositoryEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - node: Repository! - - """ - The permission level the team has on the repository - """ - permission: RepositoryPermission! -} - -""" -Ordering options for team repository connections -""" -input TeamRepositoryOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order repositories by. - """ - field: TeamRepositoryOrderField! -} - -""" -Properties by which team repository connections can be ordered. -""" -enum TeamRepositoryOrderField { - """ - Order repositories by creation time - """ - CREATED_AT - - """ - Order repositories by name - """ - NAME - - """ - Order repositories by permission - """ - PERMISSION - - """ - Order repositories by push time - """ - PUSHED_AT - - """ - Order repositories by number of stargazers - """ - STARGAZERS - - """ - Order repositories by update time - """ - UPDATED_AT -} - -""" -The role of a user on a team. -""" -enum TeamRole { - """ - User has admin rights on the team. - """ - ADMIN - - """ - User is a member of the team. - """ - MEMBER -} - -""" -A text match within a search result. -""" -type TextMatch { - """ - The specific text fragment within the property matched on. - """ - fragment: String! - - """ - Highlights within the matched fragment. - """ - highlights: [TextMatchHighlight!]! - - """ - The property matched on. - """ - property: String! -} - -""" -Represents a single highlight in a search result match. -""" -type TextMatchHighlight { - """ - The indice in the fragment where the matched text begins. - """ - beginIndice: Int! - - """ - The indice in the fragment where the matched text ends. - """ - endIndice: Int! - - """ - The text matched. - """ - text: String! -} - -""" -A topic aggregates entities that are related to a subject. -""" -type Topic implements Node & Starrable { - id: ID! - - """ - The topic's name. - """ - name: String! - - """ - A list of related topics, including aliases of this topic, sorted with the most relevant - first. Returns up to 10 Topics. - """ - relatedTopics( - """ - How many topics to return. - """ - first: Int = 3 - ): [Topic!]! - - """ - A list of users who have starred this starrable. - """ - stargazers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - ): StargazerConnection! - - """ - Returns a boolean indicating whether the viewing user has starred this starrable. - """ - viewerHasStarred: Boolean! -} - -""" -Metadata for an audit entry with a topic. -""" -interface TopicAuditEntryData { - """ - The name of the topic added to the repository - """ - topic: Topic - - """ - The name of the topic added to the repository - """ - topicName: String -} - -""" -The connection type for Topic. -""" -type TopicConnection { - """ - A list of edges. - """ - edges: [TopicEdge] - - """ - A list of nodes. - """ - nodes: [Topic] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type TopicEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: Topic -} - -""" -Reason that the suggested topic is declined. -""" -enum TopicSuggestionDeclineReason { - """ - The suggested topic is not relevant to the repository. - """ - NOT_RELEVANT - - """ - The viewer does not like the suggested topic. - """ - PERSONAL_PREFERENCE - - """ - The suggested topic is too general for the repository. - """ - TOO_GENERAL - - """ - The suggested topic is too specific for the repository (e.g. #ruby-on-rails-version-4-2-1). - """ - TOO_SPECIFIC -} - -""" -Autogenerated input type of TransferIssue -""" -input TransferIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the issue to be transferred - """ - issueId: ID! - - """ - The Node ID of the repository the issue should be transferred to - """ - repositoryId: ID! -} - -""" -Autogenerated return type of TransferIssue -""" -type TransferIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue that was transferred - """ - issue: Issue -} - -""" -Represents a 'transferred' event on a given issue or pull request. -""" -type TransferredEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - The repository this came from - """ - fromRepository: Repository - id: ID! - - """ - Identifies the issue associated with the event. - """ - issue: Issue! -} - -""" -Represents a Git tree. -""" -type Tree implements GitObject & Node { - """ - An abbreviated version of the Git object ID - """ - abbreviatedOid: String! - - """ - The HTTP path for this Git object - """ - commitResourcePath: URI! - - """ - The HTTP URL for this Git object - """ - commitUrl: URI! - - """ - A list of tree entries. - """ - entries: [TreeEntry!] - id: ID! - - """ - The Git object ID - """ - oid: GitObjectID! - - """ - The Repository the Git object belongs to - """ - repository: Repository! -} - -""" -Represents a Git tree entry. -""" -type TreeEntry { - """ - Entry file mode. - """ - mode: Int! - - """ - Entry file name. - """ - name: String! - - """ - Entry file object. - """ - object: GitObject - - """ - Entry file Git object ID. - """ - oid: GitObjectID! - - """ - The Repository the tree entry belongs to - """ - repository: Repository! - - """ - Entry file type. - """ - type: String! -} - -""" -An RFC 3986, RFC 3987, and RFC 6570 (level 4) compliant URI string. -""" -scalar URI - -""" -Represents an 'unassigned' event on any assignable object. -""" -type UnassignedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the assignable associated with the event. - """ - assignable: Assignable! - - """ - Identifies the user or mannequin that was unassigned. - """ - assignee: Assignee - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the subject (user) who was unassigned. - """ - user: User @deprecated(reason: "Assignees can now be mannequins. Use the `assignee` field instead. Removal on 2020-01-01 UTC.") -} - -""" -Represents a type that can be retrieved by a URL. -""" -interface UniformResourceLocatable { - """ - The HTML path to this resource. - """ - resourcePath: URI! - - """ - The URL to this resource. - """ - url: URI! -} - -""" -Represents an unknown signature on a Commit or Tag. -""" -type UnknownSignature implements GitSignature { - """ - Email used to sign this object. - """ - email: String! - - """ - True if the signature is valid and verified by GitHub. - """ - isValid: Boolean! - - """ - Payload for GPG signing object. Raw ODB object without the signature header. - """ - payload: String! - - """ - ASCII-armored signature header from object. - """ - signature: String! - - """ - GitHub user corresponding to the email signing this commit. - """ - signer: User - - """ - The state of this signature. `VALID` if signature is valid and verified by - GitHub, otherwise represents reason why signature is considered invalid. - """ - state: GitSignatureState! - - """ - True if the signature was made with GitHub's signing key. - """ - wasSignedByGitHub: Boolean! -} - -""" -Represents an 'unlabeled' event on a given issue or pull request. -""" -type UnlabeledEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the label associated with the 'unlabeled' event. - """ - label: Label! - - """ - Identifies the `Labelable` associated with the event. - """ - labelable: Labelable! -} - -""" -Autogenerated input type of UnlinkRepositoryFromProject -""" -input UnlinkRepositoryFromProjectInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Project linked to the Repository. - """ - projectId: ID! - - """ - The ID of the Repository linked to the Project. - """ - repositoryId: ID! -} - -""" -Autogenerated return type of UnlinkRepositoryFromProject -""" -type UnlinkRepositoryFromProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The linked Project. - """ - project: Project - - """ - The linked Repository. - """ - repository: Repository -} - -""" -Autogenerated input type of UnlockLockable -""" -input UnlockLockableInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue or pull request to be unlocked. - """ - lockableId: ID! -} - -""" -Autogenerated return type of UnlockLockable -""" -type UnlockLockablePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The item that was unlocked. - """ - unlockedRecord: Lockable -} - -""" -Represents an 'unlocked' event on a given issue or pull request. -""" -type UnlockedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Object that was unlocked. - """ - lockable: Lockable! -} - -""" -Autogenerated input type of UnmarkIssueAsDuplicate -""" -input UnmarkIssueAsDuplicateInput { - """ - ID of the issue or pull request currently considered canonical/authoritative/original. - """ - canonicalId: ID! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - ID of the issue or pull request currently marked as a duplicate. - """ - duplicateId: ID! -} - -""" -Autogenerated return type of UnmarkIssueAsDuplicate -""" -type UnmarkIssueAsDuplicatePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue or pull request that was marked as a duplicate. - """ - duplicate: IssueOrPullRequest -} - -""" -Autogenerated input type of UnminimizeComment -""" -input UnminimizeCommentInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the subject to modify. - """ - subjectId: ID! -} - -""" -Autogenerated input type of UnpinIssue -""" -input UnpinIssueInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the issue to be unpinned - """ - issueId: ID! -} - -""" -Represents an 'unpinned' event on a given issue or pull request. -""" -type UnpinnedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Identifies the issue associated with the event. - """ - issue: Issue! -} - -""" -Autogenerated input type of UnresolveReviewThread -""" -input UnresolveReviewThreadInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the thread to unresolve - """ - threadId: ID! -} - -""" -Autogenerated return type of UnresolveReviewThread -""" -type UnresolveReviewThreadPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The thread to resolve. - """ - thread: PullRequestReviewThread -} - -""" -Represents an 'unsubscribed' event on a given `Subscribable`. -""" -type UnsubscribedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - Object referenced by event. - """ - subscribable: Subscribable! -} - -""" -Entities that can be updated. -""" -interface Updatable { - """ - Check if the current viewer can update this object. - """ - viewerCanUpdate: Boolean! -} - -""" -Comments that can be updated. -""" -interface UpdatableComment { - """ - Reasons why the current viewer can not update this comment. - """ - viewerCannotUpdateReasons: [CommentCannotUpdateReason!]! -} - -""" -Autogenerated input type of UpdateBranchProtectionRule -""" -input UpdateBranchProtectionRuleInput { - """ - The global relay id of the branch protection rule to be updated. - """ - branchProtectionRuleId: ID! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Will new commits pushed to matching branches dismiss pull request review approvals. - """ - dismissesStaleReviews: Boolean - - """ - Can admins overwrite branch protection. - """ - isAdminEnforced: Boolean - - """ - The glob-like pattern used to determine matching branches. - """ - pattern: String - - """ - A list of User, Team or App IDs allowed to push to matching branches. - """ - pushActorIds: [ID!] - - """ - Number of approving reviews required to update matching branches. - """ - requiredApprovingReviewCount: Int - - """ - List of required status check contexts that must pass for commits to be accepted to matching branches. - """ - requiredStatusCheckContexts: [String!] - - """ - Are approving reviews required to update matching branches. - """ - requiresApprovingReviews: Boolean - - """ - Are reviews from code owners required to update matching branches. - """ - requiresCodeOwnerReviews: Boolean - - """ - Are commits required to be signed. - """ - requiresCommitSignatures: Boolean - - """ - Are status checks required to update matching branches. - """ - requiresStatusChecks: Boolean - - """ - Are branches required to be up to date before merging. - """ - requiresStrictStatusChecks: Boolean - - """ - Is pushing to matching branches restricted. - """ - restrictsPushes: Boolean - - """ - Is dismissal of pull request reviews restricted. - """ - restrictsReviewDismissals: Boolean - - """ - A list of User or Team IDs allowed to dismiss reviews on pull requests targeting matching branches. - """ - reviewDismissalActorIds: [ID!] -} - -""" -Autogenerated return type of UpdateBranchProtectionRule -""" -type UpdateBranchProtectionRulePayload { - """ - The newly created BranchProtectionRule. - """ - branchProtectionRule: BranchProtectionRule - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String -} - -""" -Autogenerated input type of UpdateEnterpriseActionExecutionCapabilitySetting -""" -input UpdateEnterpriseActionExecutionCapabilitySettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can create repositories setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseAdministratorRole -""" -input UpdateEnterpriseAdministratorRoleInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Enterprise which the admin belongs to. - """ - enterpriseId: ID! - - """ - The login of a administrator whose role is being changed. - """ - login: String! -} - -""" -Autogenerated input type of UpdateEnterpriseAllowPrivateRepositoryForkingSetting -""" -input UpdateEnterpriseAllowPrivateRepositoryForkingSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the allow private repository forking setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseDefaultRepositoryPermissionSetting -""" -input UpdateEnterpriseDefaultRepositoryPermissionSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the default repository permission setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanChangeRepositoryVisibilitySetting -""" -input UpdateEnterpriseMembersCanChangeRepositoryVisibilitySettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can change repository visibility setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanCreateRepositoriesSetting -""" -input UpdateEnterpriseMembersCanCreateRepositoriesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can create repositories setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanDeleteIssuesSetting -""" -input UpdateEnterpriseMembersCanDeleteIssuesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can delete issues setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanDeleteRepositoriesSetting -""" -input UpdateEnterpriseMembersCanDeleteRepositoriesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can delete repositories setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanInviteCollaboratorsSetting -""" -input UpdateEnterpriseMembersCanInviteCollaboratorsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can invite collaborators setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanMakePurchasesSetting -""" -input UpdateEnterpriseMembersCanMakePurchasesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can make purchases setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanUpdateProtectedBranchesSetting -""" -input UpdateEnterpriseMembersCanUpdateProtectedBranchesSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can update protected branches setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseMembersCanViewDependencyInsightsSetting -""" -input UpdateEnterpriseMembersCanViewDependencyInsightsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the members can view dependency insights setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseOrganizationProjectsSetting -""" -input UpdateEnterpriseOrganizationProjectsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the organization projects setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseProfile -""" -input UpdateEnterpriseProfileInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The description of the enterprise. - """ - description: String - - """ - The Enterprise ID to update. - """ - enterpriseId: ID! - - """ - The location of the enterprise. - """ - location: String - - """ - The name of the enterprise. - """ - name: String - - """ - The URL of the enterprise's website. - """ - websiteUrl: String -} - -""" -Autogenerated input type of UpdateEnterpriseRepositoryProjectsSetting -""" -input UpdateEnterpriseRepositoryProjectsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the repository projects setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseTeamDiscussionsSetting -""" -input UpdateEnterpriseTeamDiscussionsSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the team discussions setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateEnterpriseTwoFactorAuthenticationRequiredSetting -""" -input UpdateEnterpriseTwoFactorAuthenticationRequiredSettingInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the enterprise on which to set the two factor authentication required setting. - """ - enterpriseId: ID! -} - -""" -Autogenerated input type of UpdateIssueComment -""" -input UpdateIssueCommentInput { - """ - The updated text of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the IssueComment to modify. - """ - id: ID! -} - -""" -Autogenerated return type of UpdateIssueComment -""" -type UpdateIssueCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated comment. - """ - issueComment: IssueComment -} - -""" -Autogenerated input type of UpdateIssue -""" -input UpdateIssueInput { - """ - An array of Node IDs of users for this issue. - """ - assigneeIds: [ID!] - - """ - The body for the issue description. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The ID of the Issue to modify. - """ - id: ID! - - """ - An array of Node IDs of labels for this issue. - """ - labelIds: [ID!] - - """ - The Node ID of the milestone for this issue. - """ - milestoneId: ID - - """ - An array of Node IDs for projects associated with this issue. - """ - projectIds: [ID!] - - """ - The desired issue state. - """ - state: IssueState - - """ - The title for the issue. - """ - title: String -} - -""" -Autogenerated return type of UpdateIssue -""" -type UpdateIssuePayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The issue. - """ - issue: Issue -} - -""" -Autogenerated input type of UpdateProjectCard -""" -input UpdateProjectCardInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Whether or not the ProjectCard should be archived - """ - isArchived: Boolean - - """ - The note of ProjectCard. - """ - note: String - - """ - The ProjectCard ID to update. - """ - projectCardId: ID! -} - -""" -Autogenerated return type of UpdateProjectCard -""" -type UpdateProjectCardPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated ProjectCard. - """ - projectCard: ProjectCard -} - -""" -Autogenerated input type of UpdateProjectColumn -""" -input UpdateProjectColumnInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of project column. - """ - name: String! - - """ - The ProjectColumn ID to update. - """ - projectColumnId: ID! -} - -""" -Autogenerated return type of UpdateProjectColumn -""" -type UpdateProjectColumnPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated project column. - """ - projectColumn: ProjectColumn -} - -""" -Autogenerated input type of UpdateProject -""" -input UpdateProjectInput { - """ - The description of project. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The name of project. - """ - name: String - - """ - The Project ID to update. - """ - projectId: ID! - - """ - Whether the project is public or not. - """ - public: Boolean - - """ - Whether the project is open or closed. - """ - state: ProjectState -} - -""" -Autogenerated return type of UpdateProject -""" -type UpdateProjectPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated project. - """ - project: Project -} - -""" -Autogenerated input type of UpdatePullRequest -""" -input UpdatePullRequestInput { - """ - The name of the branch you want your changes pulled into. This should be an existing branch - on the current repository. - """ - baseRefName: String - - """ - The contents of the pull request. - """ - body: String - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Indicates whether maintainers can modify the pull request. - """ - maintainerCanModify: Boolean - - """ - The Node ID of the pull request. - """ - pullRequestId: ID! - - """ - The title of the pull request. - """ - title: String -} - -""" -Autogenerated return type of UpdatePullRequest -""" -type UpdatePullRequestPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated pull request. - """ - pullRequest: PullRequest -} - -""" -Autogenerated input type of UpdatePullRequestReviewComment -""" -input UpdatePullRequestReviewCommentInput { - """ - The text of the comment. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the comment to modify. - """ - pullRequestReviewCommentId: ID! -} - -""" -Autogenerated return type of UpdatePullRequestReviewComment -""" -type UpdatePullRequestReviewCommentPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated comment. - """ - pullRequestReviewComment: PullRequestReviewComment -} - -""" -Autogenerated input type of UpdatePullRequestReview -""" -input UpdatePullRequestReviewInput { - """ - The contents of the pull request review body. - """ - body: String! - - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the pull request review to modify. - """ - pullRequestReviewId: ID! -} - -""" -Autogenerated return type of UpdatePullRequestReview -""" -type UpdatePullRequestReviewPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated pull request review. - """ - pullRequestReview: PullRequestReview -} - -""" -Autogenerated input type of UpdateRef -""" -input UpdateRefInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Permit updates of branch Refs that are not fast-forwards? - """ - force: Boolean = false - - """ - The GitObjectID that the Ref shall be updated to target. - """ - oid: GitObjectID! - - """ - The Node ID of the Ref to be updated. - """ - refId: ID! -} - -""" -Autogenerated return type of UpdateRef -""" -type UpdateRefPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated Ref. - """ - ref: Ref -} - -""" -Autogenerated input type of UpdateRepository -""" -input UpdateRepositoryInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - A new description for the repository. Pass an empty string to erase the existing description. - """ - description: String - - """ - Indicates if the repository should have the issues feature enabled. - """ - hasIssuesEnabled: Boolean - - """ - Indicates if the repository should have the project boards feature enabled. - """ - hasProjectsEnabled: Boolean - - """ - Indicates if the repository should have the wiki feature enabled. - """ - hasWikiEnabled: Boolean - - """ - The URL for a web page about this repository. Pass an empty string to erase the existing URL. - """ - homepageUrl: URI - - """ - The new name of the repository. - """ - name: String - - """ - The ID of the repository to update. - """ - repositoryId: ID! - - """ - Whether this repository should be marked as a template such that anyone who - can access it can create new repositories with the same files and directory structure. - """ - template: Boolean -} - -""" -Autogenerated return type of UpdateRepository -""" -type UpdateRepositoryPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The updated repository. - """ - repository: Repository -} - -""" -Autogenerated input type of UpdateSubscription -""" -input UpdateSubscriptionInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The new state of the subscription. - """ - state: SubscriptionState! - - """ - The Node ID of the subscribable object to modify. - """ - subscribableId: ID! -} - -""" -Autogenerated return type of UpdateSubscription -""" -type UpdateSubscriptionPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The input subscribable entity. - """ - subscribable: Subscribable -} - -""" -Autogenerated input type of UpdateTopics -""" -input UpdateTopicsInput { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - The Node ID of the repository. - """ - repositoryId: ID! - - """ - An array of topic names. - """ - topicNames: [String!]! -} - -""" -Autogenerated return type of UpdateTopics -""" -type UpdateTopicsPayload { - """ - A unique identifier for the client performing the mutation. - """ - clientMutationId: String - - """ - Names of the provided topics that are not valid. - """ - invalidTopicNames: [String!] - - """ - The updated repository. - """ - repository: Repository -} - -""" -A user is an individual's account on GitHub that owns repositories and can make new content. -""" -type User implements Actor & Node & ProfileOwner & ProjectOwner & RegistryPackageOwner & RegistryPackageSearch & RepositoryOwner & Sponsorable & UniformResourceLocatable { - """ - Determine if this repository owner has any items that can be pinned to their profile. - """ - anyPinnableItems( - """ - Filter to only a particular kind of pinnable item. - """ - type: PinnableItemType - ): Boolean! - - """ - A URL pointing to the user's public avatar. - """ - avatarUrl( - """ - The size of the resulting square image. - """ - size: Int - ): URI! - - """ - The user's public profile bio. - """ - bio: String - - """ - The user's public profile bio as HTML. - """ - bioHTML: HTML! - - """ - A list of commit comments made by this user. - """ - commitComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): CommitCommentConnection! - - """ - The user's public profile company. - """ - company: String - - """ - The user's public profile company as HTML. - """ - companyHTML: HTML! - - """ - The collection of contributions this user has made to different repositories. - """ - contributionsCollection( - """ - Only contributions made at this time or later will be counted. If omitted, defaults to a year ago. - """ - from: DateTime - - """ - The ID of the organization used to filter contributions. - """ - organizationID: ID - - """ - Only contributions made before and up to and including this time will be - counted. If omitted, defaults to the current time. - """ - to: DateTime - ): ContributionsCollection! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the primary key from the database. - """ - databaseId: Int - - """ - The user's publicly visible profile email. - """ - email: String! - - """ - A list of users the given user is followed by. - """ - followers( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): FollowerConnection! - - """ - A list of users the given user is following. - """ - following( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): FollowingConnection! - - """ - Find gist by repo name. - """ - gist( - """ - The gist name to find. - """ - name: String! - ): Gist - - """ - A list of gist comments made by this user. - """ - gistComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): GistCommentConnection! - - """ - A list of the Gists the user has created. - """ - gists( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for gists returned from the connection - """ - orderBy: GistOrder - - """ - Filters Gists according to privacy. - """ - privacy: GistPrivacy - ): GistConnection! - id: ID! - - """ - Whether or not this user is a participant in the GitHub Security Bug Bounty. - """ - isBountyHunter: Boolean! - - """ - Whether or not this user is a participant in the GitHub Campus Experts Program. - """ - isCampusExpert: Boolean! - - """ - Whether or not this user is a GitHub Developer Program member. - """ - isDeveloperProgramMember: Boolean! - - """ - Whether or not this user is a GitHub employee. - """ - isEmployee: Boolean! - - """ - Whether or not the user has marked themselves as for hire. - """ - isHireable: Boolean! - - """ - Whether or not this user is a site administrator. - """ - isSiteAdmin: Boolean! - - """ - Whether or not this user is the viewing user. - """ - isViewer: Boolean! - - """ - A list of issue comments made by this user. - """ - issueComments( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): IssueCommentConnection! - - """ - A list of issues associated with this user. - """ - issues( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Filtering options for issues returned from the connection. - """ - filterBy: IssueFilters - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for issues returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the issues by. - """ - states: [IssueState!] - ): IssueConnection! - - """ - Showcases a selection of repositories and gists that the profile owner has - either curated or that have been selected automatically based on popularity. - """ - itemShowcase: ProfileItemShowcase! - - """ - The user's public profile location. - """ - location: String - - """ - The username used to login. - """ - login: String! - - """ - The user's public profile name. - """ - name: String - - """ - Find an organization by its login that the user belongs to. - """ - organization( - """ - The login of the organization to find. - """ - login: String! - ): Organization - - """ - A list of organizations the user belongs to. - """ - organizations( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): OrganizationConnection! - - """ - A list of repositories and gists this profile owner can pin to their profile. - """ - pinnableItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinnable items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - A list of repositories and gists this profile owner has pinned to their profile - """ - pinnedItems( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter the types of pinned items that are returned. - """ - types: [PinnableItemType!] - ): PinnableItemConnection! - - """ - Returns how many more items this profile owner can pin to their profile. - """ - pinnedItemsRemaining: Int! - - """ - A list of repositories this user has pinned to their profile - """ - pinnedRepositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! @deprecated(reason: "pinnedRepositories will be removed Use ProfileOwner.pinnedItems instead. Removal on 2019-10-01 UTC.") - - """ - Find project by number. - """ - project( - """ - The project number to find. - """ - number: Int! - ): Project - - """ - A list of projects under the owner. - """ - projects( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for projects returned from the connection - """ - orderBy: ProjectOrder - - """ - Query to search projects by, currently only searching by name. - """ - search: String - - """ - A list of states to filter the projects by. - """ - states: [ProjectState!] - ): ProjectConnection! - - """ - The HTTP path listing user's projects - """ - projectsResourcePath: URI! - - """ - The HTTP URL listing user's projects - """ - projectsUrl: URI! - - """ - A list of public keys associated with this user. - """ - publicKeys( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - ): PublicKeyConnection! - - """ - A list of pull requests associated with this user. - """ - pullRequests( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - The base ref name to filter the pull requests by. - """ - baseRefName: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - The head ref name to filter the pull requests by. - """ - headRefName: String - - """ - A list of label names to filter the pull requests by. - """ - labels: [String!] - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for pull requests returned from the connection. - """ - orderBy: IssueOrder - - """ - A list of states to filter the pull requests by. - """ - states: [PullRequestState!] - ): PullRequestConnection! - - """ - A list of registry packages under the owner. - """ - registryPackages( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Find registry package by name. - """ - name: String - - """ - Find registry packages by their names. - """ - names: [String] - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Filter registry package by whether it is publicly visible - """ - publicOnly: Boolean = false - - """ - Filter registry package by type (string). - """ - registryPackageType: String - - """ - Find registry packages in a repository. - """ - repositoryId: ID - ): RegistryPackageConnection! - - """ - A list of registry packages for a particular search query. - """ - registryPackagesForQuery( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Filter registry package by type. - """ - packageType: RegistryPackageType - - """ - Find registry package by search query. - """ - query: String - ): RegistryPackageConnection! - - """ - A list of repositories that the user owns. - """ - repositories( - """ - Array of viewer's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - current viewer owns. - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they are forks of another repository - """ - isFork: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - A list of repositories that the user recently contributed to. - """ - repositoriesContributedTo( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - If non-null, include only the specified types of contributions. The - GitHub.com UI uses [COMMIT, ISSUE, PULL_REQUEST, REPOSITORY] - """ - contributionTypes: [RepositoryContributionType] - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If true, include user repositories - """ - includeUserRepositories: Boolean - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - Find Repository. - """ - repository( - """ - Name of Repository to find. - """ - name: String! - ): Repository - - """ - The HTTP path for this user - """ - resourcePath: URI! - - """ - Replies this user has saved - """ - savedReplies( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - The field to order saved replies by. - """ - orderBy: SavedReplyOrder = {field: UPDATED_AT, direction: DESC} - ): SavedReplyConnection - - """ - This object's sponsorships as the maintainer. - """ - sponsorshipsAsMaintainer( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Whether or not to include private sponsorships in the result set - """ - includePrivate: Boolean = false - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - This object's sponsorships as the sponsor. - """ - sponsorshipsAsSponsor( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for sponsorships returned from this connection. If left - blank, the sponsorships will be ordered based on relevancy to the viewer. - """ - orderBy: SponsorshipOrder - ): SponsorshipConnection! - - """ - Repositories the user has starred. - """ - starredRepositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Order for connection - """ - orderBy: StarOrder - - """ - Filters starred repositories to only return repositories owned by the viewer. - """ - ownedByViewer: Boolean - ): StarredRepositoryConnection! - - """ - The user's description of what they're currently doing. - """ - status: UserStatus - - """ - Repositories the user has contributed to, ordered by contribution rank, plus repositories the user has created - """ - topRepositories( - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder! - - """ - How far back in time to fetch contributed repositories - """ - since: DateTime - ): RepositoryConnection! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The HTTP URL for this user - """ - url: URI! - - """ - Can the viewer pin repositories and gists to the profile? - """ - viewerCanChangePinnedItems: Boolean! - - """ - Can the current viewer create new projects on this owner. - """ - viewerCanCreateProjects: Boolean! - - """ - Whether or not the viewer is able to follow the user. - """ - viewerCanFollow: Boolean! - - """ - Whether or not this user is followed by the viewer. - """ - viewerIsFollowing: Boolean! - - """ - A list of repositories the given user is watching. - """ - watching( - """ - Affiliation options for repositories returned from the connection - """ - affiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR, ORGANIZATION_MEMBER] - - """ - Returns the elements in the list that come after the specified cursor. - """ - after: String - - """ - Returns the elements in the list that come before the specified cursor. - """ - before: String - - """ - Returns the first _n_ elements from the list. - """ - first: Int - - """ - If non-null, filters repositories according to whether they have been locked - """ - isLocked: Boolean - - """ - Returns the last _n_ elements from the list. - """ - last: Int - - """ - Ordering options for repositories returned from the connection - """ - orderBy: RepositoryOrder - - """ - Array of owner's affiliation options for repositories returned from the - connection. For example, OWNER will include only repositories that the - organization or user being viewed owns. - """ - ownerAffiliations: [RepositoryAffiliation] = [OWNER, COLLABORATOR] - - """ - If non-null, filters repositories according to privacy - """ - privacy: RepositoryPrivacy - ): RepositoryConnection! - - """ - A URL pointing to the user's public website/blog. - """ - websiteUrl: URI -} - -""" -The possible durations that a user can be blocked for. -""" -enum UserBlockDuration { - """ - The user was blocked for 1 day - """ - ONE_DAY - - """ - The user was blocked for 30 days - """ - ONE_MONTH - - """ - The user was blocked for 7 days - """ - ONE_WEEK - - """ - The user was blocked permanently - """ - PERMANENT - - """ - The user was blocked for 3 days - """ - THREE_DAYS -} - -""" -Represents a 'user_blocked' event on a given user. -""" -type UserBlockedEvent implements Node { - """ - Identifies the actor who performed the event. - """ - actor: Actor - - """ - Number of days that the user was blocked for. - """ - blockDuration: UserBlockDuration! - - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - id: ID! - - """ - The user who was blocked. - """ - subject: User -} - -""" -The connection type for User. -""" -type UserConnection { - """ - A list of edges. - """ - edges: [UserEdge] - - """ - A list of nodes. - """ - nodes: [User] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edit on user content -""" -type UserContentEdit implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - Identifies the date and time when the object was deleted. - """ - deletedAt: DateTime - - """ - The actor who deleted this content - """ - deletedBy: Actor - - """ - A summary of the changes for this edit - """ - diff: String - - """ - When this content was edited - """ - editedAt: DateTime! - - """ - The actor who edited this content - """ - editor: Actor - id: ID! - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! -} - -""" -A list of edits to content. -""" -type UserContentEditConnection { - """ - A list of edges. - """ - edges: [UserContentEditEdge] - - """ - A list of nodes. - """ - nodes: [UserContentEdit] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type UserContentEditEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: UserContentEdit -} - -""" -Represents a user. -""" -type UserEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: User -} - -""" -The user's description of what they're currently doing. -""" -type UserStatus implements Node { - """ - Identifies the date and time when the object was created. - """ - createdAt: DateTime! - - """ - An emoji summarizing the user's status. - """ - emoji: String - - """ - The status emoji as HTML. - """ - emojiHTML: HTML - - """ - If set, the status will not be shown after this date. - """ - expiresAt: DateTime - - """ - ID of the object. - """ - id: ID! - - """ - Whether this status indicates the user is not fully available on GitHub. - """ - indicatesLimitedAvailability: Boolean! - - """ - A brief message describing what the user is doing. - """ - message: String - - """ - The organization whose members can see this status. If null, this status is publicly visible. - """ - organization: Organization - - """ - Identifies the date and time when the object was last updated. - """ - updatedAt: DateTime! - - """ - The user who has this status. - """ - user: User! -} - -""" -The connection type for UserStatus. -""" -type UserStatusConnection { - """ - A list of edges. - """ - edges: [UserStatusEdge] - - """ - A list of nodes. - """ - nodes: [UserStatus] - - """ - Information to aid in pagination. - """ - pageInfo: PageInfo! - - """ - Identifies the total count of items in the connection. - """ - totalCount: Int! -} - -""" -An edge in a connection. -""" -type UserStatusEdge { - """ - A cursor for use in pagination. - """ - cursor: String! - - """ - The item at the end of the edge. - """ - node: UserStatus -} - -""" -Ordering options for user status connections. -""" -input UserStatusOrder { - """ - The ordering direction. - """ - direction: OrderDirection! - - """ - The field to order user statuses by. - """ - field: UserStatusOrderField! -} - -""" -Properties by which user status connections can be ordered. -""" -enum UserStatusOrderField { - """ - Order user statuses by when they were updated. - """ - UPDATED_AT -} - -""" -A valid x509 certificate string -""" -scalar X509Certificate \ No newline at end of file diff --git a/pkg/astparser/testdata/introspection_normalized.graphql b/pkg/astparser/testdata/introspection_normalized.graphql deleted file mode 100644 index 1ed1b8b1a..000000000 --- a/pkg/astparser/testdata/introspection_normalized.graphql +++ /dev/null @@ -1,242 +0,0 @@ -query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - kind - name - description - fields(includeDeprecated: true){ - name - description - args { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - isDeprecated - deprecationReason - } - inputFields { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - interfaces { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - enumValues(includeDeprecated: true){ - name - description - isDeprecated - deprecationReason - } - possibleTypes { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - } - directives { - name - description - locations - args { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - } - } -} \ No newline at end of file diff --git a/pkg/astparser/testdata/introspectionquery.graphql b/pkg/astparser/testdata/introspectionquery.graphql deleted file mode 100644 index 996742faf..000000000 --- a/pkg/astparser/testdata/introspectionquery.graphql +++ /dev/null @@ -1,99 +0,0 @@ -query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/pkg/astparser/testdata/starwars.schema.graphql b/pkg/astparser/testdata/starwars.schema.graphql deleted file mode 100644 index c6c665e03..000000000 --- a/pkg/astparser/testdata/starwars.schema.graphql +++ /dev/null @@ -1,344 +0,0 @@ -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -"The query type, represents all of the entry points into our object graph" -type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human - starship(id: ID!): Starship -} - -"The mutation type, represents all updates we can make to our data" -type Mutation { - createReview(episode: Episode, review: ReviewInput!): Review -} - -"The subscription type, represents all subscriptions we can make to our data" -type Subscription { - reviewAdded(episode: Episode): Review -} - -"The episodes in the Star Wars trilogy" -enum Episode { - "Star Wars Episode IV: A New Hope, released in 1977." - NEWHOPE - "Star Wars Episode V: The Empire Strikes Back, released in 1980." - EMPIRE - "Star Wars Episode VI: Return of the Jedi, released in 1983." - JEDI -} - -"A character from the Star Wars universe" -interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -"Units of height" -enum LengthUnit { - "The standard unit around the world" - METER - "Primarily used in the United States" - FOOT -} - -"A humanoid creature from the Star Wars universe" -type Human implements Character { - "The ID of the human" - id: ID! - "What this human calls themselves" - name: String! - "The home planet of the human, or null if unknown" - homePlanet: String - "Height in the preferred unit, default is meters" - height(unit: LengthUnit = METER): Float - "Mass in kilograms, or null if unknown" - mass: Float - "This human's friends, or an empty list if they have none" - friends: [Character] - "The friends of the human exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this human appears in" - appearsIn: [Episode]! - "A list of starships this person has piloted, or an empty list if none" - starships: [Starship] -} - -"An autonomous mechanical character in the Star Wars universe" - type Droid implements Character { - "The ID of the droid" - id: ID! - "What others call this droid" - name: String! - "This droid's friends, or an empty list if they have none" - friends: [Character] - "The friends of the droid exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this droid appears in" - appearsIn: [Episode]! - "This droid's primary function" - primaryFunction: String -} - -"A connection object for a character's friends" - type FriendsConnection { - "The total number of friends" - totalCount: Int - "The edges for each of the character's friends." - edges: [FriendsEdge] - "A list of the friends, as a convenience when edges are not needed." - friends: [Character] - "Information for paginating this connection" - pageInfo: PageInfo! -} - -"An edge object for a character's friends" - type FriendsEdge { - "A cursor used for pagination" - cursor: ID! - "The character represented by this friendship edge" - node: Character -} - -"Information for paginating this connection" - type PageInfo { - startCursor: ID - endCursor: ID - hasNextPage: Boolean! -} - -"Represents a review for a movie" - type Review { - "The movie" - episode: Episode - "The number of stars this review gave, 1-5" - stars: Int! - "Comment about the movie" - commentary: String -} - -"The input object sent when someone is creating a new review" - input ReviewInput { - "0-5 stars" - stars: Int! - "Comment about the movie, optional" - commentary: String - "Favorite color, optional" - favorite_color: ColorInput -} - -"The input object sent when passing in a color" - input ColorInput { - red: Int! - green: Int! - blue: Int! -} - -type Starship { - "The ID of the starship" - id: ID! - "The name of the starship" - name: String! - "Length of the starship, along the longest axis" - length(unit: LengthUnit = METER): Float -} - -union SearchResult = Human | Droid | Starship - -"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The `Boolean` scalar type represents `true` or `false` ." -scalar Boolean -"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `4`) or integer (such as 4) input value will be accepted as an ID." -scalar ID -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the `__TypeKind` enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given `__Type` is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. `fields` and `interfaces` are valid fields." - OBJECT - "Indicates this type is an interface. `fields` ` and ` `possibleTypes` are valid fields." - INTERFACE - "Indicates this type is a union. `possibleTypes` is a valid field." - UNION - "Indicates this type is an enum. `enumValues` is a valid field." - ENUM - "Indicates this type is an input object. `inputFields` is a valid field." - INPUT_OBJECT - "Indicates this type is a list. `ofType` is a valid field." - LIST - "Indicates this type is a non-null. `ofType` is a valid field." - NON_NULL -} diff --git a/pkg/astparser/testdata/todo.graphql b/pkg/astparser/testdata/todo.graphql deleted file mode 100644 index 5174a32e8..000000000 --- a/pkg/astparser/testdata/todo.graphql +++ /dev/null @@ -1,228 +0,0 @@ -directive @hasRole(role: Role!) on FIELD_DEFINITION | OBJECT - -enum Role { - ADMIN - USER -} - -type Todo { - id: ID! - text: String! - done: Boolean! - user: User! -} - -type User { - id: ID! - name: String! -} - -schema { - query: Query - mutation: Mutation -} - -type Query { - __schema: __Schema! - __type(name: String!): __Type - todos: [Todo!]! - todo(id: ID!): Todo -} - -input NewTodo { - text: String! - userName: String! -} - -input UpdateTodo { - done: Boolean - text: String -} - -type Mutation { - createTodo(input: NewTodo!): Todo! @hasRole(role: ADMIN) - updateTodo(id: ID!,input: UpdateTodo): Todo! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} \ No newline at end of file diff --git a/pkg/astparser/tokenizer.go b/pkg/astparser/tokenizer.go deleted file mode 100644 index 8b8a103a9..000000000 --- a/pkg/astparser/tokenizer.go +++ /dev/null @@ -1,97 +0,0 @@ -package astparser - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/token" -) - -// Tokenizer takes a raw input and turns it into set of tokens -type Tokenizer struct { - lexer *lexer.Lexer - tokens []token.Token - maxTokens int - currentToken int - skipComments bool -} - -// NewTokenizer returns a new tokenizer -func NewTokenizer() *Tokenizer { - return &Tokenizer{ - tokens: make([]token.Token, 256), - lexer: &lexer.Lexer{}, - skipComments: true, - } -} - -func (t *Tokenizer) Tokenize(input *ast.Input) { - t.lexer.SetInput(input) - t.tokens = t.tokens[:0] - - for { - next := t.lexer.Read() - if next.Keyword == keyword.EOF { - t.maxTokens = len(t.tokens) - t.currentToken = -1 - return - } - t.tokens = append(t.tokens, next) - } -} - -// hasNextToken - checks that we haven't reached eof -func (t *Tokenizer) hasNextToken(skip int) bool { - return t.currentToken+1+skip < t.maxTokens -} - -// next - increments current token index if hasNextToken -// otherwise returns current token -func (t *Tokenizer) next() int { - if t.hasNextToken(0) { - t.currentToken++ - } - return t.currentToken -} - -// Read - increments currentToken index and return token if hasNextToken -// otherwise returns keyword.EOF -func (t *Tokenizer) Read() token.Token { - tok := t.read() - if t.skipComments && tok.Keyword == keyword.COMMENT { - tok = t.read() - } - - return tok -} - -func (t *Tokenizer) read() token.Token { - if t.hasNextToken(0) { - return t.tokens[t.next()] - } - - return token.Token{ - Keyword: keyword.EOF, - } -} - -// Peek - returns token next to currentToken if hasNextToken -// otherwise returns keyword.EOF -func (t *Tokenizer) Peek() token.Token { - tok := t.peek(0) - if t.skipComments && tok.Keyword == keyword.COMMENT { - tok = t.peek(1) - } - - return tok -} - -func (t *Tokenizer) peek(skip int) token.Token { - if t.hasNextToken(skip) { - nextIndex := t.currentToken + 1 + skip - return t.tokens[nextIndex] - } - return token.Token{ - Keyword: keyword.EOF, - } -} diff --git a/pkg/astprinter/astprinter.go b/pkg/astprinter/astprinter.go deleted file mode 100644 index d1e7fe76c..000000000 --- a/pkg/astprinter/astprinter.go +++ /dev/null @@ -1,1046 +0,0 @@ -// Package astprinter takes a GraphQL document and prints it as a String with optional indentation. -package astprinter - -import ( - "bytes" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -// Print takes a document as well as a definition (optional) and prints it to the io.Writer. -// The definition is only necessary in case a GraphQL Operation should be printed. -func Print(document, definition *ast.Document, out io.Writer) error { - printer := Printer{} - return printer.Print(document, definition, out) -} - -// PrintIndent is the same as Print but accepts an additional indent parameter to set indentation. -// Indent is written once for every depth level. -func PrintIndent(document, definition *ast.Document, indent []byte, out io.Writer) error { - printer := Printer{ - indent: indent, - } - return printer.Print(document, definition, out) -} - -// PrintString is the same as Print but returns a string instead of writing to an io.Writer -func PrintString(document, definition *ast.Document) (string, error) { - buff := &bytes.Buffer{} - err := Print(document, definition, buff) - out := buff.String() - return out, err -} - -// PrintStringIndent is the same as PrintIndent but returns a string instead of writing to an io.Writer -func PrintStringIndent(document, definition *ast.Document, indent string) (string, error) { - buff := &bytes.Buffer{} - err := PrintIndent(document, definition, []byte(indent), buff) - out := buff.String() - return out, err -} - -// Printer walks a GraphQL document and prints it as a string -type Printer struct { - indent []byte - visitor printVisitor - walker astvisitor.SimpleWalker - registered bool -} - -// Print starts the actual AST printing -// Keep a printer and re-use it in case you'd like to print ASTs in the hot path. -func (p *Printer) Print(document, definition *ast.Document, out io.Writer) error { - p.visitor.indent = p.indent - p.visitor.err = nil - p.visitor.document = document - p.visitor.out = out - p.visitor.SimpleWalker = &p.walker - if !p.registered { - p.walker.SetVisitor(&p.visitor) - } - return p.walker.Walk(p.visitor.document, definition) -} - -type printVisitor struct { - *astvisitor.SimpleWalker - document *ast.Document - out io.Writer - err error - - indent []byte - inputValueDefinitionOpener []byte - inputValueDefinitionCloser []byte - isFirstDirectiveLocation bool - isDirectiveRepeatable bool -} - -func (p *printVisitor) write(data []byte) { - if p.err != nil { - return - } - _, p.err = p.out.Write(data) -} - -func (p *printVisitor) indentationDepth() (depth int) { - - if len(p.Ancestors) == 0 { - return 0 - } - - switch p.Ancestors[0].Kind { - case ast.NodeKindOperationDefinition, - ast.NodeKindFragmentDefinition: - default: - return 1 - } - - for i := range p.Ancestors { - if p.Ancestors[i].Kind == ast.NodeKindSelectionSet { - depth += 1 - } - } - - return depth -} - -func (p *printVisitor) writeIndented(data []byte) { - if p.err != nil { - return - } - depth := p.indentationDepth() - for i := 0; i < depth; i++ { - _, p.err = p.out.Write(p.indent) - } - _, p.err = p.out.Write(data) -} - -func (p *printVisitor) must(err error) { - if p.err != nil { - return - } - p.err = err -} - -func (p *printVisitor) EnterDirective(ref int) { - if p.document.DirectiveIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) { - switch p.Ancestors[len(p.Ancestors)-1].Kind { - case ast.NodeKindFieldDefinition: - p.writeFieldType(p.Ancestors[len(p.Ancestors)-1].Ref) - p.write(literal.SPACE) - case ast.NodeKindEnumValueDefinition, - ast.NodeKindInputValueDefinition: - p.write(literal.SPACE) - } - } - - p.write(literal.AT) - p.write(p.document.DirectiveNameBytes(ref)) -} - -func (p *printVisitor) LeaveDirective(ref int) { - if !p.document.DirectiveIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(literal.SPACE) - return - } - - ancestor := p.Ancestors[len(p.Ancestors)-1] - switch ancestor.Kind { - case ast.NodeKindField: - if p.document.FieldHasSelections(ancestor.Ref) { - p.write(literal.SPACE) - } else if len(p.SelectionsAfter) > 0 { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } - case ast.NodeKindVariableDefinition: - if !p.document.VariableDefinitionsAfter(ancestor.Ref) { - p.write(literal.SPACE) - } - case ast.NodeKindInlineFragment: - if len(p.SelectionsAfter) > 0 { - p.write(literal.SPACE) - } - case ast.NodeKindScalarTypeDefinition, - ast.NodeKindScalarTypeExtension, - ast.NodeKindUnionTypeDefinition, - ast.NodeKindUnionTypeExtension, - ast.NodeKindEnumTypeDefinition, - ast.NodeKindEnumTypeExtension, - ast.NodeKindEnumValueDefinition, - ast.NodeKindFieldDefinition, - ast.NodeKindInputValueDefinition: - return - default: - p.write(literal.SPACE) - } -} - -func (p *printVisitor) EnterVariableDefinition(ref int) { - if !p.document.VariableDefinitionsBefore(ref) { - p.write(literal.LPAREN) - } - - p.must(p.document.PrintValue(p.document.VariableDefinitions[ref].VariableValue, p.out)) - p.write(literal.COLON) - p.write(literal.SPACE) - - p.must(p.document.PrintType(p.document.VariableDefinitions[ref].Type, p.out)) - - if p.document.VariableDefinitions[ref].DefaultValue.IsDefined { - p.write(literal.SPACE) - p.write(literal.EQUALS) - p.write(literal.SPACE) - p.must(p.document.PrintValue(p.document.VariableDefinitions[ref].DefaultValue.Value, p.out)) - } - - if p.document.VariableDefinitions[ref].HasDirectives { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveVariableDefinition(ref int) { - if !p.document.VariableDefinitionsAfter(ref) { - p.write(literal.RPAREN) - } else { - p.write(literal.COMMA) - p.write(literal.SPACE) - } -} - -func (p *printVisitor) EnterArgument(ref int) { - if len(p.document.ArgumentsBefore(p.Ancestors[len(p.Ancestors)-1], ref)) == 0 { - p.write(literal.LPAREN) - } else { - p.write(literal.COMMA) - p.write(literal.SPACE) - } - p.must(p.document.PrintArgument(ref, p.out)) -} - -func (p *printVisitor) LeaveArgument(ref int) { - if len(p.document.ArgumentsAfter(p.Ancestors[len(p.Ancestors)-1], ref)) == 0 { - p.write(literal.RPAREN) - } -} - -func (p *printVisitor) EnterOperationDefinition(ref int) { - - hasName := p.document.OperationDefinitions[ref].Name.Length() > 0 - hasVariables := p.document.OperationDefinitions[ref].HasVariableDefinitions - - switch p.document.OperationDefinitions[ref].OperationType { - case ast.OperationTypeQuery: - if hasName || hasVariables { - p.write(literal.QUERY) - } - case ast.OperationTypeMutation: - p.write(literal.MUTATION) - case ast.OperationTypeSubscription: - p.write(literal.SUBSCRIPTION) - } - - if hasName { - p.write(literal.SPACE) - } - - if hasName { - p.write(p.document.Input.ByteSlice(p.document.OperationDefinitions[ref].Name)) - if !p.document.OperationDefinitions[ref].HasVariableDefinitions { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) LeaveOperationDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindOperationDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterSelectionSet(ref int) { - p.write(literal.LBRACE) - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } -} - -func (p *printVisitor) LeaveSelectionSet(ref int) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - p.writeIndented(literal.RBRACE) -} - -func (p *printVisitor) EnterField(ref int) { - if p.document.Fields[ref].Alias.IsDefined { - p.writeIndented(p.document.Input.ByteSlice(p.document.Fields[ref].Alias.Name)) - p.write(literal.COLON) - p.write(literal.SPACE) - p.write(p.document.Input.ByteSlice(p.document.Fields[ref].Name)) - } else { - p.writeIndented(p.document.Input.ByteSlice(p.document.Fields[ref].Name)) - } - if !p.document.FieldHasArguments(ref) && (p.document.FieldHasSelections(ref) || p.document.FieldHasDirectives(ref)) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveField(ref int) { - if !p.document.FieldHasDirectives(ref) && len(p.SelectionsAfter) != 0 { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterFragmentSpread(ref int) { - p.writeIndented(literal.SPREAD) - p.write(p.document.Input.ByteSlice(p.document.FragmentSpreads[ref].FragmentName)) -} - -func (p *printVisitor) LeaveFragmentSpread(ref int) { - ancestor := p.Ancestors[len(p.Ancestors)-1] - if p.document.SelectionsAfterFragmentSpread(ref, ancestor) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterInlineFragment(ref int) { - p.writeIndented(literal.SPREAD) - if p.document.InlineFragments[ref].TypeCondition.Type != -1 { - p.write(literal.SPACE) - p.write(literal.ON) - p.write(literal.SPACE) - p.write(p.document.Input.ByteSlice(p.document.Types[p.document.InlineFragments[ref].TypeCondition.Type].Name)) - p.write(literal.SPACE) - } else if p.document.InlineFragments[ref].HasDirectives { - p.write(literal.SPACE) - } - -} - -func (p *printVisitor) LeaveInlineFragment(ref int) { - ancestor := p.Ancestors[len(p.Ancestors)-1] - if p.document.SelectionsAfterInlineFragment(ref, ancestor) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterFragmentDefinition(ref int) { - p.write(literal.FRAGMENT) - p.write(literal.SPACE) - p.write(p.document.Input.ByteSlice(p.document.FragmentDefinitions[ref].Name)) - p.write(literal.SPACE) - p.write(literal.ON) - p.write(literal.SPACE) - p.write(p.document.Input.ByteSlice(p.document.Types[p.document.FragmentDefinitions[ref].TypeCondition.Type].Name)) - p.write(literal.SPACE) - -} - -func (p *printVisitor) LeaveFragmentDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindFragmentDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterObjectTypeDefinition(ref int) { - - if p.document.ObjectTypeDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.ObjectTypeDefinitions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.TYPE) - p.write(literal.SPACE) - p.write(p.document.ObjectTypeDefinitionNameBytes(ref)) - p.write(literal.SPACE) - - if len(p.document.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs) != 0 { - p.write(literal.IMPLEMENTS) - p.write(literal.SPACE) - for i, j := range p.document.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs { - if i != 0 { - p.write(literal.SPACE) - p.write(literal.AND) - p.write(literal.SPACE) - } - p.must(p.document.PrintType(j, p.out)) - } - p.write(literal.SPACE) - } - - p.inputValueDefinitionOpener = literal.LPAREN - p.inputValueDefinitionCloser = literal.RPAREN -} - -func (p *printVisitor) LeaveObjectTypeDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindObjectTypeDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterObjectTypeExtension(ref int) { - - if p.document.ObjectTypeExtensions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.ObjectTypeExtensions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.TYPE) - p.write(literal.SPACE) - p.write(p.document.ObjectTypeExtensionNameBytes(ref)) - p.write(literal.SPACE) - - p.inputValueDefinitionOpener = literal.LPAREN - p.inputValueDefinitionCloser = literal.RPAREN -} - -func (p *printVisitor) LeaveObjectTypeExtension(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindObjectTypeExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterFieldDefinition(ref int) { - if p.document.FieldDefinitionIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(literal.LBRACE) - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - } - if p.document.FieldDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.FieldDefinitions[ref].Description, p.indent, p.indentationDepth(), p.out)) - p.write(literal.LINETERMINATOR) - } - p.writeIndented(p.document.FieldDefinitionNameBytes(ref)) -} - -func (p *printVisitor) LeaveFieldDefinition(ref int) { - if !p.document.FieldDefinitionHasDirectives(ref) { - p.writeFieldType(ref) - } - - if p.document.FieldDefinitionIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - p.write(literal.RBRACE) - } else { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterInputValueDefinition(ref int) { - if p.document.InputValueDefinitionIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(p.inputValueDefinitionOpener) - } - if p.indent != nil { - switch p.Ancestors[len(p.Ancestors)-1].Kind { - case ast.NodeKindDirectiveDefinition, ast.NodeKindInputObjectTypeDefinition, ast.NodeKindInputObjectTypeExtension: - p.write(literal.LINETERMINATOR) - } - } - if p.document.InputValueDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.InputValueDefinitions[ref].Description, p.indent, p.indentationDepth(), p.out)) - p.write(literal.LINETERMINATOR) - } - switch p.Ancestors[len(p.Ancestors)-1].Kind { - case ast.NodeKindDirectiveDefinition, ast.NodeKindInputObjectTypeDefinition, ast.NodeKindInputObjectTypeExtension: - p.writeIndented(p.document.InputValueDefinitionNameBytes(ref)) - default: - p.write(p.document.InputValueDefinitionNameBytes(ref)) - } - p.write(literal.COLON) - p.write(literal.SPACE) - p.must(p.document.PrintType(p.document.InputValueDefinitionType(ref), p.out)) - if p.document.InputValueDefinitionHasDefaultValue(ref) { - p.write(literal.SPACE) - p.write(literal.EQUALS) - p.write(literal.SPACE) - p.must(p.document.PrintValue(p.document.InputValueDefinitionDefaultValue(ref), p.out)) - } -} - -func (p *printVisitor) LeaveInputValueDefinition(ref int) { - if p.document.InputValueDefinitionIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) { - if p.indent != nil { - switch p.Ancestors[len(p.Ancestors)-1].Kind { - case ast.NodeKindDirectiveDefinition, ast.NodeKindInputObjectTypeDefinition, ast.NodeKindInputObjectTypeExtension: - p.write(literal.LINETERMINATOR) - } - } - p.write(p.inputValueDefinitionCloser) - } else { - if len(p.Ancestors) > 0 { - // check enclosing type kind - if p.Ancestors[len(p.Ancestors)-1].Kind == ast.NodeKindFieldDefinition { - p.write(literal.COMMA) - p.write(literal.SPACE) - } else if len(p.indent) == 0 { - // add space between arguments when printing without indents - p.write(literal.SPACE) - } - } - } -} - -func (p *printVisitor) EnterInterfaceTypeDefinition(ref int) { - - if p.document.InterfaceTypeDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.InterfaceTypeDefinitions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.INTERFACE) - p.write(literal.SPACE) - p.write(p.document.InterfaceTypeDefinitionNameBytes(ref)) - p.write(literal.SPACE) - - if len(p.document.InterfaceTypeDefinitions[ref].ImplementsInterfaces.Refs) != 0 { - p.write(literal.IMPLEMENTS) - p.write(literal.SPACE) - for i, j := range p.document.InterfaceTypeDefinitions[ref].ImplementsInterfaces.Refs { - if i != 0 { - p.write(literal.SPACE) - p.write(literal.AND) - p.write(literal.SPACE) - } - p.must(p.document.PrintType(j, p.out)) - } - p.write(literal.SPACE) - } - - p.inputValueDefinitionOpener = literal.LPAREN - p.inputValueDefinitionCloser = literal.RPAREN -} - -func (p *printVisitor) LeaveInterfaceTypeDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInterfaceTypeDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterInterfaceTypeExtension(ref int) { - - if p.document.InterfaceTypeExtensions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.InterfaceTypeExtensions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.INTERFACE) - p.write(literal.SPACE) - p.write(p.document.InterfaceTypeExtensionNameBytes(ref)) - p.write(literal.SPACE) - - p.inputValueDefinitionOpener = literal.LPAREN - p.inputValueDefinitionCloser = literal.RPAREN -} - -func (p *printVisitor) LeaveInterfaceTypeExtension(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInterfaceTypeExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterScalarTypeDefinition(ref int) { - - if p.document.ScalarTypeDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.ScalarTypeDefinitions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.SCALAR) - p.write(literal.SPACE) - p.write(p.document.ScalarTypeDefinitionNameBytes(ref)) - if p.document.ScalarTypeDefinitionHasDirectives(ref) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveScalarTypeDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindScalarTypeDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterScalarTypeExtension(ref int) { - - if p.document.ScalarTypeExtensions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.ScalarTypeExtensions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.SCALAR) - p.write(literal.SPACE) - p.write(p.document.ScalarTypeExtensionNameBytes(ref)) - if p.document.ScalarTypeExtensionHasDirectives(ref) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveScalarTypeExtension(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindScalarTypeExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterUnionTypeDefinition(ref int) { - - if p.document.UnionTypeDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.UnionTypeDefinitions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.UNION) - p.write(literal.SPACE) - p.write(p.document.UnionTypeDefinitionNameBytes(ref)) - if p.document.UnionTypeDefinitionHasDirectives(ref) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveUnionTypeDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindUnionTypeDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterUnionTypeExtension(ref int) { - - if p.document.UnionTypeExtensions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.UnionTypeExtensions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.UNION) - p.write(literal.SPACE) - p.write(p.document.UnionTypeExtensionNameBytes(ref)) - if p.document.UnionTypeExtensionHasDirectives(ref) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveUnionTypeExtension(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindUnionTypeExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterUnionMemberType(ref int) { - if p.document.UnionMemberTypeIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(literal.SPACE) - p.write(literal.EQUALS) - p.write(literal.SPACE) - } - p.write(p.document.TypeNameBytes(ref)) - if !p.document.UnionMemberTypeIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(literal.SPACE) - p.write(literal.PIPE) - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveUnionMemberType(ref int) { - -} - -func (p *printVisitor) EnterEnumTypeDefinition(ref int) { - - if p.document.EnumTypeDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.EnumTypeDefinitions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.ENUM) - p.write(literal.SPACE) - p.write(p.document.EnumTypeDefinitionNameBytes(ref)) - if p.document.EnumTypeDefinitionHasDirectives(ref) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveEnumTypeDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindEnumTypeDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterEnumTypeExtension(ref int) { - - if p.document.EnumTypeExtensions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.EnumTypeExtensions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.ENUM) - p.write(literal.SPACE) - p.write(p.document.EnumTypeExtensionNameBytes(ref)) - if p.document.EnumTypeExtensionHasDirectives(ref) { - p.write(literal.SPACE) - } -} - -func (p *printVisitor) LeaveEnumTypeExtension(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindEnumTypeExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterEnumValueDefinition(ref int) { - if p.document.EnumValueDefinitionIsFirst(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(literal.SPACE) - p.write(literal.LBRACE) - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - } - if p.document.EnumValueDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.EnumValueDefinitions[ref].Description, p.indent, p.indentationDepth(), p.out)) - p.write(literal.LINETERMINATOR) - } - p.writeIndented(p.document.EnumValueDefinitionNameBytes(ref)) -} - -func (p *printVisitor) LeaveEnumValueDefinition(ref int) { - if p.document.EnumValueDefinitionIsLast(ref, p.Ancestors[len(p.Ancestors)-1]) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - p.write(literal.RBRACE) - } else { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterInputObjectTypeDefinition(ref int) { - - if p.document.InputObjectTypeDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.InputObjectTypeDefinitions[ref].Description, nil, 0, p.out)) - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - } - - p.write(literal.INPUT) - p.write(literal.SPACE) - p.write(p.document.InputObjectTypeDefinitionNameBytes(ref)) - p.write(literal.SPACE) - - p.inputValueDefinitionOpener = literal.LBRACE - p.inputValueDefinitionCloser = literal.RBRACE -} - -func (p *printVisitor) LeaveInputObjectTypeDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInputObjectTypeDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterInputObjectTypeExtension(ref int) { - - if p.document.InputObjectTypeExtensions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.InputObjectTypeExtensions[ref].Description, nil, 0, p.out)) - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - } - - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.INPUT) - p.write(literal.SPACE) - p.write(p.document.InputObjectTypeExtensionNameBytes(ref)) - p.write(literal.SPACE) - - p.inputValueDefinitionOpener = literal.LBRACE - p.inputValueDefinitionCloser = literal.RBRACE -} - -func (p *printVisitor) LeaveInputObjectTypeExtension(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindInputObjectTypeExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterDirectiveDefinition(ref int) { - if p.document.DirectiveDefinitions[ref].Description.IsDefined { - p.must(p.document.PrintDescription(p.document.DirectiveDefinitions[ref].Description, nil, 0, p.out)) - p.write(literal.LINETERMINATOR) - } - - p.write(literal.DIRECTIVE) - p.write(literal.SPACE) - p.write(literal.AT) - p.write(p.document.DirectiveDefinitionNameBytes(ref)) - p.isFirstDirectiveLocation = true - p.isDirectiveRepeatable = p.document.DirectiveDefinitionIsRepeatable(ref) - - p.inputValueDefinitionOpener = literal.LPAREN - p.inputValueDefinitionCloser = literal.RPAREN -} - -func (p *printVisitor) LeaveDirectiveDefinition(ref int) { - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindDirectiveDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) { - - if p.isFirstDirectiveLocation { - if p.isDirectiveRepeatable { - p.write(literal.SPACE) - p.write(literal.REPEATABLE) - } - - p.isFirstDirectiveLocation = false - p.write(literal.SPACE) - p.write(literal.ON) - p.write(literal.SPACE) - } else { - p.write(literal.SPACE) - p.write(literal.PIPE) - p.write(literal.SPACE) - } - - switch location { - case ast.ExecutableDirectiveLocationQuery: - p.write(literal.LocationQuery) - case ast.ExecutableDirectiveLocationMutation: - p.write(literal.LocationMutation) - case ast.ExecutableDirectiveLocationSubscription: - p.write(literal.LocationSubscription) - case ast.ExecutableDirectiveLocationField: - p.write(literal.LocationField) - case ast.ExecutableDirectiveLocationFragmentDefinition: - p.write(literal.LocationFragmentDefinition) - case ast.ExecutableDirectiveLocationFragmentSpread: - p.write(literal.LocationFragmentSpread) - case ast.ExecutableDirectiveLocationInlineFragment: - p.write(literal.LocationInlineFragment) - case ast.ExecutableDirectiveLocationVariableDefinition: - p.write(literal.LocationVariableDefinition) - case ast.TypeSystemDirectiveLocationSchema: - p.write(literal.LocationSchema) - case ast.TypeSystemDirectiveLocationScalar: - p.write(literal.LocationScalar) - case ast.TypeSystemDirectiveLocationObject: - p.write(literal.LocationObject) - case ast.TypeSystemDirectiveLocationFieldDefinition: - p.write(literal.LocationFieldDefinition) - case ast.TypeSystemDirectiveLocationArgumentDefinition: - p.write(literal.LocationArgumentDefinition) - case ast.TypeSystemDirectiveLocationInterface: - p.write(literal.LocationInterface) - case ast.TypeSystemDirectiveLocationUnion: - p.write(literal.LocationUnion) - case ast.TypeSystemDirectiveLocationEnum: - p.write(literal.LocationEnum) - case ast.TypeSystemDirectiveLocationEnumValue: - p.write(literal.LocationEnumValue) - case ast.TypeSystemDirectiveLocationInputObject: - p.write(literal.LocationInputObject) - case ast.TypeSystemDirectiveLocationInputFieldDefinition: - p.write(literal.LocationInputFieldDefinition) - } -} - -func (p *printVisitor) LeaveDirectiveLocation(location ast.DirectiveLocation) { - -} - -func (p *printVisitor) EnterSchemaDefinition(ref int) { - p.write(literal.SCHEMA) - p.write(literal.SPACE) -} - -func (p *printVisitor) LeaveSchemaDefinition(ref int) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - p.write(literal.RBRACE) - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindSchemaDefinition, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterSchemaExtension(ref int) { - p.write(literal.EXTEND) - p.write(literal.SPACE) - p.write(literal.SCHEMA) - p.write(literal.SPACE) -} - -func (p *printVisitor) LeaveSchemaExtension(ref int) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - p.write(literal.RBRACE) - if !p.document.NodeIsLastRootNode(ast.Node{Kind: ast.NodeKindSchemaExtension, Ref: ref}) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterRootOperationTypeDefinition(ref int) { - if p.document.RootOperationTypeDefinitionIsFirstInSchemaDefinition(ref, p.Ancestors[len(p.Ancestors)-1]) { - p.write(literal.LBRACE) - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } - } - switch p.document.RootOperationTypeDefinitions[ref].OperationType { - case ast.OperationTypeQuery: - p.writeIndented(literal.QUERY) - case ast.OperationTypeMutation: - p.writeIndented(literal.MUTATION) - case ast.OperationTypeSubscription: - p.writeIndented(literal.SUBSCRIPTION) - } - p.write(literal.COLON) - p.write(literal.SPACE) - p.write(p.document.Input.ByteSlice(p.document.RootOperationTypeDefinitions[ref].NamedType.Name)) -} - -func (p *printVisitor) LeaveRootOperationTypeDefinition(ref int) { - if !p.document.RootOperationTypeDefinitionIsLastInSchemaDefinition(ref, p.Ancestors[len(p.Ancestors)-1]) { - if p.indent != nil { - p.write(literal.LINETERMINATOR) - } else { - p.write(literal.SPACE) - } - } -} - -func (p *printVisitor) EnterDocument(operation, definition *ast.Document) { - -} - -func (p *printVisitor) LeaveDocument(operation, definition *ast.Document) { - -} - -func (p *printVisitor) writeFieldType(ref int) { - p.write(literal.COLON) - p.write(literal.SPACE) - p.must(p.document.PrintType(p.document.FieldDefinitionType(ref), p.out)) -} diff --git a/pkg/astprinter/astprinter_test.go b/pkg/astprinter/astprinter_test.go deleted file mode 100644 index e545d1277..000000000 --- a/pkg/astprinter/astprinter_test.go +++ /dev/null @@ -1,939 +0,0 @@ -package astprinter - -import ( - "bytes" - "os" - "testing" - - "github.com/jensneuse/diffview" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestPrint(t *testing.T) { - - must := func(t *testing.T, err error) { - t.Helper() - if report, ok := err.(operationreport.Report); ok { - if report.HasErrors() { - t.Fatalf("report has errors %s", report.Error()) - } - } - require.NoError(t, err) - } - - run := func(t *testing.T, raw string, expected string) { - t.Helper() - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - doc := unsafeparser.ParseGraphqlDocumentString(raw) - - buff := &bytes.Buffer{} - // printer := Printer{indent: []byte(" ")} - printer := Printer{} - - must(t, printer.Print(&doc, &definition, buff)) - - actual := buff.String() - assert.Equal(t, expected, actual) - } - - t.Run("simple", func(t *testing.T) { - run(t, "query o($id: String!){user(id: $id){id name birthday}}", - "query o($id: String!){user(id: $id){id name birthday}}") - }) - t.Run("complex", func(t *testing.T) { - run(t, ` - subscription sub { - ...multipleSubscriptions - } - fragment multipleSubscriptions on Subscription { - ... { - newMessage { - body - } - } - ... on Subscription { - typedInlineFragment - } - newMessage { - body - sender - } - disallowedSecondRootField - }`, - "subscription sub {...multipleSubscriptions} fragment multipleSubscriptions on Subscription {...{newMessage {body}} ... on Subscription {typedInlineFragment} newMessage {body sender} disallowedSecondRootField}") - }) - t.Run("multiline comments indentation", func(t *testing.T) { - run(t, `""" -the following lines test indentation - one tab - two spaces - two tabs -no indentation -example from issue: -{ - user(id: 1) { - userID - friends - } -} -""" -type Query`, - `""" -the following lines test indentation - one tab - two spaces - two tabs -no indentation -example from issue: -{ - user(id: 1) { - userID - friends - } -} -""" -type Query `) - }) - t.Run("directive definition", func(t *testing.T) { - run(t, ` -""" -directive @cache -""" -directive @cache( - "maxAge defines the maximum time in seconds a response will be understood 'fresh', defaults to 300 (5 minutes)" - maxAge: Int! = 300 - """ - vary defines the headers to append to the cache key - In addition to all possible headers you can also select a custom claim for authenticated requests - Examples: 'jwt.sub', 'jwt.team' to vary the cache key based on 'sub' or 'team' fields on the jwt. - """ - vary: [String]! = [] -) on QUERY directive @include(if: Boolean!) repeatable on FIELD -`, - `""" -directive @cache -""" -directive @cache("maxAge defines the maximum time in seconds a response will be understood 'fresh', defaults to 300 (5 minutes)" -maxAge: Int! = 300 """ -vary defines the headers to append to the cache key -In addition to all possible headers you can also select a custom claim for authenticated requests -Examples: 'jwt.sub', 'jwt.team' to vary the cache key based on 'sub' or 'team' fields on the jwt. -""" -vary: [String]! = []) on QUERY directive @include(if: Boolean!) repeatable on FIELD`) - }) - t.Run("fragment definition with directives", func(t *testing.T) { - run(t, ` - fragment foo on Dog @fragmentDefinition { - name - } - `, `fragment foo on Dog @fragmentDefinition {name}`) - }) - t.Run("anonymous query", func(t *testing.T) { - run(t, ` { - dog { - ...aliasedLyingFieldTargetNotDefined - } - }`, "{dog {...aliasedLyingFieldTargetNotDefined}}") - }) - t.Run("arguments", func(t *testing.T) { - run(t, ` - query argOnRequiredArg($catCommand: CatCommand @include(if: true), $complex: Boolean = true) { - dog { - doesKnowCommand(dogCommand: $catCommand) - } - }`, `query argOnRequiredArg($catCommand: CatCommand @include(if: true), $complex: Boolean = true){dog {doesKnowCommand(dogCommand: $catCommand)}}`) - }) - t.Run("spacing", func(t *testing.T) { - run(t, `query($representations: [_Any!]!){_entities (representations: $representations){... on User {reviews {body product {upc __typename}}}}}`, - `query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}`) - }) - t.Run("directives", func(t *testing.T) { - t.Run("on field", func(t *testing.T) { - run(t, ` - query directivesQuery @foo(bar: BAZ) { - dog @include(if: true, or: false) { - doesKnowCommand(dogCommand: $catCommand) - } - }`, `query directivesQuery @foo(bar: BAZ) {dog @include(if: true, or: false) {doesKnowCommand(dogCommand: $catCommand)}}`) - }) - t.Run("on inline fragment", func(t *testing.T) { - run(t, ` - { - dog { - name: nickname - ... @include(if: true) { - name - } - } - cat { - name @include(if: true) - nickname - } - }`, `{dog {name: nickname ... @include(if: true){name}} cat {name @include(if: true) nickname}}`) - }) - }) - t.Run("complex operation", func(t *testing.T) { - run(t, benchmarkTestOperation, benchmarkTestOperationFlat) - }) - t.Run("schema definition", func(t *testing.T) { - run(t, ` - schema { - query: Query - mutation: Mutation - subscription: Subscription - }`, `schema {query: Query mutation: Mutation subscription: Subscription}`) - }) - t.Run("schema extension", func(t *testing.T) { - run(t, ` - extend schema @foo { - query: Query - mutation: Mutation - subscription: Subscription - }`, `extend schema @foo {query: Query mutation: Mutation subscription: Subscription}`) - }) - t.Run("object type definition", func(t *testing.T) { - run(t, ` - type Foo { - field: String - }`, `type Foo {field: String}`) - }) - t.Run("object type extension", func(t *testing.T) { - run(t, ` - extend type Foo @foo { - field: String - }`, `extend type Foo @foo {field: String}`) - }) - t.Run("input object type definition", func(t *testing.T) { - run(t, ` - input Foo { - field: String - field2: Boolean = true - }`, `input Foo {field: String field2: Boolean = true}`) - }) - t.Run("input object type extension", func(t *testing.T) { - run(t, ` - extend input Foo @foo { - field: String - }`, `extend input Foo @foo {field: String}`) - }) - t.Run("interface type definition", func(t *testing.T) { - run(t, ` - interface Foo { - field: String - field2: Boolean - }`, `interface Foo {field: String field2: Boolean}`) - }) - t.Run("interface type extension", func(t *testing.T) { - run(t, ` - extend interface Foo @foo { - field: String - }`, `extend interface Foo @foo {field: String}`) - }) - t.Run("scalar type definition", func(t *testing.T) { - run(t, `scalar JSON`, `scalar JSON`) - }) - t.Run("scalar type extension", func(t *testing.T) { - run(t, `extend scalar JSON @foo`, `extend scalar JSON @foo`) - }) - t.Run("union type definition", func(t *testing.T) { - run(t, `union Foo = BAR | BAZ`, `union Foo = BAR | BAZ`) - }) - t.Run("union type extension", func(t *testing.T) { - run(t, `extend union Foo @foo = BAR | BAZ`, `extend union Foo @foo = BAR | BAZ`) - }) - t.Run("enum type definition", func(t *testing.T) { - run(t, ` - enum Foo { - BAR - BAZ - }`, `enum Foo {BAR BAZ}`) - }) - t.Run("enum type extension", func(t *testing.T) { - run(t, ` - extend enum Foo @foo { - BAR - BAZ - }`, `extend enum Foo @foo {BAR BAZ}`) - }) - t.Run("multiple operations with variables", func(t *testing.T) { - run(t, ` - mutation AddToWatchlist($a: Int!, $b: String!){ - addToWatchlist(movieID: $a, name: $b){ - id - name - year - } - } - - mutation AddWithInput($a: WatchlistInput!){ - addToWatchlistWithInput(input: $a){ - id - name - year - } - }`, - `mutation AddToWatchlist($a: Int!, $b: String!){addToWatchlist(movieID: $a, name: $b){id name year}} mutation AddWithInput($a: WatchlistInput!){addToWatchlistWithInput(input: $a){id name year}}`) - }) - - t.Run("ignore comments", func(t *testing.T) { - t.Run("operation", func(t *testing.T) { - run(t, ` - query #comment - findUser#comment - (#comment - $userId#comment - :#comment - ID#comment - !#comment - #comment - )#comment - {#comment - user#comment - (#comment - id#comment - :#comment - $userId#comment - #comment - )#comment - #comment - {#comment - ...#comment - UserFields#comment - ... #comment - on #comment - User#comment - {#comment - email#comment - }#comment - }#comment - }#comment - - fragment #comment - UserFields #comment - on #comment - User#comment - {#comment - id#comment - #username#comment - role#comment - }#comment`, - `query findUser($userId: ID!){user(id: $userId){...UserFields ... on User {email}}} fragment UserFields on User {id role}`) - }) - - t.Run("definition", func(t *testing.T) { - run(t, ` - #comment - scalar #comment - Date #comment - - schema #comment - { #comment - query#comment - :#comment - #comment - Query#comment - #comment - }#comment - - #comment - type#comment - Query#comment - {#comment - me#comment - :#comment - User#comment - !#comment - user(#comment - id#comment - :#comment - ID#comment - !#comment - )#comment - :#comment - User#comment - allUsers#comment - :#comment - [#comment - #comment - User#comment - ]#comment - search#comment - (#comment - term#comment - :#comment - String#comment - !#comment - )#comment - :#comment - [#comment - SearchResult#comment - !#comment - ]#comment - !#comment - myChats:#comment - [#comment - Chat#comment - !#comment - ]!#comment - } - - enum#comment - Role#comment - {#comment - #comment - USER#comment - ,#comment - ADMIN#comment - ,#comment - #comment - }#comment - - interface#comment - Node {#comment - id#comment - :#comment - ID#comment - !#comment - }#comment - - union #comment - SearchResult#comment - =#comment - User#comment - |#comment - Chat#comment - |#comment - ChatMessage#comment - - type#comment - User#comment - implements#comment - Node#comment - {#comment - id#comment - :#comment - ID#comment - !#comment - username#comment - :#comment - String#comment - !#comment - email#comment - :#comment - String#comment - !#comment - role#comment - :#comment - Role#comment - !#comment - }#comment - - type#comment - Chat#comment - implements#comment - Node#comment - {#comment - id#comment - :#comment - ID#comment - !#comment - users#comment - :#comment - [#comment - User#comment - !#comment - ]!#comment - messages#comment - :#comment - [#comment - ChatMessage#comment - !#comment - ]#comment - !#comment - #comment - }#comment - - type#comment - ChatMessage#comment - implements#comment - Node#comment - {#comment - id#comment - :#comment - ID#comment - !#comment - content#comment - :#comment - String#comment - !#comment - time#comment - :#comment - Date#comment - !#comment - user#comment - :#comment - User#comment - !#comment - #comment - }#comment`, - `scalar Date schema {query: Query} type Query {me: User! user(id: ID!): User allUsers: [User] search(term: String!): [SearchResult!]! myChats: [Chat!]!} enum Role {USER ADMIN} interface Node {id: ID!} union SearchResult = User | Chat | ChatMessage type User implements Node {id: ID! username: String! email: String! role: Role!} type Chat implements Node {id: ID! users: [User!]! messages: [ChatMessage!]!} type ChatMessage implements Node {id: ID! content: String! time: Date! user: User!}`) - }) - }) - t.Run("transitive interfaces", func(t *testing.T) { - run(t, "interface I1 {id: ID!} interface I2 implements I1 {id: ID!} interface I3 implements I1 & I2 {id: ID!}", - "interface I1 {id: ID!} interface I2 implements I1 {id: ID!} interface I3 implements I1 & I2 {id: ID!}") - }) -} - -func TestPrintArgumentWithBeforeAfterValue(t *testing.T) { - doc := unsafeparser.ParseGraphqlDocumentString(` - mutation ($email: String!) { - pge_queryRaw(query: "SELECT id, name, email from \"User\" where email = $1", parameters: [$email]) -} -`) - - doc.Arguments[1].PrintBeforeValue = []byte("\"") - doc.Arguments[1].PrintAfterValue = []byte("\"") - - buff := bytes.Buffer{} - err := Print(&doc, nil, &buff) - if err != nil { - t.Fatal(err) - } - - out := buff.Bytes() - assert.Equal(t, "mutation($email: String!){pge_queryRaw(query: \"SELECT id, name, email from \\\"User\\\" where email = $1\", parameters: \"[$email]\")}", string(out)) -} - -func TestPrintSchemaDefinition(t *testing.T) { - - doc := unsafeparser.ParseGraphqlDocumentFile("./testdata/starwars.schema.graphql") - - buff := bytes.Buffer{} - err := PrintIndent(&doc, nil, []byte(" "), &buff) - if err != nil { - t.Fatal(err) - } - - out := buff.Bytes() - - goldie.Assert(t, "starwars_schema_definition", out) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/starwars_schema_definition.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("starwars_schema_definition", fixture, out) - } -} - -func TestPrintOperationDefinition(t *testing.T) { - - schema := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentFile("./testdata/introspectionquery.graphql") - - buff := bytes.Buffer{} - err := PrintIndent(&operation, &schema, []byte(" "), &buff) - if err != nil { - t.Fatal(err) - } - - out := buff.Bytes() - - goldie.Assert(t, "introspectionquery", out) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/introspectionquery.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("introspectionquery", fixture, out) - } -} - -func BenchmarkPrint(b *testing.B) { - - must := func(err error) { - if err != nil { - panic(err) - } - } - - def := unsafeparser.ParseGraphqlDocumentString(benchmarkTestDefinition) - doc := unsafeparser.ParseGraphqlDocumentString(benchmarkTestOperation) - - buff := &bytes.Buffer{} - - printer := Printer{} - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - buff.Reset() - must(printer.Print(&doc, &def, buff)) - } -} - -const testDefinition = ` -schema { - query: Query - subscription: Subscription -} - -type Message { - body: String - sender: String -} - -type Subscription { - newMessage: Message - disallowedSecondRootField: Boolean -} - -input ComplexInput { name: String, owner: String } -input ComplexNonOptionalInput { name: String! } - -type Query { - human: Human - pet: Pet - dog: Dog - cat: Cat - catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien - arguments: ValidArguments - findDog(complex: ComplexInput): Dog - findDogNonOptional(complex: ComplexNonOptionalInput): Dog - booleanList(booleanListArg: [Boolean!]): Boolean - extra: Extra -} - -type ValidArguments { - multipleReqs(x: Int!, y: Int!): Int! - booleanArgField(booleanArg: Boolean): Boolean - floatArgField(floatArg: Float): Float - intArgField(intArg: Int): Int - nonNullBooleanArgField(nonNullBooleanArg: Boolean!): Boolean! - booleanListArgField(booleanListArg: [Boolean]!): [Boolean] - optionalNonNullBooleanArgField(optionalBooleanArg: Boolean! = false): Boolean! -} - -enum DogCommand { SIT, DOWN, HEEL } - -type Dog implements Pet { - name: String! - nickname: String - barkVolume: Int - doesKnowCommand(dogCommand: DogCommand!): Boolean! - isHousetrained(atOtherHomes: Boolean): Boolean! - owner: Human - extra: DogExtra - extras: [DogExtra] - mustExtra: DogExtra! - mustExtras: [DogExtra]! - mustMustExtras: [DogExtra!]! -} - -type DogExtra { - string: String - strings: [String] - mustStrings: [String]! - bool: Int -} - -interface Sentient { - name: String! -} - -interface Pet { - name: String! -} - -type Alien implements Sentient { - name: String! - homePlanet: String -} - -type Human implements Sentient { - name: String! -} - -enum CatCommand { JUMP } - -type Cat implements Pet { - name: String! - nickname: String - doesKnowCommand(catCommand: CatCommand!): Boolean! - meowVolume: Int - extra: CatExtra -} - -type CatExtra { - string: String - string2: String - strings: [String] - mustStrings: [String]! - bool: Boolean -} - -union CatOrDog = Cat | Dog -union DogOrHuman = Dog | Human -union HumanOrAlien = Human | Alien -union Extra = CatExtra | DogExtra - -directive @inline on INLINE_FRAGMENT -directive @spread on FRAGMENT_SPREAD -directive @fragmentDefinition on FRAGMENT_DEFINITION -directive @onQuery on QUERY -directive @onMutation on MUTATION -directive @onSubscription on SUBSCRIPTION - -"The Int scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The Float scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The String scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The Boolean scalar type represents true or false ." -scalar Boolean -"The ID scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as 4) or integer (such as 4) input value will be accepted as an ID." -scalar ID @custom(typeName: "string") -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of FieldSelections, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""ValidArguments provided to FieldSelections or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the __TypeKind enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given __Type is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. fields and interfaces are valid fields." - OBJECT - "Indicates this type is an interface. fields and possibleTypes are valid fields." - INTERFACE - "Indicates this type is a union. possibleTypes is a valid field." - UNION - "Indicates this type is an enum. enumValues is a valid field." - ENUM - "Indicates this type is an input object. inputFields is a valid field." - INPUT_OBJECT - "Indicates this type is a list. ofType is a valid field." - LIST - "Indicates this type is a non-null. ofType is a valid field." - NON_NULL -}` - -const benchmarkTestOperation = ` -query PostsUserQuery { - posts { - id - description - user { - id - name - } - } -} -fragment FirstFragment on Post { - id -} -query ArgsQuery { - foo(bar: "barValue", baz: true){ - fooField - } -} -query VariableQuery($bar: String, $baz: Boolean) { - foo(bar: $bar, baz: $baz){ - fooField - } -} -query VariableQuery { - posts { - id @include(if: true) - user - } -} -` - -const benchmarkTestOperationFlat = `query PostsUserQuery {posts {id description user {id name}}} fragment FirstFragment on Post {id} query ArgsQuery {foo(bar: "barValue", baz: true){fooField}} query VariableQuery($bar: String, $baz: Boolean){foo(bar: $bar, baz: $baz){fooField}} query VariableQuery {posts {id @include(if: true) user}}` - -const benchmarkTestDefinition = ` -directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -schema { - query: Query -} -type Query { - posts: [Post] - foo(bar: String!, baz: Boolean!): Foo -} -type User { - id: ID - name: String -} -type Post { - id: ID - description: String - user: User -} -type Foo { - fooField: String -} -scalar ID -scalar String -` diff --git a/pkg/astprinter/fixtures/introspectionquery.golden b/pkg/astprinter/fixtures/introspectionquery.golden deleted file mode 100644 index 1bf344a17..000000000 --- a/pkg/astprinter/fixtures/introspectionquery.golden +++ /dev/null @@ -1,210 +0,0 @@ -query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true){ - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true){ - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -} - -subscription sub { - ...multipleSubscriptions -} - -fragment multipleSubscriptions on Subscription { - ...{ - newMessage { - body - } - } - ... on Subscription { - typedInlineFragment - } - newMessage { - body - sender - } - disallowedSecondRootField -} - -{ - dog { - ...aliasedLyingFieldTargetNotDefined - } -} - -query argOnRequiredArg($catCommand: CatCommand @include(if: true), $complex: Boolean = true){ - dog { - doesKnowCommand(dogCommand: $catCommand) - } -} - -query directivesQuery @foo(bar: BAZ) { - dog @include(if: true, or: false) { - doesKnowCommand(dogCommand: $catCommand) - } -} - -{ - dog { - name: nickname - ... @include(if: true){ - name - } - } - cat { - name @include(if: true) @skip(if: true) - nickname - } - cat { - name @include(if: true) - nickname - } -} - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -extend schema @foo { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Foo { - field: String -} - -extend type Foo @foo { - field: String -} - -input Foo { - field: String - field2: Boolean = true -} - -extend input Foo @foo { - field: String -} - -interface Foo { - field: String - field2: Boolean -} - -extend interface Foo @foo { - field: String -} - -scalar JSON - -extend scalar JSON @foo - -union Foo = BAR | BAZ - -extend union Foo @foo = BAR | BAZ - -enum Foo { - BAR - BAZ -} - -extend enum Foo @foo { - BAR - BAZ -} \ No newline at end of file diff --git a/pkg/astprinter/fixtures/starwars_schema_definition.golden b/pkg/astprinter/fixtures/starwars_schema_definition.golden deleted file mode 100644 index 25ae06663..000000000 --- a/pkg/astprinter/fixtures/starwars_schema_definition.golden +++ /dev/null @@ -1,404 +0,0 @@ -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -"The query type, represents all of the entry points into our object graph" -type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human - starship(id: ID!): Starship -} - -extend type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human - starship(id: ID!): Starship -} - -"The mutation type, represents all updates we can make to our data" -type Mutation { - createReview(episode: Episode, review: ReviewInput!): Review -} - -"The subscription type, represents all subscriptions we can make to our data" -type Subscription { - reviewAdded(episode: Episode): Review -} - -"The episodes in the Star Wars trilogy" -enum Episode { - """ - Star Wars Episode IV: A New Hope, released in 1977. - """ - NEWHOPE - """ - Star Wars Episode V: The Empire Strikes Back, released in 1980. - """ - EMPIRE - """ - Star Wars Episode VI: Return of the Jedi, released in 1983. - Star Wars Episode VI: Return of the Jedi, released in 1983. - - Star Wars Episode VI: Return of the Jedi, released in 1983. - Star Wars Episode VI: Return of the Jedi, released in 1983. - """ - JEDI -} - -"A character from the Star Wars universe" -interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -extend interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -"Units of height" -enum LengthUnit { - "The standard unit around the world" - METER - "Primarily used in the United States" - FOOT -} - -"A humanoid creature from the Star Wars universe" -type Human implements Character { - "The ID of the human" - id: ID! - "What this human calls themselves" - name: String! - "The home planet of the human, or null if unknown" - homePlanet: String - "Height in the preferred unit, default is meters" - height(unit: LengthUnit = METER): Float - "Mass in kilograms, or null if unknown" - mass: Float - "This human's friends, or an empty list if they have none" - friends: [Character] - "The friends of the human exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this human appears in" - appearsIn: [Episode]! - "A list of starships this person has piloted, or an empty list if none" - starships: [Starship] -} - -"An autonomous mechanical character in the Star Wars universe" -type Droid implements Character { - "The ID of the droid" - id: ID! - "What others call this droid" - name: String! - "This droid's friends, or an empty list if they have none" - friends: [Character] - "The friends of the droid exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this droid appears in" - appearsIn: [Episode]! - "This droid's primary function" - primaryFunction: String -} - -"A connection object for a character's friends" -type FriendsConnection { - "The total number of friends" - totalCount: Int - "The edges for each of the character's friends." - edges: [FriendsEdge] - "A list of the friends, as a convenience when edges are not needed." - friends: [Character] - "Information for paginating this connection" - pageInfo: PageInfo! -} - -"An edge object for a character's friends" -type FriendsEdge { - "A cursor used for pagination" - cursor: ID! - "The character represented by this friendship edge" - node: Character -} - -"Information for paginating this connection" -type PageInfo { - startCursor: ID - endCursor: ID - hasNextPage: Boolean! -} - -"Represents a review for a movie" -type Review { - "The movie" - episode: Episode - "The number of stars this review gave, 1-5" - stars: Int! - "Comment about the movie" - commentary: String -} - -"The input object sent when someone is creating a new review" -input ReviewInput { - "0-5 stars" - stars: Int! - "Comment about the movie, optional" - commentary: String - "Favorite color, optional" - favorite_color: ColorInput -} - -"The input object sent when passing in a color" -input ColorInput { - red: Int! - green: Int! - blue: Int! @someDirective(someArg: "some value") -} - -type Starship { - "The ID of the starship" - id: ID! - "The name of the starship" - name: String! - "Length of the starship, along the longest axis" - length(unit: LengthUnit = METER): Float -} - -union SearchResult = Human | Droid | Starship - -"The `Int` scalar type represents non-fractional signed whole numeric values. Int can representvalues between -(2^31) and 2^31 - 1." -scalar Int - -"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The `Boolean` scalar type represents `true` or `false` ." -scalar Boolean - -"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `4`) or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included whentrue." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -directive @someDirective( - "some argument description" - someArg: String = "Some Arg" -) on INPUT_FIELD_DEFINITION - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the `__TypeKind` enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given `__Type` is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. `fields` and `interfaces` are valid fields." - OBJECT - "Indicates this type is an interface. `fields` ` and ` `possibleTypes` are valid fields." - INTERFACE - "Indicates this type is a union. `possibleTypes` is a valid field." - UNION - "Indicates this type is an enum. `enumValues` is a valid field." - ENUM - "Indicates this type is an input object. `inputFields` is a valid field." - INPUT_OBJECT - "Indicates this type is a list. `ofType` is a valid field." - LIST - "Indicates this type is a non-null. `ofType` is a valid field." - NON_NULL -} - -interface Foo { - a: String -} - -interface Bar { - b: String -} - -type FooBar implements Foo & Bar { - a: String - b: String -} \ No newline at end of file diff --git a/pkg/astprinter/testdata/introspectionquery.graphql b/pkg/astprinter/testdata/introspectionquery.graphql deleted file mode 100644 index 3248135a1..000000000 --- a/pkg/astprinter/testdata/introspectionquery.graphql +++ /dev/null @@ -1,210 +0,0 @@ -query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -} - -subscription sub { - ...multipleSubscriptions -} - -fragment multipleSubscriptions on Subscription { - ... { - newMessage { - body - } - } - ... on Subscription { - typedInlineFragment - } - newMessage { - body - sender - } - disallowedSecondRootField -} - -{ - dog { - ...aliasedLyingFieldTargetNotDefined - } -} - -query argOnRequiredArg($catCommand: CatCommand @include(if: true), $complex: Boolean = true) { - dog { - doesKnowCommand(dogCommand: $catCommand) - } -} - -query directivesQuery @foo(bar: BAZ) { - dog @include(if: true, or: false) { - doesKnowCommand(dogCommand: $catCommand) - } -} - -{ - dog { - name: nickname - ... @include(if: true) { - name - } - } - cat { - name @include(if: true) @skip(if: true) - nickname - } - cat { - name @include(if: true) - nickname - } -} - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -extend schema @foo { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Foo { - field: String -} - -extend type Foo @foo { - field: String -} - -input Foo { - field: String - field2: Boolean = true -} - -extend input Foo @foo { - field: String -} - -interface Foo { - field: String - field2: Boolean -} - -extend interface Foo @foo { - field: String -} - -scalar JSON - -extend scalar JSON @foo - -union Foo = BAR | BAZ - -extend union Foo @foo = BAR | BAZ - -enum Foo { - BAR - BAZ -} - -extend enum Foo @foo { - BAR - BAZ -} \ No newline at end of file diff --git a/pkg/astprinter/testdata/starwars.schema.graphql b/pkg/astprinter/testdata/starwars.schema.graphql deleted file mode 100644 index 2661f079a..000000000 --- a/pkg/astprinter/testdata/starwars.schema.graphql +++ /dev/null @@ -1,392 +0,0 @@ -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -"The query type, represents all of the entry points into our object graph" -type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human - starship(id: ID!): Starship -} - -extend type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human - starship(id: ID!): Starship -} - -"The mutation type, represents all updates we can make to our data" -type Mutation { - createReview(episode: Episode, review: ReviewInput!): Review -} - -"The subscription type, represents all subscriptions we can make to our data" -type Subscription { - reviewAdded(episode: Episode): Review -} - -"The episodes in the Star Wars trilogy" -enum Episode { - """ - Star Wars Episode IV: A New Hope, released in 1977. - """ - NEWHOPE - """ - Star Wars Episode V: The Empire Strikes Back, released in 1980.""" - EMPIRE - """ - Star Wars Episode VI: Return of the Jedi, released in 1983. -Star Wars Episode VI: Return of the Jedi, released in 1983. - - Star Wars Episode VI: Return of the Jedi, released in 1983. -Star Wars Episode VI: Return of the Jedi, released in 1983. - """ - JEDI -} - -"A character from the Star Wars universe" -interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -extend interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -"Units of height" -enum LengthUnit { - "The standard unit around the world" - METER - "Primarily used in the United States" - FOOT -} - -"A humanoid creature from the Star Wars universe" -type Human implements Character { - "The ID of the human" - id: ID! - "What this human calls themselves" - name: String! - "The home planet of the human, or null if unknown" - homePlanet: String - "Height in the preferred unit, default is meters" - height(unit: LengthUnit = METER): Float - "Mass in kilograms, or null if unknown" - mass: Float - "This human's friends, or an empty list if they have none" - friends: [Character] - "The friends of the human exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this human appears in" - appearsIn: [Episode]! - "A list of starships this person has piloted, or an empty list if none" - starships: [Starship] -} - -"An autonomous mechanical character in the Star Wars universe" - type Droid implements Character { - "The ID of the droid" - id: ID! - "What others call this droid" - name: String! - "This droid's friends, or an empty list if they have none" - friends: [Character] - "The friends of the droid exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this droid appears in" - appearsIn: [Episode]! - "This droid's primary function" - primaryFunction: String -} - -"A connection object for a character's friends" - type FriendsConnection { - "The total number of friends" - totalCount: Int - "The edges for each of the character's friends." - edges: [FriendsEdge] - "A list of the friends, as a convenience when edges are not needed." - friends: [Character] - "Information for paginating this connection" - pageInfo: PageInfo! -} - -"An edge object for a character's friends" - type FriendsEdge { - "A cursor used for pagination" - cursor: ID! - "The character represented by this friendship edge" - node: Character -} - -"Information for paginating this connection" - type PageInfo { - startCursor: ID - endCursor: ID - hasNextPage: Boolean! -} - -"Represents a review for a movie" - type Review { - "The movie" - episode: Episode - "The number of stars this review gave, 1-5" - stars: Int! - "Comment about the movie" - commentary: String -} - -"The input object sent when someone is creating a new review" - input ReviewInput { - "0-5 stars" - stars: Int! - "Comment about the movie, optional" - commentary: String - "Favorite color, optional" - favorite_color: ColorInput -} - -"The input object sent when passing in a color" - input ColorInput { - red: Int! - green: Int! - blue: Int! @someDirective(someArg: "some value") -} - -type Starship { - "The ID of the starship" - id: ID! - "The name of the starship" - name: String! - "Length of the starship, along the longest axis" - length(unit: LengthUnit = METER): Float -} - -union SearchResult = Human | Droid | Starship - -"The `Int` scalar type represents non-fractional signed whole numeric values. Int can representvalues between -(2^31) and 2^31 - 1." -scalar Int -"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The `Boolean` scalar type represents `true` or `false` ." -scalar Boolean -"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `4`) or integer (such as 4) input value will be accepted as an ID." -scalar ID -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included whentrue." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -directive @someDirective( - "some argument description" - someArg: String = "Some Arg" -) on INPUT_FIELD_DEFINITION - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the `__TypeKind` enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given `__Type` is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. `fields` and `interfaces` are valid fields." - OBJECT - "Indicates this type is an interface. `fields` ` and ` `possibleTypes` are valid fields." - INTERFACE - "Indicates this type is a union. `possibleTypes` is a valid field." - UNION - "Indicates this type is an enum. `enumValues` is a valid field." - ENUM - "Indicates this type is an input object. `inputFields` is a valid field." - INPUT_OBJECT - "Indicates this type is a list. `ofType` is a valid field." - LIST - "Indicates this type is a non-null. `ofType` is a valid field." - NON_NULL -} - -interface Foo { - a: String -} -interface Bar { - b: String -} -type FooBar implements Foo & Bar { - a: String - b: String -} diff --git a/pkg/asttransform/asttransform.go b/pkg/asttransform/asttransform.go deleted file mode 100644 index 5fbe7e3bf..000000000 --- a/pkg/asttransform/asttransform.go +++ /dev/null @@ -1,167 +0,0 @@ -// Package asttransform contains a set of helper methods to make recursive ast transformations possible. -// -// This is especially useful for ast normalization for nested fragment inlining. -// -// This packages is necessary to make AST transformations possible while walking an AST recusively. -// In order to resolve dependencies in a tree (inline fragments & fragment spreads) it's necessary to resolve them in a specific order. -// The right order to not mess things up is from the deepest level up to the root. -// Therefore this package is used to register transformations while walking an AST in order to bring all transformations in the right order. -// Only then, when all transformations are in the right order according to depth, it's possible to safely apply them. -package asttransform - -import ( - "sort" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -type ( - // Transformable defines the interface which needs to be implemented in order to apply Transformations - // This needs to be implemented by any AST in order to be transformable - Transformable interface { - // DeleteRootNode marks a Node for deletion - DeleteRootNode(node ast.Node) - // EmptySelectionSet marks a selectionset for emptying - EmptySelectionSet(ref int) - // AppendSelectionSet marks to append a reference to a selectionset - AppendSelectionSet(ref int, appendRef int) - // ReplaceFragmentSpread marks to replace a fragment spread with a selectionset - ReplaceFragmentSpread(selectionSet int, spreadRef int, replaceWithSelectionSet int) - // ReplaceFragmentSpreadWithInlineFragment marks a fragment spread to be replaces with an inline fragment - ReplaceFragmentSpreadWithInlineFragment(selectionSet int, spreadRef int, replaceWithSelectionSet int, typeCondition ast.TypeCondition) - } - transformation interface { - apply(transformable Transformable) - } - // Precedence defines Depth and Order of each transformation - Precedence struct { - Depth int - Order int - } - action struct { - precedence Precedence - transformation transformation - } - // Transformer takes transformation registrations and applies them - Transformer struct { - actions []action - } -) - -// Reset empties all actions -func (t *Transformer) Reset() { - t.actions = t.actions[:0] -} - -// ApplyTransformations applies all registered transformations to a transformable -func (t *Transformer) ApplyTransformations(transformable Transformable) { - - sort.Slice(t.actions, func(i, j int) bool { - if t.actions[i].precedence.Depth != t.actions[j].precedence.Depth { - return t.actions[i].precedence.Depth > t.actions[j].precedence.Depth - } - return t.actions[i].precedence.Order < t.actions[j].precedence.Order - }) - - for i := range t.actions { - t.actions[i].transformation.apply(transformable) - } -} - -// DeleteRootNode registers an action to delete a root node -func (t *Transformer) DeleteRootNode(precedence Precedence, node ast.Node) { - t.actions = append(t.actions, action{ - precedence: precedence, - transformation: deleteRootNode{node: node}, - }) -} - -// EmptySelectionSet registers an actions to empty a selectionset -func (t *Transformer) EmptySelectionSet(precedence Precedence, ref int) { - t.actions = append(t.actions, action{ - precedence: precedence, - transformation: emptySelectionSet{ref: ref}, - }) -} - -// AppendSelectionSet registers an action to append a selection to a selectionset -func (t *Transformer) AppendSelectionSet(precedence Precedence, ref int, appendRef int) { - t.actions = append(t.actions, action{ - precedence: precedence, - transformation: appendSelectionSet{ - ref: ref, - appendRef: appendRef, - }, - }) -} - -// ReplaceFragmentSpread registers an action to replace a fragment spread with a selectionset -func (t *Transformer) ReplaceFragmentSpread(precedence Precedence, selectionSet int, spreadRef int, replaceWithSelectionSet int) { - t.actions = append(t.actions, action{ - precedence: precedence, - transformation: replaceFragmentSpread{ - selectionSet: selectionSet, - spreadRef: spreadRef, - replaceWithSelectionSet: replaceWithSelectionSet, - }, - }) -} - -// ReplaceFragmentSpreadWithInlineFragment registers an action to replace a fragment spread with an inline fragment -func (t *Transformer) ReplaceFragmentSpreadWithInlineFragment(precedence Precedence, selectionSet int, spreadRef int, replaceWithSelectionSet int, typeCondition ast.TypeCondition) { - t.actions = append(t.actions, action{ - precedence: precedence, - transformation: replaceFragmentSpreadWithInlineFragment{ - selectionSet: selectionSet, - spreadRef: spreadRef, - replaceWithSelectionSet: replaceWithSelectionSet, - typeCondition: typeCondition, - }, - }) -} - -type replaceFragmentSpread struct { - selectionSet int - spreadRef int - replaceWithSelectionSet int -} - -func (r replaceFragmentSpread) apply(transformable Transformable) { - transformable.ReplaceFragmentSpread(r.selectionSet, r.spreadRef, r.replaceWithSelectionSet) -} - -type replaceFragmentSpreadWithInlineFragment struct { - selectionSet int - spreadRef int - replaceWithSelectionSet int - typeCondition ast.TypeCondition -} - -func (r replaceFragmentSpreadWithInlineFragment) apply(transformable Transformable) { - transformable.ReplaceFragmentSpreadWithInlineFragment(r.selectionSet, r.spreadRef, r.replaceWithSelectionSet, r.typeCondition) -} - -type deleteRootNode struct { - node ast.Node -} - -func (d deleteRootNode) apply(transformable Transformable) { - transformable.DeleteRootNode(d.node) -} - -type emptySelectionSet struct { - ref int -} - -func (e emptySelectionSet) apply(transformable Transformable) { - transformable.EmptySelectionSet(e.ref) -} - -type appendSelectionSet struct { - ref int - appendRef int -} - -func (a appendSelectionSet) apply(transformable Transformable) { - transformable.AppendSelectionSet(a.ref, a.appendRef) -} diff --git a/pkg/asttransform/baseschema.go b/pkg/asttransform/baseschema.go deleted file mode 100644 index b2168fd4f..000000000 --- a/pkg/asttransform/baseschema.go +++ /dev/null @@ -1,321 +0,0 @@ -package asttransform - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func MergeDefinitionWithBaseSchema(definition *ast.Document) error { - definition.Input.AppendInputBytes(baseSchema) - parser := astparser.NewParser() - report := operationreport.Report{} - parser.Parse(definition, &report) - if report.HasErrors() { - return report - } - return handleSchema(definition) -} - -func handleSchema(definition *ast.Document) error { - var queryNodeRef int - queryNode, hasQueryNode := findQueryNode(definition) - if hasQueryNode { - queryNodeRef = queryNode.Ref - } else { - queryNodeRef = definition.ImportObjectTypeDefinition("Query", "", nil, nil) - } - - addSchemaDefinition(definition) - addMissingRootOperationTypeDefinitions(definition) - addIntrospectionQueryFields(definition, queryNodeRef) - - typeNamesVisitor := NewTypeNameVisitor() - - return typeNamesVisitor.ExtendSchema(definition) -} - -func addSchemaDefinition(definition *ast.Document) { - if definition.HasSchemaDefinition() { - return - } - - schemaDefinition := ast.SchemaDefinition{} - definition.AddSchemaDefinitionRootNode(schemaDefinition) -} - -func addMissingRootOperationTypeDefinitions(definition *ast.Document) { - var rootOperationTypeRefs []int - - for i := range definition.RootNodes { - if definition.RootNodes[i].Kind == ast.NodeKindObjectTypeDefinition { - typeName := definition.ObjectTypeDefinitionNameBytes(definition.RootNodes[i].Ref) - - switch { - case bytes.Equal(typeName, ast.DefaultQueryTypeName): - rootOperationTypeRefs = createRootOperationTypeIfNotExists(definition, rootOperationTypeRefs, ast.OperationTypeQuery, i) - case bytes.Equal(typeName, ast.DefaultMutationTypeName): - rootOperationTypeRefs = createRootOperationTypeIfNotExists(definition, rootOperationTypeRefs, ast.OperationTypeMutation, i) - case bytes.Equal(typeName, ast.DefaultSubscriptionTypeName): - rootOperationTypeRefs = createRootOperationTypeIfNotExists(definition, rootOperationTypeRefs, ast.OperationTypeSubscription, i) - default: - continue - } - } - } - - definition.SchemaDefinitions[definition.SchemaDefinitionRef()].AddRootOperationTypeDefinitionRefs(rootOperationTypeRefs...) -} - -func createRootOperationTypeIfNotExists(definition *ast.Document, rootOperationTypeRefs []int, operationType ast.OperationType, nodeRef int) []int { - for i := range definition.RootOperationTypeDefinitions { - if definition.RootOperationTypeDefinitions[i].OperationType == operationType { - return rootOperationTypeRefs - } - } - - ref := definition.CreateRootOperationTypeDefinition(operationType, nodeRef) - return append(rootOperationTypeRefs, ref) -} - -func addIntrospectionQueryFields(definition *ast.Document, objectTypeDefinitionRef int) { - var fieldRefs []int - if !definition.ObjectTypeDefinitionHasField(objectTypeDefinitionRef, []byte("__schema")) { - fieldRefs = append(fieldRefs, addSchemaField(definition)) - } - - if !definition.ObjectTypeDefinitionHasField(objectTypeDefinitionRef, []byte("__type")) { - fieldRefs = append(fieldRefs, addTypeField(definition)) - } - - definition.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs = append(definition.ObjectTypeDefinitions[objectTypeDefinitionRef].FieldsDefinition.Refs, fieldRefs...) - definition.ObjectTypeDefinitions[objectTypeDefinitionRef].HasFieldDefinitions = true -} - -func addSchemaField(definition *ast.Document) (ref int) { - fieldNameRef := definition.Input.AppendInputBytes([]byte("__schema")) - fieldTypeRef := definition.AddNonNullNamedType([]byte("__Schema")) - - return definition.AddFieldDefinition(ast.FieldDefinition{ - Name: fieldNameRef, - Type: fieldTypeRef, - }) -} - -func addTypeField(definition *ast.Document) (ref int) { - fieldNameRef := definition.Input.AppendInputBytes([]byte("__type")) - fieldTypeRef := definition.AddNamedType([]byte("__Type")) - - argumentNameRef := definition.Input.AppendInputBytes([]byte("name")) - argumentTypeRef := definition.AddNonNullNamedType([]byte("String")) - - argumentRef := definition.AddInputValueDefinition(ast.InputValueDefinition{ - Name: argumentNameRef, - Type: argumentTypeRef, - }) - - return definition.AddFieldDefinition(ast.FieldDefinition{ - Name: fieldNameRef, - Type: fieldTypeRef, - - HasArgumentsDefinitions: true, - ArgumentsDefinition: ast.InputValueDefinitionList{ - Refs: []int{argumentRef}, - }, - }) -} - -func findQueryNode(definition *ast.Document) (queryNode ast.Node, ok bool) { - queryNode, ok = definition.Index.FirstNodeByNameBytes(definition.Index.QueryTypeName) - if !ok { - queryNode, ok = definition.Index.FirstNodeByNameStr("Query") - } - - return queryNode, ok -} - -var baseSchema = []byte(`"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -}`) diff --git a/pkg/asttransform/baseschema_test.go b/pkg/asttransform/baseschema_test.go deleted file mode 100644 index 7bd48efa0..000000000 --- a/pkg/asttransform/baseschema_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package asttransform - -import ( - "bytes" - "os" - "testing" - - "github.com/jensneuse/diffview" - - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func runTestMerge(definition, fixtureName string) func(t *testing.T) { - return func(t *testing.T) { - doc := unsafeparser.ParseGraphqlDocumentString(definition) - err := MergeDefinitionWithBaseSchema(&doc) - if err != nil { - panic(err) - } - buf := bytes.Buffer{} - err = astprinter.PrintIndent(&doc, nil, []byte(" "), &buf) - if err != nil { - panic(err) - } - got := buf.Bytes() - goldie.Assert(t, fixtureName, got) - if t.Failed() { - want, err := os.ReadFile("./fixtures/" + fixtureName + ".golden") - if err != nil { - panic(err) - } - diffview.NewGoland().DiffViewBytes(fixtureName, want, got) - } - } -} - -func TestMergeDefinitionWithBaseSchema(t *testing.T) { - t.Run("simple", runTestMerge(` - schema { - query: Query - } - type Query { - hello(name: String): Hello! - } - type Hello { - hello: String! - object: String! - adminInformation: String! - } - `, "simple")) - t.Run("mutation only", runTestMerge(` - type Mutation { - m: String! - } - `, "mutation_only")) - t.Run("schema with mutation", runTestMerge(` - schema { - mutation: Mutation - } - type Mutation { - m: String! - } - `, "mutation_only")) - - t.Run("subscription only", runTestMerge(` - type Subscription { - s: String! - } - `, "subscription_only")) - t.Run("schema with subscription", runTestMerge(` - schema { - subscription: Subscription - } - type Subscription { - s: String! - } - `, "subscription_only")) - t.Run("schema with renamed subscription", runTestMerge(` - schema { - subscription: Sub - } - type Sub { - s: String! - } - `, "subscription_renamed")) - - t.Run("schema missing", runTestMerge(` - type Query { - hello(name: String): Hello! - } - type Hello { - hello: String! - object: String! - adminInformation: String! - } - `, "schema_missing")) - t.Run("custom query type name", runTestMerge(` - schema { - query: query_root - } - type query_root { - hello(name: String): Hello! - } - type Hello { - hello: String! - object: String! - adminInformation: String! - } - `, "custom_query_name")) - t.Run("complete", runTestMerge(` - schema { - query: Query - } - type Query { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - } - type Hello { - hello: String! - object: String! - adminInformation: String! - } - `, "complete")) - t.Run("with mutation & subscription", runTestMerge(` - schema { - query: Query - mutation: Mutation - subscription: Subscription - } - type Mutation { - m: String! - } - type Subscription { - s: String! - } - type Query { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - } - type Hello { - hello: String! - object: String! - adminInformation: String! - } - `, "with_mutation_subscription")) -} diff --git a/pkg/asttransform/fixtures/complete.golden b/pkg/asttransform/fixtures/complete.golden deleted file mode 100644 index 21d09c0a2..000000000 --- a/pkg/asttransform/fixtures/complete.golden +++ /dev/null @@ -1,216 +0,0 @@ -schema { - query: Query -} - -type Query { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} - -type Hello { - hello: String! - object: String! - adminInformation: String! - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/custom_query_name.golden b/pkg/asttransform/fixtures/custom_query_name.golden deleted file mode 100644 index b96b84cbc..000000000 --- a/pkg/asttransform/fixtures/custom_query_name.golden +++ /dev/null @@ -1,216 +0,0 @@ -schema { - query: query_root -} - -type query_root { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} - -type Hello { - hello: String! - object: String! - adminInformation: String! - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/mutation_only.golden b/pkg/asttransform/fixtures/mutation_only.golden deleted file mode 100644 index c68aff9cb..000000000 --- a/pkg/asttransform/fixtures/mutation_only.golden +++ /dev/null @@ -1,214 +0,0 @@ -schema { - mutation: Mutation - query: Query -} - -type Mutation { - m: String! - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} - -type Query { - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/schema_missing.golden b/pkg/asttransform/fixtures/schema_missing.golden deleted file mode 100644 index 21d09c0a2..000000000 --- a/pkg/asttransform/fixtures/schema_missing.golden +++ /dev/null @@ -1,216 +0,0 @@ -schema { - query: Query -} - -type Query { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} - -type Hello { - hello: String! - object: String! - adminInformation: String! - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/simple.golden b/pkg/asttransform/fixtures/simple.golden deleted file mode 100644 index 21d09c0a2..000000000 --- a/pkg/asttransform/fixtures/simple.golden +++ /dev/null @@ -1,216 +0,0 @@ -schema { - query: Query -} - -type Query { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} - -type Hello { - hello: String! - object: String! - adminInformation: String! - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/subscription_only.golden b/pkg/asttransform/fixtures/subscription_only.golden deleted file mode 100644 index 4f0b1976c..000000000 --- a/pkg/asttransform/fixtures/subscription_only.golden +++ /dev/null @@ -1,213 +0,0 @@ -schema { - subscription: Subscription - query: Query -} - -type Subscription { - s: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} - -type Query { - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/subscription_renamed.golden b/pkg/asttransform/fixtures/subscription_renamed.golden deleted file mode 100644 index 022fb7feb..000000000 --- a/pkg/asttransform/fixtures/subscription_renamed.golden +++ /dev/null @@ -1,213 +0,0 @@ -schema { - subscription: Sub - query: Query -} - -type Sub { - s: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} - -type Query { - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} \ No newline at end of file diff --git a/pkg/asttransform/fixtures/with_mutation_subscription.golden b/pkg/asttransform/fixtures/with_mutation_subscription.golden deleted file mode 100644 index cf6615aa7..000000000 --- a/pkg/asttransform/fixtures/with_mutation_subscription.golden +++ /dev/null @@ -1,227 +0,0 @@ -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Mutation { - m: String! - __typename: String! -} - -type Subscription { - s: String! -} - -type Query { - hello(name: String): Hello! - __schema: __Schema! - __type(name: String!): __Type - __typename: String! -} - -type Hello { - hello: String! - object: String! - adminInformation: String! - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} \ No newline at end of file diff --git a/pkg/asttransform/typename_visitor.go b/pkg/asttransform/typename_visitor.go deleted file mode 100644 index 036553c66..000000000 --- a/pkg/asttransform/typename_visitor.go +++ /dev/null @@ -1,87 +0,0 @@ -package asttransform - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const typenameFieldName = "__typename" - -type TypeNameVisitor struct { - *astvisitor.Walker - definition *ast.Document -} - -func NewTypeNameVisitor() *TypeNameVisitor { - walker := astvisitor.NewWalker(48) - - visitor := &TypeNameVisitor{ - Walker: &walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterLeaveObjectTypeDefinitionVisitor(visitor) - walker.RegisterLeaveInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterLeaveUnionTypeDefinitionVisitor(visitor) - - return visitor -} - -func (v *TypeNameVisitor) ExtendSchema(definition *ast.Document) error { - report := &operationreport.Report{} - - v.Walk(definition, definition, report) - - if report.HasErrors() { - return report - } - return nil -} - -func (v *TypeNameVisitor) EnterDocument(definition, _ *ast.Document) { - v.definition = definition -} - -func (v *TypeNameVisitor) LeaveInterfaceTypeDefinition(ref int) { - if v.definition.InterfaceTypeDefinitions[ref].HasFieldDefinitions && - v.definition.FieldDefinitionsContainField(v.definition.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs, literal.TYPENAME) { - return - } - - v.definition.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs = append(v.definition.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs, v.addTypeNameField()) - v.definition.InterfaceTypeDefinitions[ref].HasFieldDefinitions = true -} - -func (v *TypeNameVisitor) LeaveObjectTypeDefinition(ref int) { - objectTypeDefName := v.definition.ObjectTypeDefinitionNameBytes(ref) - if bytes.Equal(objectTypeDefName, v.definition.Index.SubscriptionTypeName) || - bytes.Equal(objectTypeDefName, ast.DefaultSubscriptionTypeName) { - return - } - - if v.definition.ObjectTypeDefinitions[ref].HasFieldDefinitions && - v.definition.ObjectTypeDefinitionHasField(ref, literal.TYPENAME) { - return - } - - v.definition.ObjectTypeDefinitions[ref].FieldsDefinition.Refs = append(v.definition.ObjectTypeDefinitions[ref].FieldsDefinition.Refs, v.addTypeNameField()) - v.definition.ObjectTypeDefinitions[ref].HasFieldDefinitions = true -} - -func (v *TypeNameVisitor) LeaveUnionTypeDefinition(ref int) { - if v.definition.UnionTypeDefinitions[ref].HasFieldDefinitions && - v.definition.UnionTypeDefinitionHasField(ref, literal.TYPENAME) { - return // this makes the operation idempotent - } - v.definition.UnionTypeDefinitions[ref].FieldsDefinition.Refs = []int{v.addTypeNameField()} - v.definition.UnionTypeDefinitions[ref].HasFieldDefinitions = true -} - -func (v *TypeNameVisitor) addTypeNameField() (ref int) { - typeRef := v.definition.AddNonNullNamedType(literal.STRING) - return v.definition.ImportFieldDefinition(typenameFieldName, "", typeRef, nil, nil) -} diff --git a/pkg/astvalidation/definition_validation.go b/pkg/astvalidation/definition_validation.go deleted file mode 100644 index 5c0e41e6f..000000000 --- a/pkg/astvalidation/definition_validation.go +++ /dev/null @@ -1,56 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func DefaultDefinitionValidator() *DefinitionValidator { - return NewDefinitionValidator( - PopulatedTypeBodies(), - UniqueOperationTypes(), - UniqueTypeNames(), - UniqueFieldDefinitionNames(), - UniqueEnumValueNames(), - UniqueUnionMemberTypes(), - KnownTypeNames(), - RequireDefinedTypesForExtensions(), - ImplementTransitiveInterfaces(), - ImplementingTypesAreSupersets(), - DirectivesAreUniquePerLocation(), - ) -} - -func NewDefinitionValidator(rules ...Rule) *DefinitionValidator { - validator := &DefinitionValidator{ - walker: astvisitor.NewWalker(48), - } - - for _, rule := range rules { - validator.RegisterRule(rule) - } - - return validator -} - -type DefinitionValidator struct { - walker astvisitor.Walker -} - -func (d *DefinitionValidator) RegisterRule(rule Rule) { - rule(&d.walker) -} - -func (d *DefinitionValidator) Validate(definition *ast.Document, report *operationreport.Report) ValidationState { - if report == nil { - report = &operationreport.Report{} - } - - d.walker.Walk(definition, definition, report) - - if report.HasErrors() { - return Invalid - } - return Valid -} diff --git a/pkg/astvalidation/definition_validation_test.go b/pkg/astvalidation/definition_validation_test.go deleted file mode 100644 index 112c82275..000000000 --- a/pkg/astvalidation/definition_validation_test.go +++ /dev/null @@ -1,27 +0,0 @@ -package astvalidation - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" -) - -func runDefinitionValidation(t *testing.T, definitionInput string, expectation ValidationState, rules ...Rule) { - definition, report := astparser.ParseGraphqlDocumentString(definitionInput) - require.False(t, report.HasErrors()) - - err := asttransform.MergeDefinitionWithBaseSchema(&definition) - require.NoError(t, err) - - validator := &DefinitionValidator{} - for _, rule := range rules { - validator.RegisterRule(rule) - } - - result := validator.Validate(&definition, &report) - assert.Equal(t, expectation, result) -} diff --git a/pkg/astvalidation/operation_rule_all_variable_uses_defined.go b/pkg/astvalidation/operation_rule_all_variable_uses_defined.go deleted file mode 100644 index a2062a369..000000000 --- a/pkg/astvalidation/operation_rule_all_variable_uses_defined.go +++ /dev/null @@ -1,56 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// AllVariableUsesDefined validates if used variables are defined within the operation -func AllVariableUsesDefined() Rule { - return func(walker *astvisitor.Walker) { - visitor := allVariableUsesDefinedVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - } -} - -type allVariableUsesDefinedVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (a *allVariableUsesDefinedVisitor) EnterDocument(operation, definition *ast.Document) { - a.operation = operation - a.definition = definition -} - -func (a *allVariableUsesDefinedVisitor) EnterArgument(ref int) { - - if a.operation.Arguments[ref].Value.Kind != ast.ValueKindVariable { - return // skip because no variable - } - - if a.Ancestors[0].Kind != ast.NodeKindOperationDefinition { - // skip because variable is not used in operation which happens in case normalization did not merge the fragment definition - // this happens when a fragment is defined but not used which will itself lead to another validation error - // in which case we can safely skip here - return - } - - variableName := a.operation.VariableValueNameBytes(a.operation.Arguments[ref].Value.Ref) - - for _, i := range a.operation.OperationDefinitions[a.Ancestors[0].Ref].VariableDefinitions.Refs { - if bytes.Equal(variableName, a.operation.VariableDefinitionNameBytes(i)) { - return // return OK because variable is defined - } - } - - // at this point we're safe to say this variable was not defined on the root operation of this argument - argumentName := a.operation.ArgumentNameBytes(ref) - a.StopWithExternalErr(operationreport.ErrVariableNotDefinedOnArgument(variableName, argumentName)) -} diff --git a/pkg/astvalidation/operation_rule_all_variables_used.go b/pkg/astvalidation/operation_rule_all_variables_used.go deleted file mode 100644 index 9bb29ecad..000000000 --- a/pkg/astvalidation/operation_rule_all_variables_used.go +++ /dev/null @@ -1,84 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// AllVariablesUsed validates if all defined variables are used -func AllVariablesUsed() Rule { - return func(walker *astvisitor.Walker) { - visitor := allVariablesUsedVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterOperationVisitor(&visitor) - walker.RegisterLeaveOperationVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - } -} - -type allVariablesUsedVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - variableDefinitions []int -} - -func (a *allVariablesUsedVisitor) EnterDocument(operation, definition *ast.Document) { - a.operation = operation - a.definition = definition - a.variableDefinitions = a.variableDefinitions[:0] -} - -func (a *allVariablesUsedVisitor) EnterOperationDefinition(ref int) { - a.variableDefinitions = append(a.variableDefinitions, a.operation.OperationDefinitions[ref].VariableDefinitions.Refs...) -} - -func (a *allVariablesUsedVisitor) LeaveOperationDefinition(ref int) { - if len(a.variableDefinitions) != 0 { - operationName := a.operation.Input.ByteSlice(a.operation.OperationDefinitions[ref].Name) - for _, i := range a.variableDefinitions { - variableName := a.operation.VariableDefinitionNameBytes(i) - a.Report.AddExternalError(operationreport.ErrVariableDefinedButNeverUsed(variableName, operationName)) - } - a.Stop() - } -} - -func (a *allVariablesUsedVisitor) EnterArgument(ref int) { - - if len(a.variableDefinitions) == 0 { - return // nothing to check, skip - } - - a.verifyValue(a.operation.Arguments[ref].Value) -} - -func (a *allVariablesUsedVisitor) verifyValue(value ast.Value) { - switch value.Kind { - case ast.ValueKindVariable: // don't skip - case ast.ValueKindObject: - for _, i := range a.operation.ObjectValues[value.Ref].Refs { - a.verifyValue(a.operation.ObjectFields[i].Value) - } - return - case ast.ValueKindList: - for _, i := range a.operation.ListValues[value.Ref].Refs { - a.verifyValue(a.operation.Values[i]) - } - return - default: - return // skip all others - } - - variableName := a.operation.VariableValueNameBytes(value.Ref) - for i, j := range a.variableDefinitions { - if bytes.Equal(variableName, a.operation.VariableDefinitionNameBytes(j)) { - a.variableDefinitions = append(a.variableDefinitions[:i], a.variableDefinitions[i+1:]...) - return - } - } -} diff --git a/pkg/astvalidation/operation_rule_argument_uniqueness.go b/pkg/astvalidation/operation_rule_argument_uniqueness.go deleted file mode 100644 index 43fd455f2..000000000 --- a/pkg/astvalidation/operation_rule_argument_uniqueness.go +++ /dev/null @@ -1,42 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// ArgumentUniqueness validates if arguments are unique -func ArgumentUniqueness() Rule { - return func(walker *astvisitor.Walker) { - visitor := argumentUniquenessVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - } -} - -type argumentUniquenessVisitor struct { - *astvisitor.Walker - operation *ast.Document -} - -func (a *argumentUniquenessVisitor) EnterDocument(operation, definition *ast.Document) { - a.operation = operation -} - -func (a *argumentUniquenessVisitor) EnterArgument(ref int) { - - argumentName := a.operation.ArgumentNameBytes(ref) - argumentsAfter := a.operation.ArgumentsAfter(a.Ancestors[len(a.Ancestors)-1], ref) - - for _, i := range argumentsAfter { - if bytes.Equal(argumentName, a.operation.ArgumentNameBytes(i)) { - a.StopWithExternalErr(operationreport.ErrArgumentMustBeUnique(argumentName)) - return - } - } -} diff --git a/pkg/astvalidation/operation_rule_directives_defined.go b/pkg/astvalidation/operation_rule_directives_defined.go deleted file mode 100644 index 2b389d67d..000000000 --- a/pkg/astvalidation/operation_rule_directives_defined.go +++ /dev/null @@ -1,39 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// DirectivesAreDefined validates if used directives are defined -func DirectivesAreDefined() Rule { - return func(walker *astvisitor.Walker) { - visitor := directivesAreDefinedVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterDirectiveVisitor(&visitor) - } -} - -type directivesAreDefinedVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (d *directivesAreDefinedVisitor) EnterDocument(operation, definition *ast.Document) { - d.operation = operation - d.definition = definition -} - -func (d *directivesAreDefinedVisitor) EnterDirective(ref int) { - - directiveName := d.operation.DirectiveNameBytes(ref) - definition, exists := d.definition.Index.FirstNodeByNameBytes(directiveName) - - if !exists || definition.Kind != ast.NodeKindDirectiveDefinition { - d.StopWithExternalErr(operationreport.ErrDirectiveUndefined(directiveName)) - return - } -} diff --git a/pkg/astvalidation/operation_rule_directives_in_valid_locations.go b/pkg/astvalidation/operation_rule_directives_in_valid_locations.go deleted file mode 100644 index 2da316083..000000000 --- a/pkg/astvalidation/operation_rule_directives_in_valid_locations.go +++ /dev/null @@ -1,56 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// DirectivesAreInValidLocations validates if directives are used in the right place -func DirectivesAreInValidLocations() Rule { - return func(walker *astvisitor.Walker) { - visitor := directivesAreInValidLocationsVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterDirectiveVisitor(&visitor) - } -} - -type directivesAreInValidLocationsVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (d *directivesAreInValidLocationsVisitor) EnterDocument(operation, definition *ast.Document) { - d.operation = operation - d.definition = definition -} - -func (d *directivesAreInValidLocationsVisitor) EnterDirective(ref int) { - - directiveName := d.operation.DirectiveNameBytes(ref) - definition, exists := d.definition.Index.FirstNodeByNameBytes(directiveName) - - if !exists || definition.Kind != ast.NodeKindDirectiveDefinition { - return // not defined, skip - } - - ancestor := d.Ancestors[len(d.Ancestors)-1] - - if !d.directiveDefinitionContainsNodeLocation(definition.Ref, ancestor) { - ancestorKindName := d.operation.NodeKindNameBytes(ancestor) - d.StopWithExternalErr(operationreport.ErrDirectiveNotAllowedOnNode(directiveName, ancestorKindName)) - return - } -} - -func (d *directivesAreInValidLocationsVisitor) directiveDefinitionContainsNodeLocation(definition int, node ast.Node) bool { - - nodeDirectiveLocation, err := d.operation.NodeDirectiveLocation(node) - if err != nil { - return false - } - - return d.definition.DirectiveDefinitions[definition].DirectiveLocations.Get(nodeDirectiveLocation) -} diff --git a/pkg/astvalidation/operation_rule_directives_unique_per_location.go b/pkg/astvalidation/operation_rule_directives_unique_per_location.go deleted file mode 100644 index 2e5e57749..000000000 --- a/pkg/astvalidation/operation_rule_directives_unique_per_location.go +++ /dev/null @@ -1,68 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// DirectivesAreUniquePerLocation validates if directives are unique per location -func DirectivesAreUniquePerLocation() Rule { - return func(walker *astvisitor.Walker) { - visitor := directivesAreUniquePerLocationVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterDirectiveVisitor(&visitor) - } -} - -type directivesAreUniquePerLocationVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - seenDuplicates map[int]struct{} -} - -func (d *directivesAreUniquePerLocationVisitor) EnterDocument(operation, definition *ast.Document) { - d.operation = operation - d.definition = definition - d.seenDuplicates = make(map[int]struct{}) -} - -func (d *directivesAreUniquePerLocationVisitor) EnterDirective(ref int) { - if _, seen := d.seenDuplicates[ref]; seen { - // skip directive reported as duplicate - return - } - - directiveName := d.operation.DirectiveNameBytes(ref) - - directiveDefRef, exists := d.definition.DirectiveDefinitionByNameBytes(directiveName) - if !exists { - // ignore unknown directives - return - } - - if d.definition.DirectiveDefinitionIsRepeatable(directiveDefRef) { - // ignore repeatable directives - return - } - - nodeDirectives := d.operation.NodeDirectives(d.Ancestors[len(d.Ancestors)-1]) - for _, j := range nodeDirectives { - if j == ref { - continue - } - if bytes.Equal(directiveName, d.operation.DirectiveNameBytes(j)) { - d.seenDuplicates[j] = struct{}{} - d.Report.AddExternalError(operationreport.ErrDirectiveMustBeUniquePerLocation( - directiveName, - d.operation.Directives[ref].At, - d.operation.Directives[j].At, - )) - return - } - } -} diff --git a/pkg/astvalidation/operation_rule_document_contains_executable_operation.go b/pkg/astvalidation/operation_rule_document_contains_executable_operation.go deleted file mode 100644 index df7b0030e..000000000 --- a/pkg/astvalidation/operation_rule_document_contains_executable_operation.go +++ /dev/null @@ -1,34 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// DocumentContainsExecutableOperation validates if the document actually contains an executable Operation -func DocumentContainsExecutableOperation() Rule { - return func(walker *astvisitor.Walker) { - visitor := &documentContainsExecutableOperation{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(visitor) - } -} - -type documentContainsExecutableOperation struct { - *astvisitor.Walker -} - -func (d *documentContainsExecutableOperation) EnterDocument(operation, definition *ast.Document) { - if len(operation.RootNodes) == 0 { - d.StopWithExternalErr(operationreport.ErrDocumentDoesntContainExecutableOperation()) - return - } - for i := range operation.RootNodes { - if operation.RootNodes[i].Kind == ast.NodeKindOperationDefinition { - return - } - } - d.StopWithExternalErr(operationreport.ErrDocumentDoesntContainExecutableOperation()) -} diff --git a/pkg/astvalidation/operation_rule_field_selection_merging.go b/pkg/astvalidation/operation_rule_field_selection_merging.go deleted file mode 100644 index 9b42b0a01..000000000 --- a/pkg/astvalidation/operation_rule_field_selection_merging.go +++ /dev/null @@ -1,225 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// FieldSelectionMerging validates if field selections can be merged -func FieldSelectionMerging() Rule { - return func(walker *astvisitor.Walker) { - visitor := fieldSelectionMergingVisitor{Walker: walker} - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterFieldVisitor(&visitor) - walker.RegisterEnterOperationVisitor(&visitor) - walker.RegisterEnterFragmentDefinitionVisitor(&visitor) - } -} - -type fieldSelectionMergingVisitor struct { - *astvisitor.Walker - definition, operation *ast.Document - scalarRequirements scalarRequirements - nonScalarRequirements nonScalarRequirements - refs []int - pathCache [256][32]ast.PathItem - pathCacheIndex int -} -type nonScalarRequirement struct { - path ast.Path - objectName ast.ByteSlice - fieldTypeRef int - fieldTypeDefinitionNode ast.Node -} - -type nonScalarRequirements []nonScalarRequirement - -func (f *fieldSelectionMergingVisitor) NonScalarRequirementsByPathField(path ast.Path, objectName ast.ByteSlice) []int { - f.refs = f.refs[:0] - for i := range f.nonScalarRequirements { - if f.nonScalarRequirements[i].path.Equals(path) && f.nonScalarRequirements[i].objectName.Equals(objectName) { - f.refs = append(f.refs, i) - } - } - return f.refs -} - -type scalarRequirement struct { - path ast.Path - objectName ast.ByteSlice - fieldRef int - fieldType int - enclosingTypeDefinition ast.Node - fieldTypeDefinitionNode ast.Node -} - -type scalarRequirements []scalarRequirement - -func (f *fieldSelectionMergingVisitor) ScalarRequirementsByPathField(path ast.Path, objectName ast.ByteSlice) []int { - f.refs = f.refs[:0] - for i := range f.scalarRequirements { - if f.scalarRequirements[i].path.Equals(path) && f.scalarRequirements[i].objectName.Equals(objectName) { - f.refs = append(f.refs, i) - } - } - return f.refs -} - -func (f *fieldSelectionMergingVisitor) resetRequirements() { - f.scalarRequirements = f.scalarRequirements[:0] - f.nonScalarRequirements = f.nonScalarRequirements[:0] -} - -func (f *fieldSelectionMergingVisitor) EnterDocument(operation, definition *ast.Document) { - f.operation = operation - f.definition = definition - f.pathCacheIndex = 0 -} - -func (f *fieldSelectionMergingVisitor) EnterFragmentDefinition(ref int) { - f.resetRequirements() -} - -func (f *fieldSelectionMergingVisitor) EnterOperationDefinition(ref int) { - f.resetRequirements() -} - -func (f *fieldSelectionMergingVisitor) EnterField(ref int) { - fieldName := f.operation.FieldNameBytes(ref) - if bytes.Equal(fieldName, literal.TYPENAME) { - return - } - objectName := f.operation.FieldAliasOrNameBytes(ref) - definition, ok := f.definition.NodeFieldDefinitionByName(f.EnclosingTypeDefinition, fieldName) - if !ok { - enclosingTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition) - f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, enclosingTypeName)) - return - } - - fieldType := f.definition.FieldDefinitionType(definition) - fieldDefinitionTypeNode := f.definition.FieldDefinitionTypeNode(definition) - if fieldDefinitionTypeNode.Kind != ast.NodeKindScalarTypeDefinition { - - matchedRequirements := f.NonScalarRequirementsByPathField(f.Path, objectName) - fieldDefinitionTypeKindPresentInRequirements := false - for _, i := range matchedRequirements { - - if !f.potentiallySameObject(fieldDefinitionTypeNode, f.nonScalarRequirements[i].fieldTypeDefinitionNode) { - if !objectName.Equals(f.nonScalarRequirements[i].objectName) { - f.StopWithExternalErr(operationreport.ErrResponseOfDifferingTypesMustBeOfSameShape(objectName, f.nonScalarRequirements[i].objectName)) - return - } - } else if !f.definition.TypesAreCompatibleDeep(f.nonScalarRequirements[i].fieldTypeRef, fieldType) { - left, err := f.definition.PrintTypeBytes(f.nonScalarRequirements[i].fieldTypeRef, nil) - if err != nil { - f.StopWithInternalErr(err) - return - } - right, err := f.definition.PrintTypeBytes(fieldType, nil) - if err != nil { - f.StopWithInternalErr(err) - return - } - f.StopWithExternalErr(operationreport.ErrTypesForFieldMismatch(objectName, left, right)) - return - } - - if fieldDefinitionTypeNode.Kind != f.nonScalarRequirements[i].fieldTypeDefinitionNode.Kind { - fieldDefinitionTypeKindPresentInRequirements = true - } - } - - if len(matchedRequirements) != 0 && fieldDefinitionTypeKindPresentInRequirements { - return - } - - var path ast.Path - if f.pathCacheIndex != len(f.pathCache)-1 { - path = f.pathCache[f.pathCacheIndex][:len(f.Path)] - f.pathCacheIndex++ - } else { - path = make(ast.Path, len(f.Path)) - } - copy(path, f.Path) - - f.nonScalarRequirements = append(f.nonScalarRequirements, nonScalarRequirement{ - path: path, - objectName: objectName, - fieldTypeRef: fieldType, - fieldTypeDefinitionNode: fieldDefinitionTypeNode, - }) - return - } - - matchedRequirements := f.ScalarRequirementsByPathField(f.Path, objectName) - fieldDefinitionTypeKindPresentInRequirements := false - - for _, i := range matchedRequirements { - if f.potentiallySameObject(f.scalarRequirements[i].enclosingTypeDefinition, f.EnclosingTypeDefinition) { - if !f.operation.FieldsAreEqualFlat(f.scalarRequirements[i].fieldRef, ref) { - f.StopWithExternalErr(operationreport.ErrDifferingFieldsOnPotentiallySameType(objectName)) - return - } - } - if !f.definition.TypesAreCompatibleDeep(f.scalarRequirements[i].fieldType, fieldType) { - left, err := f.definition.PrintTypeBytes(f.scalarRequirements[i].fieldType, nil) - if err != nil { - f.StopWithInternalErr(err) - return - } - right, err := f.definition.PrintTypeBytes(fieldType, nil) - if err != nil { - f.StopWithInternalErr(err) - return - } - f.StopWithExternalErr(operationreport.ErrFieldsConflict(objectName, left, right)) - return - } - - if fieldDefinitionTypeNode.Kind != f.scalarRequirements[i].fieldTypeDefinitionNode.Kind { - fieldDefinitionTypeKindPresentInRequirements = true - } - } - - if len(matchedRequirements) != 0 && fieldDefinitionTypeKindPresentInRequirements { - return - } - - var path ast.Path - if f.pathCacheIndex != len(f.pathCache)-1 { - path = f.pathCache[f.pathCacheIndex][:len(f.Path)] - f.pathCacheIndex++ - } else { - path = make(ast.Path, len(f.Path)) - } - copy(path, f.Path) - - f.scalarRequirements = append(f.scalarRequirements, scalarRequirement{ - path: path, - objectName: objectName, - fieldRef: ref, - fieldType: fieldType, - enclosingTypeDefinition: f.EnclosingTypeDefinition, - fieldTypeDefinitionNode: fieldDefinitionTypeNode, - }) -} - -func (f *fieldSelectionMergingVisitor) potentiallySameObject(left, right ast.Node) bool { - switch { - case left.Kind == ast.NodeKindInterfaceTypeDefinition || right.Kind == ast.NodeKindInterfaceTypeDefinition: - return true - case left.Kind == ast.NodeKindObjectTypeDefinition && right.Kind == ast.NodeKindObjectTypeDefinition: - return bytes.Equal(f.definition.ObjectTypeDefinitionNameBytes(left.Ref), f.definition.ObjectTypeDefinitionNameBytes(right.Ref)) - default: - return false - } -} - -func (f *fieldSelectionMergingVisitor) EnterSelectionSet(ref int) { - -} diff --git a/pkg/astvalidation/operation_rule_fragments.go b/pkg/astvalidation/operation_rule_fragments.go deleted file mode 100644 index f249199c6..000000000 --- a/pkg/astvalidation/operation_rule_fragments.go +++ /dev/null @@ -1,127 +0,0 @@ -package astvalidation - -import ( - "bytes" - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// Fragments validates if the use of fragments in a given document is correct -func Fragments() Rule { - return func(walker *astvisitor.Walker) { - visitor := fragmentsVisitor{ - Walker: walker, - fragmentDefinitionsVisited: make([]ast.ByteSlice, 0, 8), - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterLeaveDocumentVisitor(&visitor) - walker.RegisterEnterFragmentDefinitionVisitor(&visitor) - walker.RegisterEnterInlineFragmentVisitor(&visitor) - walker.RegisterEnterFragmentSpreadVisitor(&visitor) - } -} - -type fragmentsVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - fragmentDefinitionsVisited []ast.ByteSlice -} - -func (f *fragmentsVisitor) EnterFragmentSpread(ref int) { - fragmentName := f.operation.FragmentSpreadNameBytes(ref) - fragmentDefinitionRef, exists := f.operation.FragmentDefinitionRef(fragmentName) - if !exists { - f.StopWithExternalErr(operationreport.ErrFragmentUndefined(fragmentName)) - return - } - fragmentTypeName := f.operation.FragmentDefinitionTypeName(fragmentDefinitionRef) - enclosingTypeName := f.EnclosingTypeDefinition.NameBytes(f.definition) - if !bytes.Equal(fragmentTypeName, enclosingTypeName) { - f.StopWithExternalErr(operationreport.ErrInvalidFragmentSpread(fragmentName, fragmentTypeName, enclosingTypeName)) - return - } - if f.Ancestors[0].Kind == ast.NodeKindOperationDefinition { - f.StopWithExternalErr(operationreport.ErrFragmentSpreadFormsCycle(fragmentName)) - } -} - -func (f *fragmentsVisitor) LeaveDocument(_, _ *ast.Document) { - for i := range f.fragmentDefinitionsVisited { - if !f.operation.FragmentDefinitionIsUsed(f.fragmentDefinitionsVisited[i]) { - fragmentName := f.fragmentDefinitionsVisited[i] - f.StopWithExternalErr(operationreport.ErrFragmentDefinedButNotUsed(fragmentName)) - return - } - } -} - -func (f *fragmentsVisitor) fragmentOnNodeIsAllowed(node ast.Node) bool { - switch node.Kind { - case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition, ast.NodeKindUnionTypeDefinition: - return true - default: - return false - } -} - -func (f *fragmentsVisitor) EnterInlineFragment(ref int) { - - if !f.operation.InlineFragmentHasTypeCondition(ref) { - return - } - - typeName := f.operation.InlineFragmentTypeConditionName(ref) - - node, exists := f.definition.Index.FirstNonExtensionNodeByNameBytes(typeName) - if !exists { - typePosition := f.operation.Types[f.operation.InlineFragments[ref].TypeCondition.Type].Position - f.Report.AddExternalError(operationreport.ErrUnknownType(typeName, typePosition)) - f.SkipNode() // skipping node cause otherwise visitor will not be able to get enclosing type and will stop with error but error is already added here - return - } - - if !f.fragmentOnNodeIsAllowed(node) { - f.StopWithExternalErr(operationreport.ErrInlineFragmentOnTypeDisallowed(typeName)) - return - } - - if !f.definition.NodeFragmentIsAllowedOnNode(node, f.EnclosingTypeDefinition) { - enclosingTypeName := f.definition.NodeNameBytes(f.EnclosingTypeDefinition) - f.StopWithExternalErr(operationreport.ErrInlineFragmentOnTypeMismatchEnclosingType(typeName, enclosingTypeName)) - return - } -} - -func (f *fragmentsVisitor) EnterDocument(operation, definition *ast.Document) { - f.operation = operation - f.definition = definition - f.fragmentDefinitionsVisited = f.fragmentDefinitionsVisited[:0] -} - -func (f *fragmentsVisitor) EnterFragmentDefinition(ref int) { - - fragmentDefinitionName := f.operation.FragmentDefinitionNameBytes(ref) - typeName := f.operation.FragmentDefinitionTypeName(ref) - - node, exists := f.definition.Index.FirstNodeByNameBytes(typeName) - if !exists { - typePosition := f.operation.Types[f.operation.FragmentDefinitions[ref].TypeCondition.Type].Position - f.StopWithExternalErr(operationreport.ErrUnknownType(typeName, typePosition)) - return - } - - if !f.fragmentOnNodeIsAllowed(node) { - f.StopWithExternalErr(operationreport.ErrFragmentDefinitionOnTypeDisallowed(fragmentDefinitionName, typeName)) - return - } - - for i := range f.fragmentDefinitionsVisited { - if bytes.Equal(fragmentDefinitionName, f.fragmentDefinitionsVisited[i]) { - f.StopWithExternalErr(operationreport.ErrFragmentDefinitionMustBeUnique(fragmentDefinitionName)) - return - } - } - - f.fragmentDefinitionsVisited = append(f.fragmentDefinitionsVisited, fragmentDefinitionName) -} diff --git a/pkg/astvalidation/operation_rule_known_arguments.go b/pkg/astvalidation/operation_rule_known_arguments.go deleted file mode 100644 index c80fce90a..000000000 --- a/pkg/astvalidation/operation_rule_known_arguments.go +++ /dev/null @@ -1,62 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// KnownArguments validates if all arguments are known -func KnownArguments() Rule { - return func(walker *astvisitor.Walker) { - visitor := knownArgumentsVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - walker.RegisterEnterFieldVisitor(&visitor) - } -} - -type knownArgumentsVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - enclosingNode ast.Node -} - -func (v *knownArgumentsVisitor) EnterField(ref int) { - _, exists := v.FieldDefinition(ref) - if !exists { - v.SkipNode() // ignore arguments of not existing fields - return - } - - v.enclosingNode = v.EnclosingTypeDefinition -} - -func (v *knownArgumentsVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation = operation - v.definition = definition -} - -func (v *knownArgumentsVisitor) EnterArgument(ref int) { - _, exists := v.ArgumentInputValueDefinition(ref) - if exists { - return - } - - ancestor := v.Ancestor() - ancestorName := v.AncestorNameBytes() - - argumentName := v.operation.ArgumentNameBytes(ref) - argumentPosition := v.operation.Arguments[ref].Position - - switch ancestor.Kind { - case ast.NodeKindField: - objectTypeDefName := v.definition.ObjectTypeDefinitionNameBytes(v.enclosingNode.Ref) - - v.Report.AddExternalError(operationreport.ErrArgumentNotDefinedOnField(argumentName, objectTypeDefName, ancestorName, argumentPosition)) - case ast.NodeKindDirective: - v.Report.AddExternalError(operationreport.ErrArgumentNotDefinedOnDirective(argumentName, ancestorName, argumentPosition)) - } -} diff --git a/pkg/astvalidation/operation_rule_lone_anonymous_operation.go b/pkg/astvalidation/operation_rule_lone_anonymous_operation.go deleted file mode 100644 index f9b0a0fe5..000000000 --- a/pkg/astvalidation/operation_rule_lone_anonymous_operation.go +++ /dev/null @@ -1,31 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// LoneAnonymousOperation validates if anonymous operations are alone in a given document. -func LoneAnonymousOperation() Rule { - return func(walker *astvisitor.Walker) { - walker.RegisterEnterDocumentVisitor(&loneAnonymousOperationVisitor{walker}) - } -} - -type loneAnonymousOperationVisitor struct { - *astvisitor.Walker -} - -func (l *loneAnonymousOperationVisitor) EnterDocument(operation, definition *ast.Document) { - if len(operation.OperationDefinitions) <= 1 { - return - } - - for i := range operation.OperationDefinitions { - if operation.OperationDefinitions[i].Name.Length() == 0 { - l.StopWithExternalErr(operationreport.ErrAnonymousOperationMustBeTheOnlyOperationInDocument()) - return - } - } -} diff --git a/pkg/astvalidation/operation_rule_operation_name_uniqueness.go b/pkg/astvalidation/operation_rule_operation_name_uniqueness.go deleted file mode 100644 index 2e22e59a4..000000000 --- a/pkg/astvalidation/operation_rule_operation_name_uniqueness.go +++ /dev/null @@ -1,41 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// OperationNameUniqueness validates if all operation names are unique -func OperationNameUniqueness() Rule { - return func(walker *astvisitor.Walker) { - walker.RegisterEnterDocumentVisitor(&operationNameUniquenessVisitor{walker}) - } -} - -type operationNameUniquenessVisitor struct { - *astvisitor.Walker -} - -func (o *operationNameUniquenessVisitor) EnterDocument(operation, definition *ast.Document) { - if len(operation.OperationDefinitions) <= 1 { - return - } - - for i := range operation.OperationDefinitions { - for k := range operation.OperationDefinitions { - if i == k || i > k { - continue - } - - left := operation.OperationDefinitions[i].Name - right := operation.OperationDefinitions[k].Name - - if ast.ByteSliceEquals(left, operation.Input, right, operation.Input) { - operationName := operation.Input.ByteSlice(operation.OperationDefinitions[i].Name) - o.StopWithExternalErr(operationreport.ErrOperationNameMustBeUnique(operationName)) - return - } - } - } -} diff --git a/pkg/astvalidation/operation_rule_required_arguments.go b/pkg/astvalidation/operation_rule_required_arguments.go deleted file mode 100644 index 3edd4c7bb..000000000 --- a/pkg/astvalidation/operation_rule_required_arguments.go +++ /dev/null @@ -1,53 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// RequiredArguments validates if all required arguments are present -func RequiredArguments() Rule { - return func(walker *astvisitor.Walker) { - visitor := requiredArgumentsVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterFieldVisitor(&visitor) - } -} - -type requiredArgumentsVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (r *requiredArgumentsVisitor) EnterDocument(operation, definition *ast.Document) { - r.operation = operation - r.definition = definition -} - -func (r *requiredArgumentsVisitor) EnterField(ref int) { - - fieldName := r.operation.FieldNameBytes(ref) - inputValueDefinitions := r.definition.NodeFieldDefinitionArgumentsDefinitions(r.EnclosingTypeDefinition, fieldName) - - for _, i := range inputValueDefinitions { - if r.definition.InputValueDefinitionArgumentIsOptional(i) { - continue - } - - name := r.definition.InputValueDefinitionNameBytes(i) - - argument, exists := r.operation.FieldArgument(ref, name) - if !exists { - r.StopWithExternalErr(operationreport.ErrArgumentRequiredOnField(name, fieldName)) - return - } - - if r.operation.ArgumentValue(argument).Kind == ast.ValueKindNull { - r.StopWithExternalErr(operationreport.ErrArgumentOnFieldMustNotBeNull(name, fieldName)) - return - } - } -} diff --git a/pkg/astvalidation/operation_rule_subscription_single_root_field.go b/pkg/astvalidation/operation_rule_subscription_single_root_field.go deleted file mode 100644 index 3ad4ba875..000000000 --- a/pkg/astvalidation/operation_rule_subscription_single_root_field.go +++ /dev/null @@ -1,37 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// SubscriptionSingleRootField validates if subscriptions have a single root field -func SubscriptionSingleRootField() Rule { - return func(walker *astvisitor.Walker) { - visitor := subscriptionSingleRootFieldVisitor{walker} - walker.RegisterEnterDocumentVisitor(&visitor) - } -} - -type subscriptionSingleRootFieldVisitor struct { - *astvisitor.Walker -} - -func (s *subscriptionSingleRootFieldVisitor) EnterDocument(operation, definition *ast.Document) { - for i := range operation.OperationDefinitions { - if operation.OperationDefinitions[i].OperationType == ast.OperationTypeSubscription { - selections := len(operation.SelectionSets[operation.OperationDefinitions[i].SelectionSet].SelectionRefs) - if selections > 1 { - subscriptionName := operation.Input.ByteSlice(operation.OperationDefinitions[i].Name) - s.StopWithExternalErr(operationreport.ErrSubscriptionMustOnlyHaveOneRootSelection(subscriptionName)) - return - } else if selections == 1 { - ref := operation.SelectionSets[operation.OperationDefinitions[i].SelectionSet].SelectionRefs[0] - if operation.Selections[ref].Kind == ast.SelectionKindField { - return - } - } - } - } -} diff --git a/pkg/astvalidation/operation_rule_valid_arguments.go b/pkg/astvalidation/operation_rule_valid_arguments.go deleted file mode 100644 index f35226026..000000000 --- a/pkg/astvalidation/operation_rule_valid_arguments.go +++ /dev/null @@ -1,184 +0,0 @@ -package astvalidation - -import ( - "bytes" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// ValidArguments validates if arguments are valid: values and variables has compatible types -// deep variables comparison is handled by Values -func ValidArguments() Rule { - return func(walker *astvisitor.Walker) { - visitor := validArgumentsVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - } -} - -type validArgumentsVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (v *validArgumentsVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation = operation - v.definition = definition -} - -func (v *validArgumentsVisitor) EnterArgument(ref int) { - definitionRef, exists := v.ArgumentInputValueDefinition(ref) - - if !exists { - return - } - - value := v.operation.ArgumentValue(ref) - v.validateIfValueSatisfiesInputFieldDefinition(value, definitionRef) -} - -func (v *validArgumentsVisitor) validateIfValueSatisfiesInputFieldDefinition(value ast.Value, inputValueDefinitionRef int) { - var ( - satisfied bool - operationTypeRef int - variableDefinitionRef int - ) - - switch value.Kind { - case ast.ValueKindVariable: - satisfied, operationTypeRef, variableDefinitionRef = v.variableValueSatisfiesInputValueDefinition(value.Ref, inputValueDefinitionRef) - case ast.ValueKindEnum, - ast.ValueKindNull, - ast.ValueKindBoolean, - ast.ValueKindInteger, - ast.ValueKindString, - ast.ValueKindFloat, - ast.ValueKindObject, - ast.ValueKindList: - // this types of values are covered by Values() / valuesVisitor - return - default: - v.StopWithInternalErr(fmt.Errorf("validateIfValueSatisfiesInputFieldDefinition: not implemented for value.Kind: %s", value.Kind)) - return - } - - if satisfied { - return - } - - if operationTypeRef == ast.InvalidRef { - // variable is not defined on operation - return - } - - printedValue, err := v.operation.PrintValueBytes(value, nil) - if v.HandleInternalErr(err) { - return - } - - typeRef := v.definition.InputValueDefinitionType(inputValueDefinitionRef) - expectedTypeName, err := v.definition.PrintTypeBytes(typeRef, nil) - if v.HandleInternalErr(err) { - return - } - - actualTypeName, err := v.operation.PrintTypeBytes(operationTypeRef, nil) - if v.HandleInternalErr(err) { - return - } - - v.StopWithExternalErr(operationreport.ErrVariableTypeDoesntSatisfyInputValueDefinition(printedValue, actualTypeName, expectedTypeName, value.Position, v.operation.VariableDefinitions[variableDefinitionRef].VariableValue.Position)) -} - -func (v *validArgumentsVisitor) variableValueSatisfiesInputValueDefinition(variableValue, inputValueDefinition int) (satisfies bool, operationTypeRef int, variableDefRef int) { - variableDefinitionRef, exists := v.variableDefinition(variableValue) - if !exists { - return false, ast.InvalidRef, variableDefinitionRef - } - - operationTypeRef = v.operation.VariableDefinitions[variableDefinitionRef].Type - definitionTypeRef := v.definition.InputValueDefinitions[inputValueDefinition].Type - - hasDefaultValue := v.validDefaultValue(v.operation.VariableDefinitions[variableDefinitionRef].DefaultValue) || - v.validDefaultValue(v.definition.InputValueDefinitions[inputValueDefinition].DefaultValue) - - return v.operationTypeSatisfiesDefinitionType(operationTypeRef, definitionTypeRef, hasDefaultValue), operationTypeRef, variableDefinitionRef -} - -func (v *validArgumentsVisitor) variableDefinition(variableValueRef int) (ref int, exists bool) { - variableName := v.operation.VariableValueNameBytes(variableValueRef) - - if v.Ancestors[0].Kind == ast.NodeKindOperationDefinition { - return v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName) - } - - for opDefRef := 0; opDefRef < len(v.operation.OperationDefinitions); opDefRef++ { - ref, exists = v.operation.VariableDefinitionByNameAndOperation(opDefRef, variableName) - if exists { - return - } - } - - return ast.InvalidRef, false -} - -func (v *validArgumentsVisitor) validDefaultValue(value ast.DefaultValue) bool { - return value.IsDefined && value.Value.Kind != ast.ValueKindNull -} - -func (v *validArgumentsVisitor) operationTypeSatisfiesDefinitionType(operationTypeRef int, definitionTypeRef int, hasDefaultValue bool) bool { - opKind := v.operation.Types[operationTypeRef].TypeKind - defKind := v.definition.Types[definitionTypeRef].TypeKind - - // A nullable op type is compatible with a non-null def type if the def has - // a default value. Strip the def non-null and continue comparing. This - // logic is only valid before any unnesting of types occurs, which is why - // it's outside the for loop below. - // - // Example: - // Op: someField(arg: Boolean): String - // Def: someField(arg: Boolean! = false): String # Boolean! -> Boolean - if opKind != ast.TypeKindNonNull && defKind == ast.TypeKindNonNull && hasDefaultValue { - definitionTypeRef = v.definition.Types[definitionTypeRef].OfType - } - - // Unnest the op and def arg types until a named type is reached, - // then compare. - for { - if operationTypeRef == -1 || definitionTypeRef == -1 { - return false - } - opKind = v.operation.Types[operationTypeRef].TypeKind - defKind = v.definition.Types[definitionTypeRef].TypeKind - - // If the op arg type is stricter than the def arg type, that's okay. - // Strip the op non-null and continue comparing. - // - // Example: - // Op: someField(arg: Boolean!): String # Boolean! -> Boolean - // Def: someField(arg: Boolean): String - if opKind == ast.TypeKindNonNull && defKind != ast.TypeKindNonNull { - operationTypeRef = v.operation.Types[operationTypeRef].OfType - continue - } - - if opKind != defKind { - return false - } - if opKind == ast.TypeKindNamed { - // defKind is also a named type because at this point both kinds - // are the same! Compare the names. - - return bytes.Equal(v.operation.Input.ByteSlice(v.operation.Types[operationTypeRef].Name), - v.definition.Input.ByteSlice(v.definition.Types[definitionTypeRef].Name)) - } - // Both types are non-null or list. Unnest and continue comparing. - operationTypeRef = v.operation.Types[operationTypeRef].OfType - definitionTypeRef = v.definition.Types[definitionTypeRef].OfType - } -} diff --git a/pkg/astvalidation/operation_rule_validate_field_selections.go b/pkg/astvalidation/operation_rule_validate_field_selections.go deleted file mode 100644 index b8afa6172..000000000 --- a/pkg/astvalidation/operation_rule_validate_field_selections.go +++ /dev/null @@ -1,89 +0,0 @@ -package astvalidation - -import ( - "bytes" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// FieldSelections validates if all FieldSelections are possible and valid -func FieldSelections() Rule { - return func(walker *astvisitor.Walker) { - fieldDefined := fieldDefined{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&fieldDefined) - walker.RegisterEnterFieldVisitor(&fieldDefined) - } -} - -type fieldDefined struct { - *astvisitor.Walker - operation *ast.Document - definition *ast.Document -} - -func (f *fieldDefined) EnterDocument(operation, definition *ast.Document) { - f.operation = operation - f.definition = definition -} - -func (f *fieldDefined) ValidateUnionField(ref int, enclosingTypeDefinition ast.Node) { - if bytes.Equal(f.operation.FieldNameBytes(ref), literal.TYPENAME) { - return - } - fieldName := f.operation.FieldNameBytes(ref) - unionName := f.definition.NodeNameBytes(enclosingTypeDefinition) - f.StopWithExternalErr(operationreport.ErrFieldSelectionOnUnion(fieldName, unionName)) -} - -func (f *fieldDefined) ValidateInterfaceObjectTypeField(ref int, enclosingTypeDefinition ast.Node) { - fieldName := f.operation.FieldNameBytes(ref) - if bytes.Equal(fieldName, literal.TYPENAME) { - return - } - typeName := f.definition.NodeNameBytes(enclosingTypeDefinition) - hasSelections := f.operation.FieldHasSelections(ref) - definitions := f.definition.NodeFieldDefinitions(enclosingTypeDefinition) - for _, i := range definitions { - definitionName := f.definition.FieldDefinitionNameBytes(i) - if bytes.Equal(fieldName, definitionName) { - // field is defined - fieldDefinitionTypeKind := f.definition.FieldDefinitionTypeNode(i).Kind - switch { - case hasSelections && fieldDefinitionTypeKind == ast.NodeKindScalarTypeDefinition: - f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, definitionName)) - case !hasSelections && (fieldDefinitionTypeKind != ast.NodeKindScalarTypeDefinition && fieldDefinitionTypeKind != ast.NodeKindEnumTypeDefinition): - f.StopWithExternalErr(operationreport.ErrMissingFieldSelectionOnNonScalar(fieldName, typeName)) - } - return - } - } - - f.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName)) -} - -func (f *fieldDefined) ValidateScalarField(ref int, enclosingTypeDefinition ast.Node) { - fieldName := f.operation.FieldNameBytes(ref) - scalarTypeName := f.operation.NodeNameBytes(enclosingTypeDefinition) - f.StopWithExternalErr(operationreport.ErrFieldSelectionOnScalar(fieldName, scalarTypeName)) -} - -func (f *fieldDefined) EnterField(ref int) { - switch f.EnclosingTypeDefinition.Kind { - case ast.NodeKindUnionTypeDefinition: - f.ValidateUnionField(ref, f.EnclosingTypeDefinition) - case ast.NodeKindInterfaceTypeDefinition, ast.NodeKindObjectTypeDefinition: - f.ValidateInterfaceObjectTypeField(ref, f.EnclosingTypeDefinition) - case ast.NodeKindScalarTypeDefinition: - f.ValidateScalarField(ref, f.EnclosingTypeDefinition) - default: - fieldName := f.operation.FieldNameBytes(ref) - typeName := f.operation.NodeNameBytes(f.EnclosingTypeDefinition) - f.StopWithInternalErr(fmt.Errorf("astvalidation/fieldDefined/EnterField: field: %s selection on type: %s unhandled", fieldName, typeName)) - } -} diff --git a/pkg/astvalidation/operation_rule_values.go b/pkg/astvalidation/operation_rule_values.go deleted file mode 100644 index 02db7a06a..000000000 --- a/pkg/astvalidation/operation_rule_values.go +++ /dev/null @@ -1,714 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astimport" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// Values validates if values are used properly -func Values() Rule { - return func(walker *astvisitor.Walker) { - visitor := valuesVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - walker.RegisterEnterVariableDefinitionVisitor(&visitor) - } -} - -type valuesVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - importer astimport.Importer -} - -func (v *valuesVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation = operation - v.definition = definition -} - -func (v *valuesVisitor) EnterVariableDefinition(ref int) { - if !v.operation.VariableDefinitionHasDefaultValue(ref) { - return // variable has no default value, deep type check not required - } - - v.valueSatisfiesOperationType(v.operation.VariableDefinitions[ref].DefaultValue.Value, v.operation.VariableDefinitions[ref].Type) -} - -func (v *valuesVisitor) EnterArgument(ref int) { - - definition, exists := v.ArgumentInputValueDefinition(ref) - if !exists { - return - } - - value := v.operation.ArgumentValue(ref) - if value.Kind == ast.ValueKindVariable { - variableName := v.operation.VariableValueNameBytes(value.Ref) - variableDefinition, exists := v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName) - if !exists { - operationName := v.operation.OperationDefinitionNameBytes(v.Ancestors[0].Ref) - v.StopWithExternalErr(operationreport.ErrVariableNotDefinedOnOperation(variableName, operationName)) - return - } - if !v.operation.VariableDefinitions[variableDefinition].DefaultValue.IsDefined { - return // variable has no default value, deep type check not required - } - value = v.operation.VariableDefinitions[variableDefinition].DefaultValue.Value - } - - v.valueSatisfiesInputValueDefinitionType(value, v.definition.InputValueDefinitions[definition].Type) -} - -func (v *valuesVisitor) valueSatisfiesOperationType(value ast.Value, operationTypeRef int) bool { - switch v.operation.Types[operationTypeRef].TypeKind { - case ast.TypeKindNonNull: - return v.valuesSatisfiesOperationNonNullType(value, operationTypeRef) - case ast.TypeKindNamed: - return v.valuesSatisfiesOperationNamedType(value, operationTypeRef) - case ast.TypeKindList: - return v.valueSatisfiesOperationListType(value, operationTypeRef, v.operation.Types[operationTypeRef].OfType) - default: - v.handleOperationTypeError(value, operationTypeRef) - return false - } -} - -func (v *valuesVisitor) valuesSatisfiesOperationNonNullType(value ast.Value, operationTypeRef int) bool { - if value.Kind == ast.ValueKindNull { - v.handleOperationUnexpectedNullError(value, operationTypeRef) - return false - } - return v.valueSatisfiesOperationType(value, v.operation.Types[operationTypeRef].OfType) -} - -func (v *valuesVisitor) valuesSatisfiesOperationNamedType(value ast.Value, operationTypeRef int) bool { - if value.Kind == ast.ValueKindNull { - // null always satisfies not required type - return true - } - - typeName := v.operation.ResolveTypeNameBytes(operationTypeRef) - node, exists := v.definition.Index.FirstNodeByNameBytes(typeName) - if !exists { - v.handleOperationTypeError(value, operationTypeRef) - return false - } - - definitionTypeRef := ast.InvalidRef - - for ref := 0; ref < len(v.definition.Types); ref++ { - if v.definition.Types[ref].TypeKind != ast.TypeKindNamed { - continue - } - - if bytes.Equal(v.definition.TypeNameBytes(ref), typeName) { - definitionTypeRef = ref - break - } - } - - if definitionTypeRef == ast.InvalidRef { - // should not happen, as in case we have not found named type node we will report it earlier - return false - } - - return v.valueSatisfiesTypeDefinitionNode(value, definitionTypeRef, node) -} - -func (v *valuesVisitor) valueSatisfiesOperationListType(value ast.Value, operationTypeRef int, listItemType int) bool { - if value.Kind == ast.ValueKindNull { - return true - } - - if value.Kind != ast.ValueKindList { - return v.valueSatisfiesOperationType(value, listItemType) - } - - if v.operation.Types[listItemType].TypeKind == ast.TypeKindNonNull { - if len(v.operation.ListValues[value.Ref].Refs) == 0 { - v.handleOperationTypeError(value, operationTypeRef) - return false - } - listItemType = v.operation.Types[listItemType].OfType - } - - valid := true - - for _, i := range v.operation.ListValues[value.Ref].Refs { - listValue := v.operation.Value(i) - if !v.valueSatisfiesOperationType(listValue, listItemType) { - valid = false - } - } - - return valid -} - -func (v *valuesVisitor) valueSatisfiesInputValueDefinitionType(value ast.Value, definitionTypeRef int) bool { - switch v.definition.Types[definitionTypeRef].TypeKind { - case ast.TypeKindNonNull: - return v.valuesSatisfiesNonNullType(value, definitionTypeRef) - case ast.TypeKindNamed: - return v.valuesSatisfiesNamedType(value, definitionTypeRef) - case ast.TypeKindList: - return v.valueSatisfiesListType(value, definitionTypeRef, v.definition.Types[definitionTypeRef].OfType) - default: - v.handleTypeError(value, definitionTypeRef) - return false - } -} - -func (v *valuesVisitor) valuesSatisfiesNonNullType(value ast.Value, definitionTypeRef int) bool { - switch value.Kind { - case ast.ValueKindNull: - v.handleUnexpectedNullError(value, definitionTypeRef) - return false - case ast.ValueKindVariable: - variableDefinitionRef, variableTypeRef, _, ok := v.operationVariableType(value.Ref) - if !ok { - v.handleTypeError(value, definitionTypeRef) - return false - } - - if v.operation.VariableDefinitionHasDefaultValue(variableDefinitionRef) { - return v.valueSatisfiesInputValueDefinitionType(v.operation.VariableDefinitions[variableDefinitionRef].DefaultValue.Value, definitionTypeRef) - } - - importedDefinitionType := v.importer.ImportType(definitionTypeRef, v.definition, v.operation) - if !v.operation.TypesAreEqualDeep(importedDefinitionType, variableTypeRef) { - v.handleVariableHasIncompatibleTypeError(value, definitionTypeRef) - return false - } - return true - } - return v.valueSatisfiesInputValueDefinitionType(value, v.definition.Types[definitionTypeRef].OfType) -} - -func (v *valuesVisitor) valuesSatisfiesNamedType(value ast.Value, definitionTypeRef int) bool { - if value.Kind == ast.ValueKindNull { - // null always satisfies not required type - return true - } - - typeName := v.definition.ResolveTypeNameBytes(definitionTypeRef) - node, exists := v.definition.Index.FirstNodeByNameBytes(typeName) - if !exists { - v.handleTypeError(value, definitionTypeRef) - return false - } - - return v.valueSatisfiesTypeDefinitionNode(value, definitionTypeRef, node) -} - -func (v *valuesVisitor) valueSatisfiesListType(value ast.Value, definitionTypeRef int, listItemType int) bool { - - if value.Kind == ast.ValueKindVariable { - variableDefinitionRef, actualType, _, ok := v.operationVariableType(value.Ref) - if !ok { - v.handleTypeError(value, definitionTypeRef) - return false - } - - if v.operation.VariableDefinitionHasDefaultValue(variableDefinitionRef) { - return v.valueSatisfiesInputValueDefinitionType(v.operation.VariableDefinitions[variableDefinitionRef].DefaultValue.Value, definitionTypeRef) - } - - expectedType := v.importer.ImportType(listItemType, v.definition, v.operation) - if v.operation.Types[actualType].TypeKind == ast.TypeKindNonNull { - actualType = v.operation.Types[actualType].OfType - } - if v.operation.Types[actualType].TypeKind == ast.TypeKindList { - actualType = v.operation.Types[actualType].OfType - } - if !v.operation.TypesAreEqualDeep(expectedType, actualType) { - v.handleVariableHasIncompatibleTypeError(value, definitionTypeRef) - return false - } - return true - } - - if value.Kind == ast.ValueKindNull { - return true - } - - if value.Kind != ast.ValueKindList { - return v.valueSatisfiesInputValueDefinitionType(value, listItemType) - } - - if v.definition.Types[listItemType].TypeKind == ast.TypeKindNonNull { - if len(v.operation.ListValues[value.Ref].Refs) == 0 { - // [] empty list is a valid input for [item!] lists - return true - } - listItemType = v.definition.Types[listItemType].OfType - } - - valid := true - - for _, i := range v.operation.ListValues[value.Ref].Refs { - listValue := v.operation.Value(i) - if !v.valueSatisfiesInputValueDefinitionType(listValue, listItemType) { - valid = false - } - } - - return valid -} - -func (v *valuesVisitor) valueSatisfiesTypeDefinitionNode(value ast.Value, definitionTypeRef int, node ast.Node) bool { - switch node.Kind { - case ast.NodeKindEnumTypeDefinition: - return v.valueSatisfiesEnum(value, definitionTypeRef, node) - case ast.NodeKindScalarTypeDefinition: - return v.valueSatisfiesScalar(value, definitionTypeRef, node.Ref) - case ast.NodeKindInputObjectTypeDefinition: - return v.valueSatisfiesInputObjectTypeDefinition(value, definitionTypeRef, node.Ref) - } - return false -} - -func (v *valuesVisitor) valueSatisfiesEnum(value ast.Value, definitionTypeRef int, node ast.Node) bool { - if value.Kind == ast.ValueKindVariable { - expectedTypeName := node.NameBytes(v.definition) - return v.variableValueHasMatchingTypeName(value, definitionTypeRef, expectedTypeName) - } - - if value.Kind != ast.ValueKindEnum { - v.handleUnexpectedEnumValueError(value, definitionTypeRef) - return false - } - enumValue := v.operation.EnumValueNameBytes(value.Ref) - - if !v.definition.EnumTypeDefinitionContainsEnumValue(node.Ref, enumValue) { - v.handleNotExistingEnumValueError(value, definitionTypeRef) - return false - } - - return true -} - -func (v *valuesVisitor) valueSatisfiesScalar(value ast.Value, definitionTypeRef int, scalar int) bool { - scalarName := v.definition.ScalarTypeDefinitionNameBytes(scalar) - - if value.Kind == ast.ValueKindVariable { - return v.variableValueHasMatchingTypeName(value, definitionTypeRef, scalarName) - } - - switch { - case bytes.Equal(scalarName, literal.ID): - return v.valueSatisfiesScalarID(value, definitionTypeRef) - case bytes.Equal(scalarName, literal.BOOLEAN): - return v.valueSatisfiesScalarBoolean(value, definitionTypeRef) - case bytes.Equal(scalarName, literal.INT): - return v.valueSatisfiesScalarInt(value, definitionTypeRef) - case bytes.Equal(scalarName, literal.FLOAT): - return v.valueSatisfiesScalarFloat(value, definitionTypeRef) - case bytes.Equal(scalarName, literal.STRING): - return v.valueSatisfiesScalarString(value, definitionTypeRef) - default: - // custom scalar values could be of any kind - return true - } -} - -func (v *valuesVisitor) valueSatisfiesScalarID(value ast.Value, definitionTypeRef int) bool { - if value.Kind == ast.ValueKindString || value.Kind == ast.ValueKindInteger { - return true - } - - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return false - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyID(printedValue, printedType, value.Position)) - - return false -} - -func (v *valuesVisitor) valueSatisfiesScalarBoolean(value ast.Value, definitionTypeRef int) bool { - if value.Kind == ast.ValueKindBoolean { - return true - } - - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return false - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyBoolean(printedValue, printedType, value.Position)) - - return false -} - -func (v *valuesVisitor) valueSatisfiesScalarInt(value ast.Value, definitionTypeRef int) bool { - var isValidInt32 bool - isInt := value.Kind == ast.ValueKindInteger - - if isInt { - isValidInt32 = v.operation.IntValueValidInt32(value.Ref) - } - - if isInt && isValidInt32 { - return true - } - - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return false - } - - if !isInt { - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyInt(printedValue, printedType, value.Position)) - return false - } - - v.Report.AddExternalError(operationreport.ErrBigIntValueDoesntSatisfyInt(printedValue, printedType, value.Position)) - return false -} - -func (v *valuesVisitor) valueSatisfiesScalarFloat(value ast.Value, definitionTypeRef int) bool { - if value.Kind == ast.ValueKindFloat || value.Kind == ast.ValueKindInteger { - return true - } - - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return false - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyFloat(printedValue, printedType, value.Position)) - - return false -} - -func (v *valuesVisitor) valueSatisfiesScalarString(value ast.Value, definitionTypeRef int) bool { - if value.Kind == ast.ValueKindString { - return true - } - - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return false - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyString(printedValue, printedType, value.Position)) - - return false -} - -func (v *valuesVisitor) valueSatisfiesInputObjectTypeDefinition(value ast.Value, definitionTypeRef int, inputObjectTypeDefinition int) bool { - if value.Kind == ast.ValueKindVariable { - expectedTypeName := v.definition.InputObjectTypeDefinitionNameBytes(inputObjectTypeDefinition) - return v.variableValueHasMatchingTypeName(value, definitionTypeRef, expectedTypeName) - } - - if value.Kind != ast.ValueKindObject { - v.handleNotObjectTypeError(value, definitionTypeRef) - return false - } - - valid := true - - for _, i := range v.definition.InputObjectTypeDefinitions[inputObjectTypeDefinition].InputFieldsDefinition.Refs { - if !v.objectValueSatisfiesInputValueDefinition(value, inputObjectTypeDefinition, i) { - valid = false - } - } - - if !valid { - return false - } - - for _, i := range v.operation.ObjectValues[value.Ref].Refs { - if !v.objectFieldDefined(i, inputObjectTypeDefinition) { - objectFieldName := v.operation.ObjectFieldNameBytes(i) - def := v.definition.Input.ByteSlice(v.definition.InputObjectTypeDefinitions[inputObjectTypeDefinition].Name) - - v.Report.AddExternalError(operationreport.ErrUnknownFieldOfInputObject(objectFieldName, def, v.operation.ObjectField(i).Position)) - valid = false - } - } - - if !valid { - return false - } - - if v.objectValueHasDuplicateFields(value.Ref) { - return false - } - - return true -} - -func (v *valuesVisitor) objectValueHasDuplicateFields(objectValue int) bool { - hasDuplicates := false - - reportedFieldRefs := make(map[int]struct{}) - for i, j := range v.operation.ObjectValues[objectValue].Refs { - for k, l := range v.operation.ObjectValues[objectValue].Refs { - if i == k || i > k { - continue - } - - if _, ok := reportedFieldRefs[l]; ok { - continue - } - - fieldName := v.operation.ObjectFieldNameBytes(j) - otherFieldName := v.operation.ObjectFieldNameBytes(l) - - if bytes.Equal(fieldName, otherFieldName) { - v.Report.AddExternalError(operationreport.ErrDuplicatedFieldInputObject( - fieldName, - v.operation.ObjectField(j).Position, - v.operation.ObjectField(l).Position)) - hasDuplicates = true - reportedFieldRefs[l] = struct{}{} - } - } - } - - return hasDuplicates -} - -func (v *valuesVisitor) objectFieldDefined(objectField, inputObjectTypeDefinition int) bool { - name := v.operation.ObjectFieldNameBytes(objectField) - for _, i := range v.definition.InputObjectTypeDefinitions[inputObjectTypeDefinition].InputFieldsDefinition.Refs { - if bytes.Equal(name, v.definition.InputValueDefinitionNameBytes(i)) { - return true - } - } - return false -} - -func (v *valuesVisitor) objectValueSatisfiesInputValueDefinition(objectValue ast.Value, inputObjectDefinition, inputValueDefinition int) bool { - - name := v.definition.InputValueDefinitionNameBytes(inputValueDefinition) - definitionTypeRef := v.definition.InputValueDefinitionType(inputValueDefinition) - - for _, i := range v.operation.ObjectValues[objectValue.Ref].Refs { - if bytes.Equal(name, v.operation.ObjectFieldNameBytes(i)) { - value := v.operation.ObjectFieldValue(i) - return v.valueSatisfiesInputValueDefinitionType(value, definitionTypeRef) - } - } - - // argument is not present on object value, if arg is optional it's still ok, otherwise not satisfied - if !v.definition.InputValueDefinitionArgumentIsOptional(inputValueDefinition) { - v.handleMissingRequiredFieldOfInputObjectError(objectValue, name, inputObjectDefinition, inputValueDefinition) - return false - } - - return true -} - -func (v *valuesVisitor) variableValueHasMatchingTypeName(value ast.Value, definitionTypeRef int, expectedTypeName []byte) bool { - variableDefinitionRef, _, actualTypeName, ok := v.operationVariableType(value.Ref) - if !ok { - v.handleVariableHasIncompatibleTypeError(value, definitionTypeRef) - return false - } - - if v.operation.VariableDefinitionHasDefaultValue(variableDefinitionRef) { - return v.valueSatisfiesInputValueDefinitionType(v.operation.VariableDefinitions[variableDefinitionRef].DefaultValue.Value, definitionTypeRef) - } - - if !bytes.Equal(actualTypeName, expectedTypeName) { - v.handleVariableHasIncompatibleTypeError(value, definitionTypeRef) - return false - } - - return true -} - -func (v *valuesVisitor) handleTypeError(value ast.Value, definitionTypeRef int) { - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyType(printedValue, printedType, value.Position)) -} - -func (v *valuesVisitor) handleNotObjectTypeError(value ast.Value, definitionTypeRef int) { - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return - } - - v.Report.AddExternalError(operationreport.ErrValueIsNotAnInputObjectType(printedValue, printedType, value.Position)) -} - -func (v *valuesVisitor) handleUnexpectedNullError(value ast.Value, definitionTypeRef int) { - printedType, err := v.definition.PrintTypeBytes(definitionTypeRef, nil) - if v.HandleInternalErr(err) { - return - } - - v.Report.AddExternalError(operationreport.ErrNullValueDoesntSatisfyInputValueDefinition(printedType, value.Position)) -} - -func (v *valuesVisitor) handleUnexpectedEnumValueError(value ast.Value, definitionTypeRef int) { - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyEnum(printedValue, printedType, value.Position)) -} - -func (v *valuesVisitor) handleNotExistingEnumValueError(value ast.Value, definitionTypeRef int) { - printedValue, printedType, ok := v.printValueAndUnderlyingType(value, definitionTypeRef) - if !ok { - return - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntExistsInEnum(printedValue, printedType, value.Position)) -} - -func (v *valuesVisitor) handleVariableHasIncompatibleTypeError(value ast.Value, definitionTypeRef int) { - printedValue, ok := v.printOperationValue(value) - if !ok { - return - } - - expectedTypeName, err := v.definition.PrintTypeBytes(definitionTypeRef, nil) - if v.HandleInternalErr(err) { - return - } - - variableDefinitionRef, _, actualTypeName, ok := v.operationVariableType(value.Ref) - if !ok { - return - } - - v.Report.AddExternalError(operationreport.ErrVariableTypeDoesntSatisfyInputValueDefinition( - printedValue, - actualTypeName, - expectedTypeName, - value.Position, - v.operation.VariableDefinitions[variableDefinitionRef].VariableValue.Position, - )) -} - -func (v *valuesVisitor) handleMissingRequiredFieldOfInputObjectError(value ast.Value, fieldName ast.ByteSlice, inputObjectDefinition, inputValueDefinition int) { - printedType, err := v.definition.PrintTypeBytes(v.definition.InputValueDefinitions[inputValueDefinition].Type, nil) - if v.HandleInternalErr(err) { - return - } - - v.Report.AddExternalError(operationreport.ErrMissingRequiredFieldOfInputObject( - v.definition.InputObjectTypeDefinitionNameBytes(inputObjectDefinition), - fieldName, - printedType, - value.Position, - )) -} - -func (v *valuesVisitor) handleOperationTypeError(value ast.Value, operationTypeRef int) { - printedValue, printedType, ok := v.printOperationValueAndUnderlyingType(value, operationTypeRef) - if !ok { - return - } - - v.Report.AddExternalError(operationreport.ErrValueDoesntSatisfyType(printedValue, printedType, value.Position)) -} - -func (v *valuesVisitor) handleOperationUnexpectedNullError(value ast.Value, operationTypeRef int) { - printedType, err := v.operation.PrintTypeBytes(operationTypeRef, nil) - if v.HandleInternalErr(err) { - return - } - - v.Report.AddExternalError(operationreport.ErrNullValueDoesntSatisfyInputValueDefinition(printedType, value.Position)) -} - -func (v *valuesVisitor) printValueAndUnderlyingType(value ast.Value, definitionTypeRef int) (printedValue, printedType []byte, ok bool) { - var err error - - printedValue, ok = v.printOperationValue(value) - if !ok { - return nil, nil, false - } - - underlyingType := v.definition.ResolveUnderlyingType(definitionTypeRef) - printedType, err = v.definition.PrintTypeBytes(underlyingType, nil) - if v.HandleInternalErr(err) { - return nil, nil, false - } - - return printedValue, printedType, true -} - -func (v *valuesVisitor) printOperationValueAndUnderlyingType(value ast.Value, operationTypeRef int) (printedValue, printedType []byte, ok bool) { - printedValue, ok = v.printOperationValue(value) - if !ok { - return nil, nil, false - } - - printedType, ok = v.printUnderlyingOperationType(operationTypeRef) - if !ok { - return nil, nil, false - } - - return printedValue, printedType, true -} - -func (v *valuesVisitor) printUnderlyingOperationType(operationTypeRef int) (printedType []byte, ok bool) { - var err error - - underlyingType := v.operation.ResolveUnderlyingType(operationTypeRef) - printedType, err = v.operation.PrintTypeBytes(underlyingType, nil) - if v.HandleInternalErr(err) { - return nil, false - } - - return printedType, true -} - -func (v *valuesVisitor) printOperationValue(value ast.Value) (printedValue []byte, ok bool) { - var err error - printedValue, err = v.operation.PrintValueBytes(value, nil) - if v.HandleInternalErr(err) { - return nil, false - } - - return printedValue, true -} - -func (v *valuesVisitor) operationVariableDefinition(variableValueRef int) (ref int, exists bool) { - variableName := v.operation.VariableValueNameBytes(variableValueRef) - - if v.Ancestors[0].Kind == ast.NodeKindOperationDefinition { - return v.operation.VariableDefinitionByNameAndOperation(v.Ancestors[0].Ref, variableName) - } - - for opDefRef := 0; opDefRef < len(v.operation.OperationDefinitions); opDefRef++ { - ref, exists = v.operation.VariableDefinitionByNameAndOperation(opDefRef, variableName) - if exists { - return - } - } - - return ast.InvalidRef, false -} - -func (v *valuesVisitor) operationVariableType(variableValueRef int) (variableDefinitionRef int, variableTypeRef int, typeName ast.ByteSlice, ok bool) { - variableDefRef, exists := v.operationVariableDefinition(variableValueRef) - if !exists { - return ast.InvalidRef, ast.InvalidRef, nil, false - } - - variableTypeRef = v.operation.VariableDefinitions[variableDefRef].Type - typeName = v.operation.ResolveTypeNameBytes(variableTypeRef) - - return variableDefRef, variableTypeRef, typeName, true -} diff --git a/pkg/astvalidation/operation_rule_variable_uniqueness.go b/pkg/astvalidation/operation_rule_variable_uniqueness.go deleted file mode 100644 index b61ccb64f..000000000 --- a/pkg/astvalidation/operation_rule_variable_uniqueness.go +++ /dev/null @@ -1,57 +0,0 @@ -package astvalidation - -import ( - "bytes" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// VariableUniqueness validates if variables are unique in a given document -func VariableUniqueness() Rule { - return func(walker *astvisitor.Walker) { - visitor := variableUniquenessVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterVariableDefinitionVisitor(&visitor) - } -} - -type variableUniquenessVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (v *variableUniquenessVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation = operation - v.definition = definition -} - -func (v *variableUniquenessVisitor) EnterVariableDefinition(ref int) { - - name := v.operation.VariableDefinitionNameBytes(ref) - - if v.Ancestors[0].Kind != ast.NodeKindOperationDefinition { - return - } - - variableDefinitions := v.operation.OperationDefinitions[v.Ancestors[0].Ref].VariableDefinitions.Refs - - for _, i := range variableDefinitions { - if i == ref { - continue - } - if bytes.Equal(name, v.operation.VariableDefinitionNameBytes(i)) { - if v.Ancestors[0].Kind != ast.NodeKindOperationDefinition { - v.StopWithInternalErr(fmt.Errorf("variable definition must have Operation ObjectDefinition as root ancestor, got: %s", v.Ancestors[0].Kind)) - return - } - operationName := v.operation.Input.ByteSlice(v.operation.OperationDefinitions[v.Ancestors[0].Ref].Name) - v.StopWithExternalErr(operationreport.ErrVariableMustBeUnique(name, operationName)) - return - } - } -} diff --git a/pkg/astvalidation/operation_rule_variables_are_input_types.go b/pkg/astvalidation/operation_rule_variables_are_input_types.go deleted file mode 100644 index 6ef7372fa..000000000 --- a/pkg/astvalidation/operation_rule_variables_are_input_types.go +++ /dev/null @@ -1,54 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// VariablesAreInputTypes validates if variables are correct input types -func VariablesAreInputTypes() Rule { - return func(walker *astvisitor.Walker) { - visitor := variablesAreInputTypesVisitor{ - Walker: walker, - } - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterVariableDefinitionVisitor(&visitor) - } -} - -type variablesAreInputTypesVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document -} - -func (v *variablesAreInputTypesVisitor) EnterDocument(operation, definition *ast.Document) { - v.operation = operation - v.definition = definition -} - -func (v *variablesAreInputTypesVisitor) EnterVariableDefinition(ref int) { - - typeName := v.operation.ResolveTypeNameBytes(v.operation.VariableDefinitions[ref].Type) - typeDefinitionNode, ok := v.definition.Index.FirstNodeByNameBytes(typeName) - if !ok { - v.Report.AddExternalError(operationreport.ErrUnknownType(typeName, v.operation.Types[v.operation.VariableDefinitions[ref].Type].Position)) - return - } - - switch typeDefinitionNode.Kind { - case ast.NodeKindInputObjectTypeDefinition, ast.NodeKindScalarTypeDefinition, ast.NodeKindEnumTypeDefinition: - return - default: - variableName := v.operation.VariableDefinitionNameBytes(ref) - variableTypePos := v.operation.Types[v.operation.VariableDefinitions[ref].Type].Position - - printedType, err := v.operation.PrintTypeBytes(v.operation.VariableDefinitions[ref].Type, nil) - if v.HandleInternalErr(err) { - return - } - - v.Report.AddExternalError(operationreport.ErrVariableOfTypeIsNoValidInputValue(variableName, printedType, variableTypePos)) - return - } -} diff --git a/pkg/astvalidation/operation_validation.go b/pkg/astvalidation/operation_validation.go deleted file mode 100644 index 005712765..000000000 --- a/pkg/astvalidation/operation_validation.go +++ /dev/null @@ -1,75 +0,0 @@ -// Package astvalidation implements the validation rules specified in the GraphQL specification. -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// DefaultOperationValidator returns a fully initialized OperationValidator with all default rules registered -func DefaultOperationValidator() *OperationValidator { - - validator := OperationValidator{ - walker: astvisitor.NewWalker(48), - } - - validator.RegisterRule(AllVariablesUsed()) - validator.RegisterRule(AllVariableUsesDefined()) - validator.RegisterRule(DocumentContainsExecutableOperation()) - validator.RegisterRule(OperationNameUniqueness()) - validator.RegisterRule(LoneAnonymousOperation()) - validator.RegisterRule(SubscriptionSingleRootField()) - validator.RegisterRule(FieldSelections()) - validator.RegisterRule(FieldSelectionMerging()) - validator.RegisterRule(KnownArguments()) - validator.RegisterRule(ValidArguments()) - validator.RegisterRule(Values()) - validator.RegisterRule(ArgumentUniqueness()) - validator.RegisterRule(RequiredArguments()) - validator.RegisterRule(Fragments()) - validator.RegisterRule(DirectivesAreDefined()) - validator.RegisterRule(DirectivesAreInValidLocations()) - validator.RegisterRule(VariableUniqueness()) - validator.RegisterRule(DirectivesAreUniquePerLocation()) - validator.RegisterRule(VariablesAreInputTypes()) - - return &validator -} - -func NewOperationValidator(rules []Rule) *OperationValidator { - validator := OperationValidator{ - walker: astvisitor.NewWalker(48), - } - - for _, rule := range rules { - validator.RegisterRule(rule) - } - - return &validator -} - -// OperationValidator orchestrates the validation process of Operations -type OperationValidator struct { - walker astvisitor.Walker -} - -// RegisterRule registers a rule to the OperationValidator -func (o *OperationValidator) RegisterRule(rule Rule) { - rule(&o.walker) -} - -// Validate validates the operation against the definition using the registered ruleset. -func (o *OperationValidator) Validate(operation, definition *ast.Document, report *operationreport.Report) ValidationState { - - if report == nil { - report = &operationreport.Report{} - } - - o.walker.Walk(operation, definition, report) - - if report.HasErrors() { - return Invalid - } - return Valid -} diff --git a/pkg/astvalidation/operation_validation_test.go b/pkg/astvalidation/operation_validation_test.go deleted file mode 100644 index da21908a2..000000000 --- a/pkg/astvalidation/operation_validation_test.go +++ /dev/null @@ -1,11539 +0,0 @@ -package astvalidation - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type options struct { - disableNormalization bool - expectNormalizationError bool - expectValidationErrors bool - expectedValidationErrorMsgs []string -} - -type option func(options *options) - -// nolint -func withDisableNormalization() option { - return func(options *options) { - options.disableNormalization = true - } -} - -func withExpectNormalizationError() option { - return func(options *options) { - options.expectNormalizationError = true - } -} - -func withValidationErrors(errMsgs ...string) option { - return func(options *options) { - options.expectValidationErrors = true - options.expectedValidationErrorMsgs = errMsgs - } -} - -func TestExecutionValidation(t *testing.T) { - must := func(err error) { - if report, ok := err.(operationreport.Report); ok { - if report.HasErrors() { - t.Fatal(report.Error()) - } - return - } - if err != nil { - t.Fatal(err) - } - } - - mustDocument := func(doc ast.Document, report operationreport.Report) ast.Document { - if report.HasErrors() { - must(report) - } - return doc - } - - mustString := func(str string, err error) string { - must(err) - return str - } - - runWithDefinition := func(t *testing.T, definitionInput, operationInput string, rule Rule, expectation ValidationState, opts ...option) { - t.Helper() - - var options options - for _, opt := range opts { - opt(&options) - } - - definition := mustDocument(astparser.ParseGraphqlDocumentString(definitionInput)) - operation := mustDocument(astparser.ParseGraphqlDocumentString(operationInput)) - report := operationreport.Report{} - - if !options.disableNormalization { - astnormalization.NormalizeOperation(&operation, &definition, &report) - if report.HasErrors() && !options.expectNormalizationError { - panic(report.Error()) - } - } - - validator := &OperationValidator{} - validator.RegisterRule(rule) - - result := validator.Validate(&operation, &definition, &report) - - printedOperation := mustString(astprinter.PrintString(&operation, &definition)) - - if options.expectValidationErrors { - for _, msg := range options.expectedValidationErrorMsgs { - assert.Contains(t, report.Error(), msg) - } - } - - require.Equal(t, expectation, result, "wrong validation result expected: %v got: %v\nreason: %v\noperation:\n%s\n", expectation, result, report.Error(), printedOperation) - } - - runManyRulesWithDefinition := func(t *testing.T, definitionInput, operationInput string, expectation ValidationState, rules ...Rule) { - t.Helper() - for _, rule := range rules { - runWithDefinition(t, definitionInput, operationInput, rule, expectation) - } - } - _ = runManyRulesWithDefinition - - runManyRules := func(t *testing.T, operationInput string, expectation ValidationState, rules ...Rule) { - t.Helper() - for _, rule := range rules { - runWithDefinition(t, testDefinition, operationInput, rule, expectation) - } - } - _ = runManyRules - - run := func(t *testing.T, operationInput string, rule Rule, expectation ValidationState, opts ...option) { - t.Helper() - runWithDefinition(t, testDefinition, operationInput, rule, expectation, opts...) - } - - // 5.1 Documents - // 5.1.1 Executable Definitions - // -> won't be addressed as the parser will only parse operation- and fragment definitions - // when parsing executable definitions - - t.Run("5.2 Operations", func(t *testing.T) { - t.Run("5.2.1 Named Operation Definitions", func(t *testing.T) { - t.Run("5.2.1.1 Operation Name Uniqueness", func(t *testing.T) { - t.Run("92", func(t *testing.T) { - run(t, ` - query getDogName { - dog { - name - } - } - query getOwnerName { - dog { - owner { - name - } - } - }`, - OperationNameUniqueness(), Valid) - }) - t.Run("93", func(t *testing.T) { - run(t, ` - query getName { - dog { - name - } - } - query getName { - dog { - owner { - name - } - } - }`, - OperationNameUniqueness(), Invalid) - }) - t.Run("94", func(t *testing.T) { - run(t, ` - query dogOperation { - dog { - name - } - } - mutation dogOperation { - mutateDog { - id - } - }`, - OperationNameUniqueness(), Invalid) - }) - }) - }) - t.Run("5.2.2 Anonymous Operation Definitions", func(t *testing.T) { - t.Run("5.2.2.1 Lone Anonymous Operation", func(t *testing.T) { - t.Run("95", func(t *testing.T) { - run(t, ` { - dog { - name - } - }`, - LoneAnonymousOperation(), Valid) - }) - t.Run("96", func(t *testing.T) { - run(t, ` { - dog { - name - } - } - query getName { - dog { - owner { - name - } - } - }`, - LoneAnonymousOperation(), Invalid) - }) - t.Run("96 variant", func(t *testing.T) { - run(t, ` query getDogName { - dog { - name - } - } - query getOwnerName { - dog { - owner { - name - } - } - }`, - LoneAnonymousOperation(), Valid) - }) - }) - }) - t.Run("5.2.3 Subscription Operation Definitions", func(t *testing.T) { - t.Run("5.2.3.1 Single root field", func(t *testing.T) { - t.Run("97", func(t *testing.T) { - run(t, ` - subscription sub { - newMessage { - body - sender - } - }`, - SubscriptionSingleRootField(), Valid) - }) - t.Run("97 variant", func(t *testing.T) { - run(t, ` - query sub { - foo - bar - }`, - SubscriptionSingleRootField(), Valid) - }) - t.Run("97 variant", func(t *testing.T) { - run(t, ` - subscription sub { - ... { foo } - ... { bar } - }`, - SubscriptionSingleRootField(), Invalid) - }) - t.Run("98", func(t *testing.T) { - run(t, ` subscription sub { - ...newMessageFields - } - fragment newMessageFields on Subscription { - newMessage { - body - sender - } - }`, - SubscriptionSingleRootField(), Valid) - }) - t.Run("99", func(t *testing.T) { - run(t, ` - subscription sub { - newMessage { - body - sender - } - disallowedSecondRootField - }`, - SubscriptionSingleRootField(), Invalid) - }) - t.Run("100", func(t *testing.T) { - run(t, ` - subscription sub { - ...multipleSubscriptions - } - fragment multipleSubscriptions on Subscription { - newMessage { - body - sender - } - disallowedSecondRootField - }`, - SubscriptionSingleRootField(), Invalid) - }) - t.Run("101", func(t *testing.T) { - run(t, ` - subscription sub { - newMessage { - body - sender - } - __typename - }`, - SubscriptionSingleRootField(), Invalid) - }) - }) - }) - }) - t.Run("5.3 FieldSelections", func(t *testing.T) { - t.Run("5.3.1 Field Selections on Objects, Interfaces, and Unions Types", func(t *testing.T) { - t.Run("104", func(t *testing.T) { - run(t, ` - { - dog { - ...aliasedLyingFieldTargetNotDefined - } - } - fragment aliasedLyingFieldTargetNotDefined on Dog { - barkVolume: kawVolume - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - t.Run("104 variant", func(t *testing.T) { - run(t, ` - { - dog { - barkVolume: kawVolume - } - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - t.Run("103", func(t *testing.T) { - run(t, ` { - dog { - ...interfaceFieldSelection - } - } - fragment interfaceFieldSelection on Pet { - name - }`, - FieldSelections(), Valid) - }) - t.Run("104", func(t *testing.T) { - run(t, ` - { - dog { - ...definedOnImplementorsButNotInterface - } - } - fragment definedOnImplementorsButNotInterface on Pet { - nickname - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - t.Run("105", func(t *testing.T) { - run(t, ` fragment inDirectFieldSelectionOnUnion on CatOrDog { - __typename - ... on Pet { - name - } - ... on Dog { - name - } - }`, - FieldSelections(), Valid) - }) - t.Run("105 variant", func(t *testing.T) { - run(t, ` - fragment inDirectFieldSelectionOnUnion on CatOrDog { - __typename - ... on Pet { - name - } - ... on Dog { - name - } - }`, - FieldSelections(), Valid) - }) - t.Run("105 variant", func(t *testing.T) { - run(t, ` - fragment inDirectFieldSelectionOnUnion on CatOrDog { - __typename - ... on Pet { - name - } - ... { - x - } - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - t.Run("106", func(t *testing.T) { - run(t, ` - fragment directFieldSelectionOnUnion on CatOrDog { - name - barkVolume - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - t.Run("106 variant", func(t *testing.T) { - run(t, ` - fragment directFieldSelectionOnUnion on Cat { - name { - name - } - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - }) - t.Run("5.3.2 Field Selection Merging", func(t *testing.T) { - t.Run("introspection query", func(t *testing.T) { - run(t, `query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - kind - name - description - fields(includeDeprecated: true){ - name - description - args { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - isDeprecated - deprecationReason - } - inputFields { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - interfaces { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - enumValues(includeDeprecated: true){ - name - description - isDeprecated - deprecationReason - } - possibleTypes { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - } - directives { - name - description - locations - args { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - } - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("reference implementation tests", func(t *testing.T) { - t.Run("Same aliases allowed on non-overlapping fields", func(t *testing.T) { - run(t, ` - fragment sameAliasesWithDifferentFieldTargets on Pet { - ... on Dog { - name - } - ... on Cat { - name: nickname - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("allows different args where no conflict is possible", func(t *testing.T) { - run(t, ` - fragment conflictingArgs on Pet { - ... on Dog { - name(surname: true) - } - ... on Cat { - name - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("encounters conflict in fragments", func(t *testing.T) { - run(t, ` - { - ...A - ...B - } - fragment A on Query { - x: a - } - fragment B on Query { - x: b - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("reports each conflict once", func(t *testing.T) { - run(t, ` - { - f1 { - ...A - ...B - } - f2 { - ...B - ...A - } - f3 { - ...A - ...B - x: c - } - } - fragment A on Field { - x: a - } - fragment B on Field { - x: b - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("deep conflict", func(t *testing.T) { - run(t, ` - { - field { - x: a - }, - field { - x: b - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("deep conflict with multiple issues", func(t *testing.T) { - run(t, ` - { - field { - x: a - y: c - }, - field { - x: b - y: d - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("very deep conflict", func(t *testing.T) { - run(t, ` - { - field { - deepField { - x: a - } - }, - field { - deepField { - x: b - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("very deep conflict validated", func(t *testing.T) { - run(t, ` - { - field { - deepField { - x: a - } - }, - field { - deepField { - x: a - } - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("reports deep conflict to nearest common ancestor", func(t *testing.T) { - run(t, ` - { - field { - deepField { - x: a - } - deepField { - x: b - } - }, - field { - deepField { - y - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("reports deep conflict to nearest common ancestor in fragments", func(t *testing.T) { - run(t, ` - { - field { - ...F - } - field { - ...F - } - } - fragment F on T { - deepField { - deeperField { - x: a - } - deeperField { - x: b - } - }, - deepField { - deeperField { - y - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("reports deep conflict in nested fragments", func(t *testing.T) { - run(t, ` - { - field { - ...F - } - field { - ...I - } - } - fragment F on Field { - x: a - ...G - } - fragment G on Field { - y: c - } - fragment I on Field { - y: d - ...J - } - fragment J on Field { - x: b - }`, FieldSelectionMerging(), Invalid) - }) - /* - Why ignore when this still will result in an error because T is undefined? - t.Run("ignores unknown fragments", func(t *testing.T) { - run(t,` - { - field - ...Unknown - ...Known - } - fragment Known on T { - field - ...OtherUnknown - }`, FieldSelectionMerging(), Valid) - })*/ - t.Run("return types must be unambiguous", func(t *testing.T) { - t.Run("conflicting return types which potentially overlap", func(t *testing.T) { - /*This is invalid since an object could potentially be both the Object - type IntBox and the interface type NonNullStringBox1. While that - condition does not exist in the current schema, the schema could - expand in the future to allow this. Thus it is invalid.*/ - runWithDefinition(t, boxDefinition, ` - { - someBox { - ...on IntBox { - scalar - } - ...on NonNullStringBox1 { - scalar - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("compatible return shapes on different return types", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on SomeBox { - deepBox { - unrelatedField - } - } - ... on StringBox { - deepBox { - unrelatedField - } - } - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("disallows differing return types despite no overlap", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - scalar - } - ... on StringBox { - scalar - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("disallows differing return types despite no overlap", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - b: unrelatedField - } - ... on SomeBox { - b: unrelatedField - } - ... on StringBox { - b: scalar - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("deeply nested", func(t *testing.T) { - // reports correctly when a non-exclusive follows an exclusive - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - deepBox { - ...X - } - } - } - someBox { - ... on StringBox { - deepBox { - ...Y - } - } - } - memoed: someBox { - ... on IntBox { - deepBox { - ...X - } - } - } - memoed: someBox { - ... on StringBox { - deepBox { - ...Y - } - } - } - other: someBox { - ...X - } - other: someBox { - ...Y - } - } - fragment X on SomeBox { - scalar - } - fragment Y on SomeBox { - scalar: unrelatedField - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("disallows differing return type nullability despite no overlap", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on NonNullStringBox1 { - scalar - } - ... on StringBox { - scalar - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("disallows differing return type list despite no overlap", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - box: listStringBox { - scalar - } - } - ... on StringBox { - box: stringBox { - scalar - } - } - } - }`, FieldSelectionMerging(), Invalid) - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar - } - } - ... on StringBox { - box: listStringBox { - scalar - } - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("disallows differing subfields", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - box: stringBox { - val: scalar - val: unrelatedField - } - } - ... on StringBox { - box: stringBox { - val: scalar - } - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("disallows differing deep return types despite no overlap", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar - } - } - ... on StringBox { - box: intBox { - scalar - } - } - } - }`, FieldSelectionMerging(), Invalid) - }) - t.Run("allows non-conflicting overlapping types", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ... on IntBox { - scalar: unrelatedField - } - ... on StringBox { - scalar - } - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("same wrapped scalar return types", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - someBox { - ...on NonNullStringBox1 { - scalar - } - ...on NonNullStringBox2 { - scalar - } - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("allows inline typeless fragments", func(t *testing.T) { - run(t, ` - { - a - ... { - a - } - }`, FieldSelectionMerging(), Valid) - }) - t.Run("compares deep types including list", func(t *testing.T) { - runWithDefinition(t, boxDefinition, ` - { - connection { - ...edgeID - edges { - node { - id: name - } - } - } - } - fragment edgeID on Connection { - edges { - node { - id - } - } - }`, FieldSelectionMerging(), Invalid) - }) - /* - Why ignore? - t.Run("ignores unknown types", func(t *testing.T) { - runWithDefinition(t,boxDefinition, ` - { - someBox { - ...on UnknownType { - scalar - } - ...on NonNullStringBox2 { - scalar - } - } - }`, FieldSelectionMerging(), Valid) - })*/ - }) - }) - t.Run("107", func(t *testing.T) { - run(t, ` - fragment mergeIdenticalFields on Dog { - name - name - } - fragment mergeIdenticalAliasesAndFields on Dog { - otherName: name - otherName: name - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("107 variant", func(t *testing.T) { - run(t, ` - query mergeIdenticalFields { - dog { - name - name - } - } - query mergeIdenticalAliasesAndFields { - dog { - otherName: name - otherName: name - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108", func(t *testing.T) { - run(t, ` - fragment conflictingBecauseAlias on Dog { - name: nickname - name - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - name: nickname - name - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - extra { string } - extra { string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extra { string } - extra { string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extra { string } - extra { string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extra { string } - extra { noString: string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extra { string } - extra { string: noString } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - extra { string } - extra: extras { string } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - extras { string } - extras: mustExtras { string } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - x: extras { string } - x: mustExtras { string } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extras { string,string2: string } - extras { string,string3: string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extras { string,string2: string } - extras { string,string2: string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extras { string,string2: string2 } - extras { string,string2: string,string3: string } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extras { ... { string },string2: string } - extras { ... { string },... { string },string2: string } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - extras { ... { string },string: string1 } - extras { ... { string1: string },string2: string } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extras { ...frag, ...frag } - extras { ...frag } - } - } - fragment frag on DogExtra { string }`, - FieldSelectionMerging(), Valid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - extras { - ... { - string1: bool - } - } - extras { - ... { - string1: string - } - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` - query conflictingBecauseAlias { - dog { - extras { ...frag } - extras { ...frag2 } - } - } - fragment frag on DogExtra { string1 } - fragment frag2 on DogExtra { string1: string }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - extra { looksLikeString: string } - extra { looksLikeString: bool } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - name: nickname - ...nameFrag - } - } - fragment nameFrag on Dog { - name - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - name: nickname - ...nameFrag - } - } - fragment nameFrag on Dog { - ...nameFrag2 - } - fragment nameFrag2 on Dog { - name - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - name: nickname - ... on Dog { - ... nameFrag - } - } - } - fragment nameFrag on Dog { - name - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - name: nickname - ... { - name - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - name: nickname - ... @include(if: true) { - name - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("108 variant", func(t *testing.T) { - run(t, ` query conflictingBecauseAlias { - dog { - name: nickname - ... @include(if: false) { - name - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109", func(t *testing.T) { - run(t, ` - fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: SIT) - } - fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: $dogCommand) - doesKnowCommand(dogCommand: $dogCommand) - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: 1) - doesKnowCommand(dogCommand: 1) - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` - fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: 1) - doesKnowCommand(dogCommand: 0) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: 1.1) - doesKnowCommand(dogCommand: 1.1) - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: 1.1) - doesKnowCommand(dogCommand: 0.1) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: "foo") - doesKnowCommand(dogCommand: "foo") - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: "foo") - doesKnowCommand(dogCommand: "bar") - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: null) - doesKnowCommand(dogCommand: null) - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: null) - doesKnowCommand(dogCommand: 0) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: [1.1]) - doesKnowCommand(dogCommand: [1.1]) - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: [1.1]) - doesKnowCommand(dogCommand: [0.1]) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: [1.1]) - doesKnowCommand(dogCommand: [1.1,1.1]) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` - fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: {foo: "bar"}) - doesKnowCommand(dogCommand: {foo: "bar"}) - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` - fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: {foo: "bar"}) - doesKnowCommand(dogCommand: {bar: "bar"}) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: {foo: "bar"}) - doesKnowCommand(dogCommand: {foo: "baz"}) - doesKnowCommand(dogCommand: {bar: "baz"}) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("109 variant", func(t *testing.T) { - run(t, ` fragment mergeIdenticalFieldsWithIdenticalValues on Dog { - doesKnowCommand(dogCommand: {foo: "bar"}) - doesKnowCommand(dogCommand: {foo: "baz",bar: "bat"}) - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("110", func(t *testing.T) { - run(t, ` fragment conflictingArgsOnValues on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: HEEL) - }`, - FieldSelectionMerging(), Invalid) - run(t, ` fragment conflictingArgsOnValues on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand1: HEEL) - }`, - FieldSelectionMerging(), Invalid) - run(t, ` fragment conflictingArgsValueAndVar on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: $dogCommand) - }`, - FieldSelectionMerging(), Invalid) - run(t, ` fragment conflictingArgsWithVars on Dog { - doesKnowCommand(dogCommand: $varOne) - doesKnowCommand(dogCommand: $varTwo) - }`, - FieldSelectionMerging(), Invalid) - run(t, ` fragment differingArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("111", func(t *testing.T) { - run(t, ` - fragment safeDifferingFields on Pet { - ... on Dog { - volume: barkVolume - } - ... on Cat { - volume: meowVolume - } - } - fragment safeDifferingArgs on Pet { - ... on Dog { - doesKnowCommand(dogCommand: SIT) - } - ... on Cat { - doesKnowCommand(catCommand: JUMP) - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ... on Dog { - someValue: nickname - } - ... on Cat { - someValue: meowVolume - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - string - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - strings - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - string: strings - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - string: mustStrings - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - string: string2 - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - noString: string - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - string: bool - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - ... { - string: bool - } - } - } - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - ... on CatExtra { - string - } - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - ... on CatExtra { - ... { string } - } - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - ... on CatExtra { - ...spreadNotExists - } - } - } - }`, - FieldSelectionMerging(), Invalid, withExpectNormalizationError()) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ... on Dog { - extra { - string - } - } - ... on Cat { - extra { - ... on CatExtra { - noString: string - } - } - } - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ...dogFrag - ...catFrag - } - fragment dogFrag on Dog { - someValue: nickname - } - fragment catFrag on Cat { - someValue: meowVolume - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - pet { - ...dogFrag - ...catFrag - } - } - fragment dogFrag on Dog { - someValue: nickname - } - fragment catFrag on Cat { - someValue: meowVolume - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - catOrDog { - ...catDogFrag - } - } - fragment catDogFrag on CatOrDog { - ...catFrag - ...dogFrag - } - fragment catFrag on Cat { - someValue: meowVolume - } - fragment dogFrag on Dog { - someValue: barkVolume - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - pet { - ...pet1 - ...pet2 - } - } - fragment pet1 on Pet { - name - } - fragment pet2 on Pet { - name - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - pet { - ...pet1 - ...pet2 - } - } - fragment pet1 on Pet { - name1: name - } - fragment pet2 on Pet { - name1: nickname - }`, - FieldSelectionMerging(), Invalid, withExpectNormalizationError()) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - query conflictingDifferingResponses { - catOrDog { - ...catDogFrag - } - } - fragment catDogFrag on CatOrDog { - ...catFrag - ...dogFrag - } - fragment catFrag on Cat { - someValue: meowVolume - } - fragment dogFrag on Dog { - someValue: name - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ...dogFrag - ...catFrag - } - fragment dogFrag on Dog { - someValue: barkVolume - } - fragment catFrag on Cat { - someValue: meowVolume - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` fragment conflictingDifferingResponses on Pet { - ...dogFrag - ...catFrag - } - fragment dogFrag on Dog { - someValue: barkVolume - } - fragment catFrag on Cat { - someValue: name - }`, - FieldSelectionMerging(), Invalid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ...dogFrag - ...catFrag - } - fragment dogFrag on Dog { - someValue: barkVolume - } - fragment catFrag on Cat { - someValue: meowVolume - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - fragment conflictingDifferingResponses on Pet { - ...dogFrag - ... on Cat { - someValue: meowVolume - } - } - fragment dogFrag on Dog { - someValue: barkVolume - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - pet { - ...dogFrag - ...catFrag - } - } - fragment dogFrag on Dog { - someValue: barkVolume - } - fragment catFrag on Cat { - someValue: meowVolume - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - pet { - ...dogFrag - ... on Cat { - someValue: meowVolume - } - } - } - fragment dogFrag on Dog { - someValue: barkVolume - }`, - FieldSelectionMerging(), Valid) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` - query conflictingDifferingResponses { - pet { - ...dogFrag - ... on Cat { - foo - } - } - } - fragment dogFrag on Dog { - someValue: barkVolume - }`, - FieldSelectionMerging(), Invalid, withExpectNormalizationError()) - }) - t.Run("112 variant", func(t *testing.T) { - run(t, ` query conflictingDifferingResponses { - extra { - ... on CatExtra { value: bool } - ... on DogExtra { value: bool } - } - }`, - FieldSelectionMerging(), Invalid) - }) - }) - t.Run("5.3.3 Leaf Field Selections", func(t *testing.T) { - t.Run("113", func(t *testing.T) { - run(t, ` fragment scalarSelection on Dog { - barkVolume - }`, - FieldSelections(), Valid) - }) - t.Run("114", func(t *testing.T) { - run(t, ` - fragment scalarSelectionsNotAllowedOnInt on Dog { - barkVolume { - sinceWhen - } - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - t.Run("116", func(t *testing.T) { - run(t, ` - query directQueryOnObjectWithoutSubFields { - human - }`, - FieldSelections(), Invalid) - run(t, ` query directQueryOnInterfaceWithoutSubFields { - pet - }`, - FieldSelections(), Invalid) - run(t, ` query directQueryOnUnionWithoutSubFields { - catOrDog - }`, - FieldSelections(), Invalid) - run(t, ` - mutation directQueryOnUnionWithoutSubFields { - catOrDog - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - run(t, ` - subscription directQueryOnUnionWithoutSubFields { - catOrDog - }`, - FieldSelections(), Invalid, withExpectNormalizationError()) - }) - }) - }) - t.Run("5.4 Arguments", func(t *testing.T) { - t.Run("5.4.1 Argument Names", func(t *testing.T) { - t.Run("117", func(t *testing.T) { - run(t, ` - fragment argOnRequiredArg on Dog { - doesKnowCommand(dogCommand: SIT) - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: true) @include(if: true) - }`, - KnownArguments(), Valid) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg { - dog { - doesKnowCommand(dogCommand: SIT) - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: true) @include(if: true) - }`, - KnownArguments(), Valid) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg($dogCommand: DogCommand!) { - dog { - doesKnowCommand(dogCommand: $dogCommand) - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: true) @include(if: true) - }`, - KnownArguments(), Valid) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` - query argOnRequiredArg($dogCommand: DogCommand = SIT) { - dog { - doesKnowCommand(dogCommand: $dogCommand) - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: true) @include(if: true) - }`, - KnownArguments(), Valid, withDisableNormalization()) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` - query argOnRequiredArg($catCommand: CatCommand) { - dog { - doesKnowCommand(dogCommand: $catCommand) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$catCommand" of type "CatCommand" used in position expecting type "DogCommand!".`)) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, `query argOnRequiredArg($dogCommand: CatCommand) { - dog { - ... on Dog { - doesKnowCommand(dogCommand: $dogCommand) - } - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$dogCommand" of type "CatCommand" used in position expecting type "DogCommand!".`)) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg($booleanArg: Boolean) { - dog { - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: $booleanArg) @include(if: true) - }`, - ValidArguments(), Valid) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` - query argOnRequiredArg($booleanArg: Boolean!) { - dog { - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: $booleanArg) @include(if: $booleanArg) - }`, - ValidArguments(), Valid) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` - query argOnRequiredArg($booleanArg: Boolean) { - dog { - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: $booleanArg) @include(if: $booleanArg) - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$booleanArg" of type "Boolean" used in position expecting type "Boolean!".`)) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg($booleanArg: Boolean!) { - dog { - ...argOnOptional - } - } - fragment argOnOptional on Dog { - ... { - isHousetrained(atOtherHomes: $booleanArg) @include(if: $booleanArg) - } - }`, - ValidArguments(), Valid) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg($intArg: Integer) { - dog { - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: $intArg) @include(if: true) - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$intArg" of type "Integer" used in position expecting type "Boolean".`)) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg($intArg: Integer) { - pet { - ...argOnOptional - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: $intArg) @include(if: true) - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$intArg" of type "Integer" used in position expecting type "Boolean".`)) - }) - t.Run("117 variant", func(t *testing.T) { - run(t, ` query argOnRequiredArg($intArg: Integer) { - pet { - ...on Dog { - ...argOnOptional - } - } - } - fragment argOnOptional on Dog { - isHousetrained(atOtherHomes: $intArg) @include(if: true) - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$intArg" of type "Integer" used in position expecting type "Boolean".`)) - }) - t.Run("118", func(t *testing.T) { - run(t, ` - { - dog { ...invalidArgName} - } - fragment invalidArgName on Dog { - doesKnowCommand(command: CLEAN_UP_HOUSE) - }`, - KnownArguments(), Invalid, withValidationErrors(`Unknown argument "command" on field "Dog.doesKnowCommand"`)) - }) - t.Run("118 variant", func(t *testing.T) { - run(t, ` - { - dog { ...invalidArgName} - } - fragment invalidArgName on Dog { - doesKnowCommand(dogCommand: CLEAN_UP_HOUSE) - }`, - Values(), - Invalid, - withValidationErrors(`Value "CLEAN_UP_HOUSE" does not exist in "DogCommand" enum.`)) - }) - t.Run("119", func(t *testing.T) { - run(t, ` { - dog { ...invalidArgName } - } - fragment invalidArgName on Dog { - isHousetrained(atOtherHomes: true) @include(unless: false) - }`, - KnownArguments(), Invalid, withValidationErrors(`Unknown argument "unless" on directive "@include".`)) - }) - t.Run("121 args in reversed order", func(t *testing.T) { - run(t, ` fragment multipleArgs on ValidArguments { - multipleReqs(x: 1, y: 2) - } - fragment multipleArgsReverseOrder on ValidArguments { - multipleReqs(y: 2, x: 1) - }`, - ValidArguments(), Valid) - }) - t.Run("undefined arg", func(t *testing.T) { - run(t, ` { - dog(name: "Goofy"){ - name - } - }`, - KnownArguments(), Invalid, withValidationErrors(`Unknown argument "name" on field "Query.dog".`)) - }) - }) - t.Run("5.4.2 Argument Uniqueness", func(t *testing.T) { - t.Run("121 variant", func(t *testing.T) { - run(t, ` - { - arguments { ... multipleArgs } - } - fragment multipleArgs on ValidArguments { - multipleReqs(x: 1, x: 2) - }`, - ArgumentUniqueness(), Invalid) - }) - t.Run("121 variant", func(t *testing.T) { - run(t, `{ - arguments { ... multipleArgs } - } - fragment multipleArgs on ValidArguments { - multipleReqs(x: 1) - }`, - ArgumentUniqueness(), Valid) - }) - }) - - t.Run("Required Invalid Arguments", func(t *testing.T) { - t.Run("required String", func(t *testing.T) { - run(t, ` query requiredString { - args { - requiredString(s: foo) - } - }`, - Values(), Invalid, withValidationErrors(`String cannot represent a non string value: foo`)) - }) - t.Run("required String", func(t *testing.T) { - run(t, ` query requiredString { - args { - requiredString(s: null) - } - }`, - Values(), Invalid, withValidationErrors(`Expected value of type "String!", found null`)) - }) - - t.Run("required Float", func(t *testing.T) { - run(t, ` query requiredFloat { - args { - requiredFloat(f: "1.1") - } - }`, - Values(), Invalid, withValidationErrors(`Float cannot represent non numeric value: "1.1"`)) - }) - t.Run("required Float", func(t *testing.T) { - run(t, ` query requiredFloat { - args { - requiredFloat(f: null) - } - }`, - Values(), Invalid, withValidationErrors(`Expected value of type "Float!", found null`)) - }) - }) - - t.Run("5.4.2.1 Required ValidArguments", func(t *testing.T) { - t.Run("required String", func(t *testing.T) { - run(t, ` query requiredString { - args { - requiredString(s: "foo") - } - }`, - Values(), Valid) - }) - - t.Run("required Float", func(t *testing.T) { - run(t, ` query requiredFloat { - args { - requiredFloat(f: 1.1) - } - }`, - Values(), Valid) - }) - t.Run("122", func(t *testing.T) { - run(t, ` { - arguments { - ...goodBooleanArg - ...goodNonNullArg - } - } - fragment goodBooleanArg on ValidArguments { - booleanArgField(booleanArg: true) - } - fragment goodNonNullArg on ValidArguments { - nonNullBooleanArgField(nonNullBooleanArg: true) - }`, - RequiredArguments(), Valid) - }) - t.Run("123", func(t *testing.T) { - run(t, ` { - arguments { - ...goodBooleanArgDefault - } - } - fragment goodBooleanArgDefault on ValidArguments { - booleanArgField - }`, - RequiredArguments(), Valid) - }) - t.Run("124", func(t *testing.T) { - run(t, ` - { - arguments { - ...missingRequiredArg - } - } - fragment missingRequiredArg on ValidArguments { - nonNullBooleanArgField - }`, - RequiredArguments(), Invalid) - }) - t.Run("125", func(t *testing.T) { - run(t, ` { - arguments { - ...missingRequiredArg - } - } - fragment missingRequiredArg on ValidArguments { - nonNullBooleanArgField(nonNullBooleanArg: null) - }`, - RequiredArguments(), Invalid) - }) - t.Run("125 variant", func(t *testing.T) { - run(t, ` { - arguments { - ...missingRequiredArg - } - } - fragment missingRequiredArg on ValidArguments { - nonNullBooleanArgField(nonNullBooleanArg: true) - }`, - RequiredArguments(), Valid) - }) - t.Run("125 variant", func(t *testing.T) { - run(t, ` { - booleanList (booleanListArg: [true]) - }`, - RequiredArguments(), Valid) - }) - }) - }) - t.Run("5.5 Fragments", func(t *testing.T) { - t.Run("5.5.1 Fragment Declarations", func(t *testing.T) { - t.Run("5.5.1.1 Fragment Name Uniqueness", func(t *testing.T) { - t.Run("126", func(t *testing.T) { - run(t, ` - { - dog { - ...fragmentOne - ...fragmentTwo - } - } - fragment fragmentOne on Dog { - name - } - fragment fragmentTwo on Dog { - owner { - name - } - }`, - Fragments(), Valid) - }) - t.Run("127", func(t *testing.T) { - run(t, ` - { - dog { - ...fragmentOne - } - } - fragment fragmentOne on Dog { - name - } - fragment fragmentOne on Dog { - owner { - name - } - }`, - Fragments(), Invalid) - }) - }) - t.Run("5.5.1.2 Fragment Spread Existence", func(t *testing.T) { - t.Run("128", func(t *testing.T) { - run(t, ` - { - dog { - ...inlineFragment - ...inlineFragment2 - } - } - fragment correctType on Dog { - name - } - fragment inlineFragment on Dog { - ... on Dog { - name - } - ...correctType - } - fragment inlineFragment2 on Dog { - ... @include(if: true) { - name - } - }`, Fragments(), Valid) - }) - t.Run("129", func(t *testing.T) { - run(t, ` - fragment notOnExistingType on NotInSchema { - name - }`, Fragments(), Invalid, withExpectNormalizationError()) - }) - t.Run("129", func(t *testing.T) { - run(t, ` - fragment inlineNotExistingType on Dog { - ... on NotInSchema { - name - } - }`, Fragments(), Invalid, withExpectNormalizationError()) - }) - }) - t.Run("5.5.1.3 Fragments on Composite Types", func(t *testing.T) { - t.Run("130", func(t *testing.T) { - run(t, ` - { - dog { - ...fragOnObject - ...fragOnInterface - ...fragOnUnion - } - } - fragment fragOnObject on Dog { - name - } - fragment fragOnInterface on Pet { - name - } - fragment fragOnUnion on CatOrDog { - ... on Dog { - name - } - }`, - Fragments(), Valid) - }) - t.Run("131", func(t *testing.T) { - run(t, ` - fragment fragOnScalar on Int { - something - }`, - Fragments(), Invalid, withExpectNormalizationError()) - }) - t.Run("131", func(t *testing.T) { - run(t, ` - fragment inlineFragOnScalar on Dog { - ... on Boolean { - somethingElse - } - }`, - Fragments(), Invalid, withExpectNormalizationError()) - }) - }) - t.Run("5.5.1.4 Fragments must be used", func(t *testing.T) { - t.Run("132", func(t *testing.T) { - run(t, ` - fragment nameFragment on Dog { - name - ...nameFragment2 - } - fragment nameFragment2 on Dog { - name - } - fragment nameFragment3 on Dog { - name - } - { - dog { - ...nameFragment - ...nameFragment2 - ...nameFragment2 - } - }`, - Fragments(), Invalid) - }) - t.Run("132 variant", func(t *testing.T) { - run(t, ` - fragment dogNames on Query { - dog { name } - } - { - ...dogNames - }`, - Fragments(), Valid) - }) - t.Run("132 variant", func(t *testing.T) { - run(t, ` - fragment catNames on Query { - dog { name } - } - { - ...dogNames - }`, - Fragments(), Invalid, withExpectNormalizationError()) - }) - t.Run("132 variant", func(t *testing.T) { - run(t, ` fragment dogNames on Query { - dog { name } - } - { - ... { ...dogNames } - }`, - Fragments(), Valid) - }) - }) - }) - t.Run("5.5.2 Fragment Spreads", func(t *testing.T) { - t.Run("5.5.2.1 Fragment spread target defined", func(t *testing.T) { - t.Run("Undefined fragment returns ErrFragmentUndefined", func(t *testing.T) { - run(t, ` - { - dog { - ...undefinedFragment - } - }`, - Fragments(), Invalid, withExpectNormalizationError(), withValidationErrors("undefinedFragment undefined")) - }) - t.Run("Undefined fragment after valid fragment returns ErrFragmentUndefined", func(t *testing.T) { - run(t, ` - { - cat { - ...validCatFragment - } - dog { - ...undefinedFragment - } - } - fragment validCatFragment on Cat { - name - meowVolume - }`, - Fragments(), Invalid, withExpectNormalizationError(), withValidationErrors("undefinedFragment undefined")) - }) - }) - t.Run("5.5.2.2 Fragment spreads must not form cycles", func(t *testing.T) { - t.Run("134", func(t *testing.T) { - run(t, ` - { - dog { - ...nameFragment - } - } - fragment nameFragment on Dog { - name - ...barkVolumeFragment - } - fragment barkVolumeFragment on Dog { - barkVolume - ...nameFragment - }`, - Fragments(), Invalid, withValidationErrors("external: fragment spread: barkVolumeFragment forms fragment cycle")) - }) - t.Run("136", func(t *testing.T) { - run(t, ` - { - dog { - ...dogFragment - } - } - fragment dogFragment on Dog { - name - owner { - ...ownerFragment - } - } - fragment ownerFragment on Dog { - name - pets { - ...dogFragment - } - }`, - Fragments(), Invalid, withExpectNormalizationError()) - }) - t.Run("136 variant", func(t *testing.T) { - run(t, ` - { - dog { - ...dogFragment - } - } - fragment dogFragment on Dog { - name - owner { - ...ownerFragment - } - } - fragment ownerFragment on Dog { - name - pets { - ... { ...dogFragment } - } - }`, - Fragments(), Invalid, withExpectNormalizationError()) - }) - }) - t.Run("5.5.2.3 Fragment spread is possible", func(t *testing.T) { - t.Run("5.5.2.3.1 Object Spreads In Object Scope", func(t *testing.T) { - t.Run("137", func(t *testing.T) { - run(t, ` - { - dog { - ...dogFragment - } - } - fragment dogFragment on Dog { - ... on Dog { - barkVolume - } - }`, - Fragments(), Valid) - }) - t.Run("137 variant", func(t *testing.T) { - run(t, ` - { - dog { - ...dogFragment - } - } - fragment dogFragment on Dog { - ... on NoDog { - barkVolume - } - }`, - Fragments(), Invalid, withExpectNormalizationError()) - }) - t.Run("138", func(t *testing.T) { - run(t, ` - { - dog { - ...catInDogFragmentInvalid - } - } - fragment catInDogFragmentInvalid on Dog { - ... on Cat { - meowVolume - } - }`, - Fragments(), Invalid) - }) - t.Run("138 variant", func(t *testing.T) { - run(t, ` - { - dog { - ...catInDogFragmentInvalid - } - } - fragment catInDogFragmentInvalid on CatOrDog { - ... on Cat { - meowVolume - } - }`, - Fragments(), Valid) - }) - t.Run("Spreading a fragment on an invalid type returns ErrInvalidFragmentSpread", func(t *testing.T) { - run(t, ` - { - dog { - ...invalidCatFragment - } - } - fragment invalidCatFragment on Cat { - meowVolume - }`, - Fragments(), Invalid, withValidationErrors("external: fragment spread: fragment invalidCatFragment must be spread on type Cat and not type Dog")) - }) - }) - t.Run("5.5.2.3.2 Abstract Spreads in Object Scope", func(t *testing.T) { - t.Run("139", func(t *testing.T) { - run(t, ` { - dog { - ...interfaceWithinObjectFragment - } - } - fragment petNameFragment on Pet { - name - } - fragment interfaceWithinObjectFragment on Dog { - ...petNameFragment - }`, - Fragments(), Valid) - }) - t.Run("140", func(t *testing.T) { - run(t, ` - { - dog { - ...unionWithObjectFragment - } - } - fragment catOrDogNameFragment on CatOrDog { - ... on Cat { - meowVolume - } - } - fragment unionWithObjectFragment on Dog { - ...catOrDogNameFragment - }`, - Fragments(), Valid) - }) - }) - t.Run("5.5.2.3.3 Object Spreads In Abstract Scope", func(t *testing.T) { - t.Run("141", func(t *testing.T) { - run(t, ` { - dog { - ...petFragment - ...catOrDogFragment - } - } - fragment petFragment on Pet { - name - ... on Dog { - barkVolume - } - } - fragment catOrDogFragment on CatOrDog { - ... on Cat { - meowVolume - } - }`, - Fragments(), Valid) - }) - t.Run("142", func(t *testing.T) { - run(t, ` fragment sentientFragment on Sentient { - ... on Dog { - barkVolume - } - }`, - Fragments(), Invalid) - }) - t.Run("142 variant", func(t *testing.T) { - run(t, ` fragment humanOrAlienFragment on HumanOrAlien { - ... on Cat { - meowVolume - } - }`, - Fragments(), Invalid) - }) - }) - t.Run("5.5.2.3.4 Abstract Spreads in Abstract Scope", func(t *testing.T) { - t.Run("143", func(t *testing.T) { - run(t, ` - { - dog { - ...unionWithInterface - } - } - fragment unionWithInterface on Pet { - ...dogOrHumanFragment - } - fragment dogOrHumanFragment on DogOrHuman { - ... on Dog { - barkVolume - } - }`, - Fragments(), Valid) - }) - t.Run("143 variant", func(t *testing.T) { - run(t, ` - { - dog { - ...interfaceWithUnion - } - } - fragment interfaceWithUnion on DogOrHuman { - ...petFragment - } - fragment petFragment on Pet { - ... on Dog { - barkVolume - } - }`, - Fragments(), Valid) - }) - t.Run("144", func(t *testing.T) { - run(t, ` - { - dog { - ...nonIntersectingInterfaces - } - } - fragment nonIntersectingInterfaces on Pet { - ...sentientFragment - } - fragment sentientFragment on Sentient { - name - }`, - Fragments(), Invalid) - }) - }) - }) - }) - }) - t.Run("5.6 Values", func(t *testing.T) { - t.Run("5.6.1 Values of Correct Type", func(t *testing.T) { - t.Run("valid ID arguments", func(t *testing.T) { - t.Run("ID as arg given as string", func(t *testing.T) { - runWithDefinition(t, countriesDefinition, `{ - country(code: "DE") { - code - name - } - }`, - Values(), Valid) - }) - t.Run("ID as arg given as integer", func(t *testing.T) { - runWithDefinition(t, countriesDefinition, `{ - country(code: 11) { - code - name - } - }`, - Values(), Valid) - }) - }) - - t.Run("valid custom scalar arguments", func(t *testing.T) { - - const testSchema = ` -scalar BigInt - -schema { - query: Query -} - -type Query { - add(a: BigInt!, b: BigInt!): BigInt! -} - -` - t.Run("BigInt as arg given as integer", func(t *testing.T) { - runWithDefinition(t, testSchema, `{ - add(a: 3000000000, b: 4000000000) - }`, - Values(), Valid) - }) - - t.Run("BigInt as arg given as string", func(t *testing.T) { - runWithDefinition(t, testSchema, `{ - add(a: "3000000000", b: "4000000000") - }`, - Values(), Valid) - }) - }) - - t.Run("145", func(t *testing.T) { - run(t, ` - query goodComplexDefaultValue($search: ComplexInput = { name: "Fido" }) { - findDog(complex: $search) - }`, - Values(), Valid) - run(t, ` - query goodComplexDefaultValue($search: ComplexInput = { name: "Fido" }) { - ...queryFragment - } - fragment queryFragment on Query { findDog(complex: $search) }`, - Values(), Valid) - run(t, ` - query goodComplexDefaultValue { - arguments { - booleanArgField(booleanArg: true) - } - }`, - Values(), Valid) - run(t, ` - query goodComplexDefaultValue() { - arguments { - floatArgField(floatArg: 123) - } - }`, - Values(), Valid) - run(t, ` - query goodComplexDefaultValue() { - arguments { - floatArgField(floatArg: 1.23) - } - }`, - Values(), Valid) - }) - t.Run("145 variant inline variable", func(t *testing.T) { - run(t, ` - query goodComplexDefaultValue($name: String = "Fido" ) { - findDog(complex: { name: $name }) - }`, - Values(), Valid) - }) - t.Run("145 variant variable non null into required field", func(t *testing.T) { - run(t, ` - query goodComplexDefaultValue($name: String ) { - findDogNonOptional(complex: { name: $name }) - }`, - Values(), Invalid, withValidationErrors(`Variable "$name" of type "String" used in position expecting type "String!"`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` - query goodComplexDefaultValue($search: ComplexInput = { name: 123 }) { - findDog(complex: $search) - }`, - Values(), Invalid, withDisableNormalization(), withValidationErrors(`String cannot represent a non string value: 123`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue($search: ComplexInput = { name: "123" }) { - findDog(complex: $search) - }`, - Values(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` query goodComplexDefaultValue { - findDog(complex: { name: 123 }) - }`, - Values(), Invalid, withValidationErrors(`String cannot represent a non string value: 123`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` query goodComplexDefaultValue { - findDog(complex: { name: "123" }) - }`, - Values(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` { - dog { - doesKnowCommand(dogCommand: SIT) - } - }`, - Values(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` { - dog { - doesKnowCommand(dogCommand: MEOW) - } - }`, - Values(), Invalid, withValidationErrors(`Value "MEOW" does not exist in "DogCommand" enum`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` { - dog { - doesKnowCommand(dogCommand: [true]) - } - }`, - Values(), Invalid, withValidationErrors(`Enum "DogCommand" cannot represent non-enum value: [true]`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, ` { - dog { - doesKnowCommand(dogCommand: {foo: "bar"}) - } - }`, - Values(), Invalid, withValidationErrors(`Enum "DogCommand" cannot represent non-enum value: {foo: "bar"}`)) - }) - t.Run("146", func(t *testing.T) { - run(t, ` - { - arguments { ...stringIntoInt } - } - fragment stringIntoInt on ValidArguments { - intArgField(intArg: "123") - }`, - Values(), Invalid, withValidationErrors(`Int cannot represent non-integer value: "123"`)) - run(t, ` - query badComplexValue { - findDog(complex: { name: 123 }) - }`, - Values(), Invalid, withValidationErrors(`String cannot represent a non string value: 123`)) - }) - t.Run("146 variant", func(t *testing.T) { - run(t, ` - query badComplexValue { - findDog(complex: { name: "123" }) - }`, - Values(), Valid) - }) - }) - t.Run("5.6.2 Input Object Field Names", func(t *testing.T) { - t.Run("147", func(t *testing.T) { - run(t, `{ - findDog(complex: { name: "Fido" }) - }`, - Values(), Valid) - }) - t.Run("148", func(t *testing.T) { - run(t, `{ - findDog(complex: { favoriteCookieFlavor: "Bacon" }) - }`, - Values(), Invalid, withValidationErrors(`Field "favoriteCookieFlavor" is not defined by type "ComplexInput"`)) - }) - }) - t.Run("5.6.3 Input Object Field Uniqueness", func(t *testing.T) { - t.Run("149", func(t *testing.T) { - run(t, `{ - findDog(complex: { name: "Fido", name: "Goofy"}) - }`, - Values(), Invalid, withValidationErrors(`There can be only one input field named "name"`)) - }) - }) - t.Run("5.6.4 Input Object Required Fields", func(t *testing.T) { - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue($search: ComplexNonOptionalInput = { name: "123" }) { - findDogNonOptional(complex: $search) - }`, - Values(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue($search: ComplexNonOptionalInput = { name: null }) { - findDogNonOptional(complex: $search) - }`, - Values(), Invalid, withDisableNormalization(), withValidationErrors(`Expected value of type "String!", found null`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue($search: ComplexNonOptionalInput = {}) { - findDogNonOptional(complex: $search) - }`, - Values(), Invalid, withDisableNormalization(), withValidationErrors(`Field "ComplexNonOptionalInput.name" of required type "String!" was not provided.`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue { - findDogNonOptional(complex: {}) - }`, - Values(), Invalid, withValidationErrors(`Field "ComplexNonOptionalInput.name" of required type "String!" was not provided.`)) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue { - findDogNonOptional(complex: { name: "Goofy" }) - }`, - Values(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue { - ...viaFragment - } - fragment viaFragment on Query { - findDogNonOptional(complex: { name: "Goofy" }) - }`, - Values(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query goodComplexDefaultValue { - ...viaFragment - } - fragment viaFragment on Query { - findDogNonOptional(complex: { name: 123 }) - }`, - Values(), Invalid, withValidationErrors(`String cannot represent a non string value: 123`)) - }) - }) - t.Run("complex nested validation", func(t *testing.T) { - t.Run("complex nested 1", func(t *testing.T) { - run(t, ` - { - nested(input: {}) - } - `, Values(), Invalid, withValidationErrors(`Field "NestedInput.requiredString" of required type "String!" was not provided.`)) - }) - t.Run("complex nested ok", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"] - }) - } - `, Values(), Valid) - }) - t.Run("complex nested 'notList' is not list of Strings should be ok with coersion", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: "notList", - requiredListOfRequiredStrings: ["str"] - }) - } - `, Values(), Valid) - }) - t.Run("complex nested ok 3", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: ["str"], - requiredListOfRequiredStrings: ["str"], - requiredListOfOptionalStringsWithDefault: ["more strings"] - }) - } - `, Values(), Valid) - }) - t.Run("complex nested ok optional list of nested input", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: ["str"], - requiredListOfRequiredStrings: ["str"], - requiredListOfOptionalStringsWithDefault: ["more strings"] - optionalListOfNestedInput: [ - { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"] - }, - { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"] - } - ] - }) - } - `, Values(), Valid) - }) - t.Run("complex nested ok optional list of nested input, required string missing", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: ["str"], - requiredListOfRequiredStrings: ["str"], - requiredListOfOptionalStringsWithDefault: ["more strings"] - optionalListOfNestedInput: [ - { - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"] - } - ] - }) - } - `, Values(), Invalid, withValidationErrors(`Field "NestedInput.requiredString" of required type "String!" was not provided.`)) - }) - t.Run("complex nested 'str' is not String", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: [str], - requiredListOfRequiredStrings: ["str"], - requiredListOfOptionalStringsWithDefault: ["more strings"] - }) - } - `, Values(), Invalid, withValidationErrors(`String cannot represent a non string value: str`)) - }) - t.Run("complex nested requiredListOfRequiredStrings could be empty but not `null` or `[null]`", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: [] - }) - } - `, Values(), Valid) - }) - t.Run("complex 2x nested", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"], - optionalNestedInput: { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"], - } - }) - } - `, Values(), Valid) - }) - t.Run("complex 2x nested required string missing", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"], - optionalNestedInput: { - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"], - } - }) - } - `, Values(), Invalid, withValidationErrors(`Field "NestedInput.requiredString" of required type "String!" was not provided.`)) - }) - t.Run("complex 2x nested '123' is no String", func(t *testing.T) { - run(t, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"], - optionalNestedInput: { - requiredString: "str", - requiredListOfOptionalStrings: [123], - requiredListOfRequiredStrings: ["str"], - } - }) - } - `, Values(), Invalid, withValidationErrors(`String cannot represent a non string value: 123`)) - }) - }) - }) - t.Run("5.7 Directives", func(t *testing.T) { - t.Run("5.7.1 Directives Are Defined", func(t *testing.T) { - t.Run("145 variant", func(t *testing.T) { - run(t, `query definedDirective { - arguments { - booleanArgField(booleanArg: true) @skip(if: true) - } - }`, - DirectivesAreDefined(), Valid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query undefinedDirective { - arguments { - booleanArgField(booleanArg: true) @noSkip(if: true) - } - }`, - DirectivesAreDefined(), Invalid) - }) - t.Run("145 variant", func(t *testing.T) { - run(t, `query undefinedDirective { - arguments { - ...viaFragment - } - } - fragment viaFragment on ValidArguments { - booleanArgField(booleanArg: true) @noSkip(if: true) - }`, - DirectivesAreDefined(), Invalid) - }) - }) - t.Run("5.7.2 Directives Are In Valid Locations", func(t *testing.T) { - t.Run("150 variant", func(t *testing.T) { - run(t, `query @skip(if: true) { - dog - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, `query { - dog @skip(if: true) - }`, - DirectivesAreInValidLocations(), Valid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` { - ... @inline { - dog - } - }`, - DirectivesAreInValidLocations(), Valid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` { - ... { - dog @inline - } - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - { - ...frag @spread - } - fragment frag on Query {}`, - DirectivesAreInValidLocations(), Valid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` { - ... { - dog @spread - } - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` { - ... { - dog @fragmentDefinition - } - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` { - ...frag - } - fragment frag on Query @fragmentDefinition {}`, - DirectivesAreInValidLocations(), Valid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` query @onQuery { - dog - }`, - DirectivesAreInValidLocations(), Valid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` query @onMutation { - dog - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` query @onSubscription { - dog - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - mutation @onQuery { - mutateDog - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - mutation @onSubscription { - mutateDog - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - mutation @onMutation { - mutateDog - }`, - DirectivesAreInValidLocations(), Valid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - subscription @onQuery { - subscribeDog - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - subscription @onMutation { - foo - }`, - DirectivesAreInValidLocations(), Invalid) - }) - t.Run("150 variant", func(t *testing.T) { - run(t, ` - subscription @onSubscription { - foo - }`, - DirectivesAreInValidLocations(), Valid) - }) - }) - t.Run("5.7.3 Directives Are Unique Per Location", func(t *testing.T) { - t.Run("151", func(t *testing.T) { - run(t, `query MyQuery($foo: Boolean = true, $bar: Boolean = false) { - field @skip(if: $foo) @skip(if: $bar) - }`, - DirectivesAreUniquePerLocation(), Invalid) - }) - t.Run("152", func(t *testing.T) { - run(t, `query MyQuery($foo: Boolean = true, $bar: Boolean = false) { - field @skip(if: $foo) { - subfieldA - } - field @skip(if: $bar) { - subfieldB - } - }`, - DirectivesAreUniquePerLocation(), Valid) - }) - }) - }) - t.Run("5.8 Variables", func(t *testing.T) { - t.Run("5.8.1 VariableValue Uniqueness", func(t *testing.T) { - t.Run("153", func(t *testing.T) { - run(t, `query houseTrainedQuery($atOtherHomes: Boolean, $atOtherHomes: Boolean) { - dog { - isHousetrained(atOtherHomes: $atOtherHomes) - } - }`, - VariableUniqueness(), Invalid) - }) - t.Run("154", func(t *testing.T) { - run(t, ` - query A($atOtherHomes: Boolean) { - ...HouseTrainedFragment - } - query B($atOtherHomes: Boolean) { - ...HouseTrainedFragment - } - fragment HouseTrainedFragment on Query { - dog { - isHousetrained(atOtherHomes: $atOtherHomes) - } - }`, - VariableUniqueness(), Valid) - }) - }) - t.Run("5.8.2 Variables Are Input Types", func(t *testing.T) { - t.Run("156", func(t *testing.T) { - run(t, ` - query takesBoolean($atOtherHomes: Boolean) { - dog { - isHousetrained(atOtherHomes: $atOtherHomes) - } - } - query takesComplexInput($complexInput: ComplexInput) { - findDog(complex: $complexInput) { - name - } - } - query TakesListOfBooleanBang($booleans: [Boolean!]) { - booleanList(booleanListArg: $booleans) - }`, - VariablesAreInputTypes(), Valid) - }) - t.Run("156", func(t *testing.T) { - run(t, `query TakesListOfBooleanBang($booleans: [Boolean!]) { - booleanList(booleanListArg: $booleans) - }`, - VariablesAreInputTypes(), Valid) - }) - t.Run("157", func(t *testing.T) { - run(t, `query takesCat($cat: Cat) {}`, - VariablesAreInputTypes(), Invalid) - run(t, `query takesDogBang($dog: Dog!) {}`, - VariablesAreInputTypes(), Invalid) - run(t, `query takesListOfPet($pets: [Pet]) {}`, - VariablesAreInputTypes(), Invalid) - run(t, `query takesCatOrDog($catOrDog: CatOrDog) {}`, - VariablesAreInputTypes(), Invalid) - run(t, `query takesCatOrDog($catCommand: CatCommand) {}`, - VariablesAreInputTypes(), Valid) - }) - }) - t.Run("5.8.3 All VariableValue Uses Defined", func(t *testing.T) { - t.Run("158", func(t *testing.T) { - run(t, `query variableIsDefined($atOtherHomes: Boolean) { - dog { - isHousetrained(atOtherHomes: $atOtherHomes) - } - }`, - AllVariableUsesDefined(), Valid) - }) - t.Run("159", func(t *testing.T) { - run(t, `query variableIsNotDefined { - dog { - isHousetrained(atOtherHomes: $atOtherHomes) - } - }`, - AllVariableUsesDefined(), Invalid) - }) - t.Run("160", func(t *testing.T) { - run(t, `query variableIsDefinedUsedInSingleFragment($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariableUsesDefined(), Valid) - }) - t.Run("161", func(t *testing.T) { - run(t, `query variableIsNotDefinedUsedInSingleFragment { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariableUsesDefined(), Invalid) - }) - t.Run("162", func(t *testing.T) { - run(t, `query variableIsNotDefinedUsedInNestedFragment { - dog { - ...outerHousetrainedFragment - } - } - fragment outerHousetrainedFragment on Dog { - ...isHousetrainedFragment - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariableUsesDefined(), Invalid) - t.Run("163", func(t *testing.T) { - run(t, `query housetrainedQueryOne($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - query housetrainedQueryTwo($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariableUsesDefined(), Valid) - }) - t.Run("164", func(t *testing.T) { - run(t, `query housetrainedQueryOne($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - query housetrainedQueryTwoNotDefined { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariableUsesDefined(), Invalid) - }) - }) - }) - t.Run("5.8.4 All Variables Used", func(t *testing.T) { - t.Run("165", func(t *testing.T) { - run(t, ` query variableUnused($name: String) { - findDog(complex: {name: $name}) - }`, - AllVariablesUsed(), Valid) - }) - t.Run("165 variant nested", func(t *testing.T) { - run(t, ` query variableUnused($name: String) { - findNestedDog(complex: {nested: {name: $name}}) - }`, - AllVariablesUsed(), Valid) - }) - t.Run("165 variant - input object type variable", func(t *testing.T) { - run(t, `query variableUnused($atOtherHomes: Boolean) { - dog { - isHousetrained - } - }`, - AllVariablesUsed(), Invalid) - }) - t.Run("165 variant", func(t *testing.T) { - run(t, `query variableUnused($x: Int!) { - arguments { - multipleReqs(x: $x, y: 1) - } - }`, - AllVariablesUsed(), Valid) - }) - t.Run("166", func(t *testing.T) { - run(t, `query variableUsedInFragment($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariablesUsed(), Valid) - }) - t.Run("167", func(t *testing.T) { - run(t, `query variableNotUsedWithinFragment($atOtherHomes: Boolean) { - dog { - ...isHousetrainedWithoutVariableFragment - } - } - fragment isHousetrainedWithoutVariableFragment on Dog { - isHousetrained - }`, - AllVariablesUsed(), Invalid) - }) - t.Run("168", func(t *testing.T) { - run(t, `query queryWithUsedVar($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - query queryWithExtraVar($atOtherHomes: Boolean, $extra: Int) { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, - AllVariablesUsed(), Invalid) - }) - t.Run("variables in array object", func(t *testing.T) { - runWithDefinition(t, todoSchema, `mutation AddTak($title: String!, $completed: Boolean!, $name: String! @fromClaim(name: "sub")) { - addTask(input: [{title: $title, completed: $completed, user: {name: $name}}]){ - task { - id - title - completed - } - } - }`, - AllVariablesUsed(), Valid) - }) - t.Run("variables in nested array object", func(t *testing.T) { - run(t, `query variableUnused($name: String) { - dog(where: { - AND: [ - { nestedDog: { nickname: { eq: "Scooby Doo" } } } - { nestedDog: { name: { eq: $name } } } - { - OR: [ - { - AND: [ - { - nestedDog: { - birthday: { eq: "2021-07-29" } - } - } - { - nestedDog: { barkVolume: { eq: 20 } } - } - ] - } - { - AND: [ - { - nestedDog: { - birthday: { eq: "2021-08-02" } - } - } - { - nestedDog: { barkVolume: { eq: 35 } } - } - ] - } - ] - } - ] - }) { - id - name - } - }`, - AllVariablesUsed(), Valid) - }) - }) - t.Run("5.8.5 All VariableValue Usages are Allowed", func(t *testing.T) { - t.Run("169", func(t *testing.T) { - run(t, `query intCannotGoIntoBoolean($intArg: Int) { - arguments { - booleanArgField(booleanArg: $intArg) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$intArg" of type "Int" used in position expecting type "Boolean".`)) - }) - t.Run("170", func(t *testing.T) { - run(t, `query booleanListCannotGoIntoBoolean($booleanListArg: [Boolean]) { - arguments { - booleanArgField(booleanArg: $booleanListArg) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$booleanListArg" of type "[Boolean]" used in position expecting type "Boolean".`)) - }) - t.Run("171", func(t *testing.T) { - run(t, `query booleanArgQuery($booleanArg: Boolean) { - arguments { - nonNullBooleanArgField(nonNullBooleanArg: $booleanArg) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$booleanArg" of type "Boolean" used in position expecting type "Boolean!".`)) - }) - // Non-null types are compatible with nullable types. - t.Run("172", func(t *testing.T) { - run(t, `query nonNullListToList($nonNullListOfBoolean: [Boolean]!) { - arguments { - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: $nonNullListOfBoolean) - } - }`, - ValidArguments(), Valid) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query listToList($listOfBoolean: [Boolean]) { - arguments { - listOfBooleanArgField(listOfBooleanArg: $listOfBoolean) - } - }`, - ValidArguments(), Valid) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query listOfNonNullToList($listOfNonNullBoolean: [Boolean!]) { - arguments { - listOfBooleanArgField(listOfBooleanArg: $listOfNonNullBoolean) - } - }`, - ValidArguments(), Valid) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query nonNullListOfNonNullToList($nonNullListOfNonNullBoolean: [Boolean!]!) { - arguments { - listOfBooleanArgField(listOfBooleanArg: $nonNullListOfNonNullBoolean) - } - }`, - ValidArguments(), Valid) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query nonNullListToListLiteral { - arguments { - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: [true,false,true]) - } - }`, - Values(), Valid) - }) - // Types in lists must match - t.Run("172 variant", func(t *testing.T) { - run(t, `query listContainingIncorrectType { - arguments { - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: [true,false,"123"]) - } - }`, - Values(), Invalid, withValidationErrors(`Boolean cannot represent a non boolean value: "123"`)) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query listContainingIncorrectType { - arguments { - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: [true,false,123]) - } - }`, - Values(), Invalid, withValidationErrors(`Boolean cannot represent a non boolean value: 123`)) - }) - // Nullable types are NOT compatible with non-null types. - t.Run("172 variant", func(t *testing.T) { - run(t, `query listToListOfNonNull($listOfBoolean: [Boolean]) { - arguments { - listOfNonNullBooleanArgField(listOfNonNullBooleanArg: $listOfBoolean) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$listOfBoolean" of type "[Boolean]" used in position expecting type "[Boolean!]"`)) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query nonNullListToListOfNonNull($nonNullListOfBoolean: [Boolean]!) { - arguments { - listOfNonNullBooleanArgField(listOfNonNullBooleanArg: $nonNullListOfBoolean) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$nonNullListOfBoolean" of type "[Boolean]!" used in position expecting type "[Boolean!]"`)) - }) - t.Run("172 variant", func(t *testing.T) { - run(t, `query listOfNonNullToNonNullList($listOfNonNullBoolean: [Boolean!]) { - arguments { - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: $listOfNonNullBoolean) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$listOfNonNullBoolean" of type "[Boolean!]" used in position expecting type "[Boolean]!"`)) - }) - t.Run("173", func(t *testing.T) { - run(t, `query listToNonNullList($listOfBoolean: [Boolean]) { - arguments { - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: $listOfBoolean) - } - }`, - ValidArguments(), Invalid, withValidationErrors(`Variable "$listOfBoolean" of type "[Boolean]" used in position expecting type "[Boolean]!"`)) - }) - t.Run("174", func(t *testing.T) { - run(t, `query booleanArgQueryWithDefault($booleanArg: Boolean) { - arguments { - nonNullBooleanWithDefaultArgField(nonNullBooleanWithDefaultArg: $booleanArg) - } - }`, - ValidArguments(), Valid) - }) - t.Run("175", func(t *testing.T) { - run(t, `query booleanArgQueryWithDefault($booleanArg: Boolean = true) { - arguments { - nonNullBooleanArgField(nonNullBooleanArg: $booleanArg) - } - }`, - ValidArguments(), Valid, withDisableNormalization()) - }) - t.Run("complex values", func(t *testing.T) { - runWithDefinition(t, wundergraphSchema, ` - query FirstNamespace($id: String $mode: QueryMode) { - findFirstnamespace(where: {id: {equals: $id mode: $mode}}) { - id - name - api { - id - name - created_at - } - } - } - `, ValidArguments(), Valid) - }) - t.Run("complex values", func(t *testing.T) { - runWithDefinition(t, wundergraphSchema, ` - query FirstNamespace($id: String $mode: QueryMode) { - findFirstnamespace(where: {id: {equals: $id mode: $mode}}) { - id - name - api { - id - name - created_at - } - } - } - `, Values(), Valid) - }) - t.Run("complex values with input object", func(t *testing.T) { - runWithDefinition(t, wundergraphSchema, ` - query FirstAPI($a: String $b: StringFilter) { - findFirstapi(where: {id: {equals: $a} AND: {name: $b}}) { - id - name - namespace { - id - name - } - } - } - `, Values(), Valid) - }) - t.Run("with boolean input", func(t *testing.T) { - runWithDefinition(t, wundergraphSchema, ` - query QueryWithBooleanInput($a: Boolean) { - findFirstnodepool( - where: { shared: { equals: $a } } - ) { - id - } - } - `, Values(), Valid) - }) - t.Run("with nested boolean where clause", func(t *testing.T) { - runWithDefinition(t, wundergraphSchema, ` - query QueryWithNestedBooleanClause($a: String) { - findFirstnodepool( - where: { id: { equals: $a }, AND: { shared: { equals: true } } } - ) { - id - } - } - `, Values(), Valid) - }) - t.Run("with variables inside an input object", func(t *testing.T) { - runWithDefinition(t, wundergraphSchema, ` - query QueryWithNestedBooleanClause($a: String, $b: Boolean) { - findFirstnodepool( - where: { id: { equals: $b }, AND: { shared: { equals: $a } } } - ) { - id - } - } - `, Values(), Invalid, - withValidationErrors( - `Variable "$a" of type "String" used in position expecting type "Boolean"`, - `Variable "$b" of type "Boolean" used in position expecting type "String"`, - )) - }) - - t.Run("with variables inside an input object", func(t *testing.T) { - run(t, ` - query booleanIntoStringList($a: Boolean) { - findDog(complex: {optionalListOfOptionalStrings: $a}) { - id - } - } - `, Values(), Invalid, - withValidationErrors( - `Variable "$a" of type "Boolean" used in position expecting type "[String]"`, - )) - }) - }) - }) -} - -func TestValidationEdgeCases(t *testing.T) { - run := func(definition, operation string, withNormalization bool) func(t *testing.T) { - return func(t *testing.T) { - op := unsafeparser.ParseGraphqlDocumentString(operation) - def := unsafeparser.ParseGraphqlDocumentString(definition) - - if withNormalization { - report := operationreport.Report{} - normalizer := astnormalization.NewWithOpts( - astnormalization.WithExtractVariables(), - astnormalization.WithRemoveFragmentDefinitions(), - astnormalization.WithRemoveUnusedVariables(), - astnormalization.WithNormalizeDefinition(), - ) - normalizer.NormalizeOperation(&op, &def, &report) - if report.HasErrors() { - panic(report.Error()) - } - } - - validator := DefaultOperationValidator() - var report operationreport.Report - validator.Validate(&op, &def, &report) - if report.HasErrors() { - t.Fatal(report.Error()) - } - } - } - - t.Run("validation with typename", run( - ` - schema { - query: Query - } - type Query { - api(id: String): ApiResult - } - union ApiResult = Api | RequestResult - type Api { - id: String - name: String - } - type RequestResult { - status: String - message: String - } - scalar String - `, - ` - query getApi($id: String!) { - api(id: $id) { - __typename - ... on Api { - __typename - id - name - } - ... on RequestResult { - __typename - status - message - } - } - }`, false, - )) - - t.Run("validation for normalized federation schema", run( - ` - scalar _Any - scalar String - union _Entity = User - - extend type Query { - _entities(representations: [_Any!]!): [_Entity]! - } - - extend type Query { - me: User! - } - - extend type User { - name: String! - }`, - ` - query($representations: [_Any!]!) { - _entities(representations: $representations) { - ... on User { - name - } - } - }`, true, - )) -} - -func BenchmarkValidation(b *testing.B) { - must := func(err error) { - if err != nil { - panic(err) - } - } - - mustDocument := func(doc ast.Document, report operationreport.Report) ast.Document { - if report.HasErrors() { - must(report) - } - return doc - } - - run := func(b *testing.B, definition, operation string, state ValidationState) { - op, def := mustDocument(astparser.ParseGraphqlDocumentString(operation)), mustDocument(astparser.ParseGraphqlDocumentString(definition)) - report := operationreport.Report{} - astnormalization.NormalizeOperation(&op, &def, &report) - if report.HasErrors() { - panic(report.Error()) - } - - validator := DefaultOperationValidator() - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - report.Reset() - out := validator.Validate(&op, &def, &report) - if out != state { - panic(fmt.Errorf("want state: %s, got: %s, reason: %s", state, out, report.Error())) - } - } - } - - b.Run("simple query", func(b *testing.B) { - run(b, testDefinition, ` - query getDogName { - dog { - name - } - } - query getOwnerName { - dog { - owner { - name - } - } - }`, Valid) - }) - b.Run("complex", func(b *testing.B) { - run(b, testDefinition, ` - query housetrainedQueryOne($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - query housetrainedQueryTwo($atOtherHomes: Boolean) { - dog { - ...isHousetrainedFragment - } - } - fragment isHousetrainedFragment on Dog { - isHousetrained(atOtherHomes: $atOtherHomes) - }`, Valid) - }) - b.Run("nested", func(b *testing.B) { - run(b, testDefinition, ` - { - nested(input: { - requiredString: "str", - requiredListOfOptionalStrings: ["str"], - requiredListOfRequiredStrings: ["str"], - requiredListOfOptionalStringsWithDefault: ["more strings"] - optionalListOfNestedInput: [ - { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"] - }, - { - requiredString: "str", - requiredListOfOptionalStrings: [], - requiredListOfRequiredStrings: ["str"] - } - ] - }) - }`, Valid) - }) - b.Run("args", func(b *testing.B) { - run(b, testDefinition, ` - { - arguments { ...stringIntoInt } - } - fragment stringIntoInt on ValidArguments { - intArgField(intArg: "123") - }`, Invalid) - }) - b.Run("interfaces", func(b *testing.B) { - run(b, testDefinition, ` - query conflictingDifferingResponses { - catOrDog { - ...catDogFrag - } - } - fragment catDogFrag on CatOrDog { - ...catFrag - ...dogFrag - } - fragment catFrag on Cat { - someValue: meowVolume - } - fragment dogFrag on Dog { - someValue: barkVolume - }`, Valid) - }) - b.Run("union", func(b *testing.B) { - run(b, testDefinition, ` - fragment inDirectFieldSelectionOnUnion on CatOrDog { - __typename - ... on Pet { - name - } - ... on Dog { - nickname - } - }`, Invalid) - }) - b.Run("nested object", func(b *testing.B) { - run(b, nexusSchema, ` - mutation ($drawDate: AWSDate!, $pick: [String!]!) { - AddTicket: addCartItem( - item: { - drawDate: $drawDate - fractional: false - play: { - pick: $pick - } - quantity: 1 - regionGameId: "lucky7|UAE" - } - ) { - id - } - }`, Valid) - }) - b.Run("nested object wrong type", func(b *testing.B) { - run(b, nexusSchema, ` - mutation ($drawDate: AWSDate!, $pick: [Int!]!) { - AddTicket: addCartItem( - item: { - drawDate: $drawDate - fractional: false - play: { - pick: $pick - } - quantity: 1 - regionGameId: "lucky7|UAE" - } - ) { - id - } - }`, Invalid) - }) - b.Run("nested object not optional", func(b *testing.B) { - run(b, nexusSchema, ` - mutation ($drawDate: AWSDate!, $pick: [String]!) { - AddTicket: addCartItem( - item: { - drawDate: $drawDate - fractional: false - play: { - pick: $pick - } - quantity: 1 - regionGameId: "lucky7|UAE" - } - ) { - id - } - }`, Invalid) - }) - b.Run("nested object not optional list", func(b *testing.B) { - run(b, nexusSchema, ` - mutation ($drawDate: AWSDate!, $pick: [String!]) { - AddTicket: addCartItem( - item: { - drawDate: $drawDate - fractional: false - play: { - pick: $pick - } - quantity: 1 - regionGameId: "lucky7|UAE" - } - ) { - id - } - }`, Invalid) - }) - b.Run("introspection", func(b *testing.B) { - run(b, testDefinition, `query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - kind - name - description - fields(includeDeprecated: true){ - name - description - args { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - isDeprecated - deprecationReason - } - inputFields { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - interfaces { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - enumValues(includeDeprecated: true){ - name - description - isDeprecated - deprecationReason - } - possibleTypes { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - } - directives { - name - description - locations - args { - name - description - type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - } - defaultValue - } - } - } - }`, Valid) - }) -} - -var testDefinition = ` -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Message { - sender: String - body: String -} - -type Subscription { - subscribeDog: Dog - newMessage: Message - foo: String - bar: String - disallowedSecondRootField: Boolean -} - -type Mutation { - mutateDog: Dog -} - -input ComplexInput { name: String, owner: String, optionalListOfOptionalStrings: [String]} -input ComplexNestedInput { complex: ComplexInput } -input ComplexNonOptionalInput { name: String! } - -input NestedInput { - requiredString: String! - requiredStringWithDefault: String! = "defaultString" - optionalListOfOptionalStrings: [String] - requiredListOfOptionalStrings: [String]! - requiredListOfOptionalStringsWithDefault: [String]! = [] - requiredListOfRequiredStrings: [String!]! - optionalNestedInput: NestedInput - optionalListOfNestedInput: [NestedInput] -} - -type Field { - subfieldA: String - subfieldB: String - deepField: DeepField - a: String - b: String - c: String - d: String -} - -type DeepField { - a: String - b: String - y: String - deeperField: DeepField -} - -type T { - deepField: DeepField - a: String - b: String - c: String - d: String -} - -type Query { - __schema: __Schema! - f1: Field - f2: Field - f3: Field - a: String! - b: String! - field: Field - foo: String - bar: String - human: Human - pet: Pet - dog: Dog - cat: Cat - catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien - arguments: ValidArguments - findDog(complex: ComplexInput): Dog - findNestedDog(complex: ComplexNestedInput): Dog - findDogNonOptional(complex: ComplexNonOptionalInput): Dog - booleanList(booleanListArg: [Boolean!]): Boolean - extra: Extra - nested(input: NestedInput): Boolean - args: Arguments -} - -type Arguments { - requiredString(s: String!): String! - requiredFloat(f: Float!): Float! -} - -type ValidArguments { - multipleReqs(x: Int!, y: Int!): Int! - floatArgField(floatArg: Float): Float - intArgField(intArg: Int): Int - booleanArgField(booleanArg: Boolean): String - nonNullBooleanArgField(nonNullBooleanArg: Boolean!): String - listOfBooleanArgField(listOfBooleanArg: [Boolean]): String - listOfNonNullBooleanArgField(listOfNonNullBooleanArg: [Boolean!]): String - nonNullListOfBooleanArgField(nonNullListOfBooleanArg: [Boolean]!): String - nonNullListOfNonNullBooleanArgField(nonNullListOfNonNullBooleanArg: [Boolean!]!): String - nonNullBooleanWithDefaultArgField(nonNullBooleanWithDefaultArg: Boolean! = false): String -} - -enum DogCommand { SIT, DOWN, HEEL } - -type Dog implements Pet { - id: ID - name: String! - nickname: String! - barkVolume: Int - doesKnowCommand(dogCommand: DogCommand!): Boolean! - isHousetrained(atOtherHomes: Boolean): Boolean! - owner: Human - extra: DogExtra - extras: [DogExtra] - mustExtra: DogExtra! - mustExtras: [DogExtra]! - mustMustExtras: [DogExtra!]! -} - -type DogExtra { - string: String - string1: String - string2: String - string3: String - noString: Boolean - strings: [String] - mustStrings: [String]! - bool: Int -} - -interface Sentient { - name: String! -} - -interface Pet { - name: String! -} - -type Alien implements Sentient { - name: String! - homePlanet: String -} - -type Human implements Sentient { - name: String! -} - -enum CatCommand { JUMP } - -type Cat implements Pet { - name: String! - nickname: String! - doesKnowCommand(catCommand: CatCommand!): Boolean! - meowVolume: Int - extra: CatExtra -} - -type CatExtra { - string: String - string2: String - strings: [String] - mustStrings: [String]! - bool: Boolean -} - -union CatOrDog = Cat | Dog -union DogOrHuman = Dog | Human -union HumanOrAlien = Human | Alien -union Extra = CatExtra | DogExtra - -directive @inline on INLINE_FRAGMENT -directive @spread on FRAGMENT_SPREAD -directive @fragmentDefinition on FRAGMENT_DEFINITION -directive @onQuery on QUERY -directive @onMutation on MUTATION -directive @onSubscription on SUBSCRIPTION - -"The Int scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The Float scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The String scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The Boolean scalar type represents true or false ." -scalar Boolean -"The ID scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as 4) or integer (such as 4) input value will be accepted as an ID." -scalar ID @custom(typeName: "string") -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of FieldSelections, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""ValidArguments provided to FieldSelections or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the __TypeKind enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given __Type is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. fields and interfaces are valid fields." - OBJECT - "Indicates this type is an interface. fields and possibleTypes are valid fields." - INTERFACE - "Indicates this type is a union. possibleTypes is a valid field." - UNION - "Indicates this type is an enum. enumValues is a valid field." - ENUM - "Indicates this type is an input object. inputFields is a valid field." - INPUT_OBJECT - "Indicates this type is a list. ofType is a valid field." - LIST - "Indicates this type is a non-null. ofType is a valid field." - NON_NULL -}` - -const boxDefinition = ` -scalar String -scalar ID -scalar Int -interface SomeBox { - scalar: String - deepBox: SomeBox - unrelatedField: String -} -type StringBox implements SomeBox { - scalar: String - deepBox: StringBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox -} -type IntBox implements SomeBox { - scalar: Int - deepBox: IntBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox -} -interface NonNullStringBox1 { - scalar: String! -} -type NonNullStringBox1Impl implements SomeBox & NonNullStringBox1 { - scalar: String! - unrelatedField: String - deepBox: SomeBox -} -interface NonNullStringBox2 { - scalar: String! -} -type NonNullStringBox2Impl implements SomeBox & NonNullStringBox2 { - scalar: String! - unrelatedField: String - deepBox: SomeBox -} -type Connection { - edges: [Edge] -} -type Edge { - node: Node -} -type Node { - id: ID - name: String -} -type Query { - someBox: SomeBox - connection: Connection -} -schema { - query: Query -}` - -const countriesDefinition = `directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT | INTERFACE - -scalar String -scalar ID -scalar Boolean - -schema { - query: Query -} - -enum CacheControlScope { - PUBLIC - PRIVATE -} - -type Continent { - code: ID! - name: String! - countries: [Country!]! -} - -input ContinentFilterInput { - code: StringQueryOperatorInput -} - -type Country { - code: ID! - name: String! - native: String! - phone: String! - continent: Continent! - capital: String - currency: String - languages: [Language!]! - emoji: String! - emojiU: String! - states: [State!]! -} - -input CountryFilterInput { - code: StringQueryOperatorInput - currency: StringQueryOperatorInput - continent: StringQueryOperatorInput -} - -type Language { - code: ID! - name: String - native: String - rtl: Boolean! -} - -input LanguageFilterInput { - code: StringQueryOperatorInput -} - -type Query { - continents(filter: ContinentFilterInput): [Continent!]! - continent(code: ID!): Continent - countries(filter: CountryFilterInput): [Country!]! - country(code: ID!): Country - languages(filter: LanguageFilterInput): [Language!]! - language(code: ID!): Language -} - -type State { - code: String - name: String! - country: Country! -} - -input StringQueryOperatorInput { - eq: String - ne: String - in: [String] - nin: [String] - regex: String - glob: String -} - -"""The Upload scalar type represents a file upload.""" -scalar Upload -` - -const todoSchema = ` - -schema { - query: Query - mutation: Mutation -} - -scalar ID -scalar String -scalar Boolean - -"""""" -scalar DateTime - -"""""" -enum DgraphIndex { - """""" - int - """""" - float - """""" - bool - """""" - hash - """""" - exact - """""" - term - """""" - fulltext - """""" - trigram - """""" - regexp - """""" - year - """""" - month - """""" - day - """""" - hour -} - -"""""" -input DateTimeFilter { - """""" - eq: DateTime - """""" - le: DateTime - """""" - lt: DateTime - """""" - ge: DateTime - """""" - gt: DateTime -} - -"""""" -input StringHashFilter { - """""" - eq: String -} - -"""""" -type UpdateTaskPayload { - """""" - task(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - numUids: Int -} - -"""""" -type Subscription { - """""" - getTask(id: ID!): Task - """""" - queryTask(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - getUser(username: String!): User - """""" - queryUser(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] -} - -"""""" -input FloatFilter { - """""" - eq: Float - """""" - le: Float - """""" - lt: Float - """""" - ge: Float - """""" - gt: Float -} - -"""""" -input StringTermFilter { - """""" - allofterms: String - """""" - anyofterms: String -} - -"""""" -type DeleteTaskPayload { - """""" - task(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - msg: String - """""" - numUids: Int -} - -"""""" -type Mutation { - """""" - addTask(input: [AddTaskInput!]!): AddTaskPayload - """""" - updateTask(input: UpdateTaskInput!): UpdateTaskPayload - """""" - deleteTask(filter: TaskFilter!): DeleteTaskPayload - """""" - addUser(input: [AddUserInput!]!): AddUserPayload - """""" - updateUser(input: UpdateUserInput!): UpdateUserPayload - """""" - deleteUser(filter: UserFilter!): DeleteUserPayload -} - -"""""" -enum HTTPMethod { - """""" - GET - """""" - POST - """""" - PUT - """""" - PATCH - """""" - DELETE -} - -"""""" -type DeleteUserPayload { - """""" - user(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] - """""" - msg: String - """""" - numUids: Int -} - -"""""" -input TaskFilter { - """""" - id: [ID!] - """""" - title: StringFullTextFilter - """""" - completed: Boolean - """""" - and: TaskFilter - """""" - or: TaskFilter - """""" - not: TaskFilter -} - -"""""" -type UpdateUserPayload { - """""" - user(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] - """""" - numUids: Int -} - -"""""" -input TaskRef { - """""" - id: ID - """""" - title: String - """""" - completed: Boolean - """""" - user: UserRef -} - -"""""" -input UserFilter { - """""" - username: StringHashFilter - """""" - name: StringExactFilter - """""" - and: UserFilter - """""" - or: UserFilter - """""" - not: UserFilter -} - -"""""" -input UserOrder { - """""" - asc: UserOrderable - """""" - desc: UserOrderable - """""" - then: UserOrder -} - -"""""" -input AuthRule { - """""" - and: [AuthRule] - """""" - or: [AuthRule] - """""" - not: AuthRule - """""" - rule: String -} - -"""""" -type AddTaskPayload { - """""" - task(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - numUids: Int -} - -"""""" -type AddUserPayload { - """""" - user(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] - """""" - numUids: Int -} - -"""""" -type Task { - """""" - id: ID! - """""" - title: String! - """""" - completed: Boolean! - """""" - user(filter: UserFilter): User! -} - -"""""" -input IntFilter { - """""" - eq: Int - """""" - le: Int - """""" - lt: Int - """""" - ge: Int - """""" - gt: Int -} - -"""""" -input StringExactFilter { - """""" - eq: String - """""" - le: String - """""" - lt: String - """""" - ge: String - """""" - gt: String -} - -"""""" -enum UserOrderable { - """""" - username - """""" - name -} - -"""""" -input AddTaskInput { - """""" - title: String! - """""" - completed: Boolean! - """""" - user: UserRef! -} - -"""""" -input TaskPatch { - """""" - title: String - """""" - completed: Boolean - """""" - user: UserRef -} - -"""""" -input UserRef { - """""" - username: String - """""" - name: String - """""" - tasks: [TaskRef] -} - -"""""" -input StringFullTextFilter { - """""" - alloftext: String - """""" - anyoftext: String -} - -"""""" -enum TaskOrderable { - """""" - title -} - -"""""" -input UpdateTaskInput { - """""" - filter: TaskFilter! - """""" - set: TaskPatch - """""" - remove: TaskPatch -} - -"""""" -input UserPatch { - """""" - name: String - """""" - tasks: [TaskRef] -} - -"""""" -type Query { - """""" - getTask(id: ID!): Task - """""" - queryTask(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - getUser(username: String!): User - """""" - queryUser(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] -} - -"""""" -type User { - """""" - username: String! - """""" - name: String - """""" - tasks(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] -} - -"""""" -enum Mode { - """""" - BATCH - """""" - SINGLE -} - -"""""" -input CustomHTTP { - """""" - url: String! - """""" - method: HTTPMethod! - """""" - body: String - """""" - graphql: String - """""" - mode: Mode - """""" - forwardHeaders: [String!] - """""" - secretHeaders: [String!] - """""" - introspectionHeaders: [String!] - """""" - skipIntrospection: Boolean -} - -"""""" -input StringRegExpFilter { - """""" - regexp: String -} - -"""""" -input AddUserInput { - """""" - username: String! - """""" - name: String - """""" - tasks: [TaskRef] -} - -"""""" -input TaskOrder { - """""" - asc: TaskOrderable - """""" - desc: TaskOrderable - """""" - then: TaskOrder -} - -"""""" -input UpdateUserInput { - """""" - filter: UserFilter! - """""" - set: UserPatch - """""" - remove: UserPatch -} -""" -The @cache directive caches the response server side and sets cache control headers according to the configuration. -With this setting you can reduce the load on your backend systems for operations that get hit a lot while data doesn't change that frequently. -""" -directive @cache( - """maxAge defines the maximum time in seconds a response will be understood 'fresh', defaults to 300 (5 minutes)""" - maxAge: Int! = 300 - """ - vary defines the headers to append to the cache key - In addition to all possible headers you can also select a custom claim for authenticated requests - Examples: 'jwt.sub', 'jwt.team' to vary the cache key based on 'sub' or 'team' fields on the jwt. - """ - vary: [String]! = [] -) on QUERY - -"""The @auth directive lets you configure auth for a given operation""" -directive @auth( - """disable explicitly disables authentication for the annotated operation""" - disable: Boolean! = false -) on QUERY | MUTATION | SUBSCRIPTION - -"""The @fromClaim directive overrides a variable from a select claim in the jwt""" -directive @fromClaim( - """ - name is the name of the claim you want to use for the variable - examples: sub, team, custom.nested.claim - """ - name: String! -) on VARIABLE_DEFINITION -` - -const wundergraphSchema = ` - -schema { - query: Query - mutation: Mutation -} - -scalar String -scalar Boolean - -enum QueryMode { - default - insensitive -} - -input NestedStringFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringFilter -} - -input StringFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - mode: QueryMode - not: NestedStringFilter -} - -input NestedDateTimeFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeFilter -} - -input DateTimeFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeFilter -} - -input NestedStringNullableFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableFilter -} - -input StringNullableFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - mode: QueryMode - not: NestedStringNullableFilter -} - -enum user_role { - user - admin -} - -input Enumuser_roleFilter { - equals: user_role - in: [user_role] - notIn: [user_role] - not: user_role -} - -input NestedDateTimeNullableFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeNullableFilter -} - -input DateTimeNullableFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeNullableFilter -} - -input Access_tokenListRelationFilter { - every: access_tokenWhereInput - some: access_tokenWhereInput - none: access_tokenWhereInput -} - -enum membership { - owner - maintainer - viewer - guest -} - -input EnummembershipFilter { - equals: membership - in: [membership] - notIn: [membership] - not: membership -} - -input NestedIntFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: NestedIntFilter -} - -input IntFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: NestedIntFilter -} - -input NestedBoolFilter { - equals: Boolean - not: NestedBoolFilter -} - -input BoolFilter { - equals: Boolean - not: NestedBoolFilter -} - -input NamespaceListRelationFilter { - every: namespaceWhereInput - some: namespaceWhereInput - none: namespaceWhereInput -} - -input price_planWhereInput { - AND: price_planWhereInput - OR: [price_planWhereInput] - NOT: price_planWhereInput - id: IntFilter - name: StringFilter - quota_daily_requests: IntFilter - quota_environments: IntFilter - quota_members: IntFilter - quota_apis: IntFilter - allow_secondary_environments: BoolFilter - namespace: NamespaceListRelationFilter -} - -input Price_planRelationFilter { - is: price_planWhereInput - isNot: price_planWhereInput -} - -input JsonFilter { - equals: DateTime - not: DateTime -} - -input ApiRelationFilter { - is: apiWhereInput - isNot: apiWhereInput -} - -input DeploymentRelationFilter { - is: deploymentWhereInput - isNot: deploymentWhereInput -} - -input StringNullableListFilter { - equals: [String] - has: String - hasEvery: [String] - hasSome: [String] - isEmpty: Boolean -} - -input edgeWhereInput { - AND: edgeWhereInput - OR: [edgeWhereInput] - NOT: edgeWhereInput - id: StringFilter - name: StringFilter - location: StringFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - environment_edges: Environment_edgesListRelationFilter -} - -input EdgeRelationFilter { - is: edgeWhereInput - isNot: edgeWhereInput -} - -input environment_edgesWhereInput { - AND: environment_edgesWhereInput - OR: [environment_edgesWhereInput] - NOT: environment_edgesWhereInput - environment_id: StringFilter - edge_id: StringFilter - edge: EdgeRelationFilter - environment: EnvironmentRelationFilter -} - -input Environment_edgesListRelationFilter { - every: environment_edgesWhereInput - some: environment_edgesWhereInput - none: environment_edgesWhereInput -} - -input NodepoolListRelationFilter { - every: nodepoolWhereInput - some: nodepoolWhereInput - none: nodepoolWhereInput -} - -input wundernodeWhereInput { - AND: wundernodeWhereInput - OR: [wundernodeWhereInput] - NOT: wundernodeWhereInput - id: StringFilter - etag: StringFilter - config: JsonFilter - ipv4: StringNullableFilter - ipv6: StringNullableFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - nodepool: NodepoolListRelationFilter -} - -input WundernodeRelationFilter { - is: wundernodeWhereInput - isNot: wundernodeWhereInput -} - -input nodepoolWhereInput { - AND: nodepoolWhereInput - OR: [nodepoolWhereInput] - NOT: nodepoolWhereInput - id: StringFilter - wundernode_id: StringFilter - shared: BoolFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - wundernode: WundernodeRelationFilter - nodepool_environment: Nodepool_environmentListRelationFilter -} - -input NodepoolRelationFilter { - is: nodepoolWhereInput - isNot: nodepoolWhereInput -} - -input nodepool_environmentWhereInput { - AND: nodepool_environmentWhereInput - OR: [nodepool_environmentWhereInput] - NOT: nodepool_environmentWhereInput - nodepool_id: StringFilter - environment_id: StringFilter - environment: EnvironmentRelationFilter - nodepool: NodepoolRelationFilter -} - -input Nodepool_environmentListRelationFilter { - every: nodepool_environmentWhereInput - some: nodepool_environmentWhereInput - none: nodepool_environmentWhereInput -} - -input environmentWhereInput { - AND: environmentWhereInput - OR: [environmentWhereInput] - NOT: environmentWhereInput - id: StringFilter - name: StringFilter - namespace_id: StringFilter - primary_hostname: StringFilter - hostnames: StringNullableListFilter - primary: BoolFilter - namespace: NamespaceRelationFilter - deployment_environment: Deployment_environmentListRelationFilter - environment_edges: Environment_edgesListRelationFilter - nodepool_environment: Nodepool_environmentListRelationFilter -} - -input EnvironmentRelationFilter { - is: environmentWhereInput - isNot: environmentWhereInput -} - -input deployment_environmentWhereInput { - AND: deployment_environmentWhereInput - OR: [deployment_environmentWhereInput] - NOT: deployment_environmentWhereInput - deployment_id: StringFilter - environment_id: StringFilter - deployment: DeploymentRelationFilter - environment: EnvironmentRelationFilter -} - -input Deployment_environmentListRelationFilter { - every: deployment_environmentWhereInput - some: deployment_environmentWhereInput - none: deployment_environmentWhereInput -} - -input deploymentWhereInput { - AND: deploymentWhereInput - OR: [deploymentWhereInput] - NOT: deploymentWhereInput - id: StringFilter - api_id: StringFilter - name: StringFilter - config: JsonFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - api: ApiRelationFilter - deployment_environment: Deployment_environmentListRelationFilter -} - -input DeploymentListRelationFilter { - every: deploymentWhereInput - some: deploymentWhereInput - none: deploymentWhereInput -} - -input apiWhereInput { - AND: apiWhereInput - OR: [apiWhereInput] - NOT: apiWhereInput - id: StringFilter - namespace_id: StringFilter - name: StringFilter - markdown_description: StringFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - namespace: NamespaceRelationFilter - deployment: DeploymentListRelationFilter -} - -input ApiListRelationFilter { - every: apiWhereInput - some: apiWhereInput - none: apiWhereInput -} - -input EnvironmentListRelationFilter { - every: environmentWhereInput - some: environmentWhereInput - none: environmentWhereInput -} - -input namespaceWhereInput { - AND: namespaceWhereInput - OR: [namespaceWhereInput] - NOT: namespaceWhereInput - id: StringFilter - name: StringFilter - price_plan_id: IntFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - price_plan: Price_planRelationFilter - api: ApiListRelationFilter - environment: EnvironmentListRelationFilter - namespace_members: Namespace_membersListRelationFilter -} - -input NamespaceRelationFilter { - is: namespaceWhereInput - isNot: namespaceWhereInput -} - -input namespace_membersWhereInput { - AND: namespace_membersWhereInput - OR: [namespace_membersWhereInput] - NOT: namespace_membersWhereInput - user_id: StringFilter - namespace_id: StringFilter - membership: EnummembershipFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - namespace: NamespaceRelationFilter - users: UsersRelationFilter -} - -input Namespace_membersListRelationFilter { - every: namespace_membersWhereInput - some: namespace_membersWhereInput - none: namespace_membersWhereInput -} - -input usersWhereInput { - AND: usersWhereInput - OR: [usersWhereInput] - NOT: usersWhereInput - id: StringFilter - name: StringNullableFilter - email: StringFilter - role: Enumuser_roleFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - access_token: Access_tokenListRelationFilter - namespace_members: Namespace_membersListRelationFilter -} - -input UsersRelationFilter { - is: usersWhereInput - isNot: usersWhereInput -} - -input access_tokenWhereInput { - AND: access_tokenWhereInput - OR: [access_tokenWhereInput] - NOT: access_tokenWhereInput - id: StringFilter - token: StringFilter - user_id: StringFilter - name: StringFilter - created_at: DateTimeFilter - users: UsersRelationFilter -} - -enum SortOrder { - asc - desc -} - -input access_tokenOrderByInput { - id: SortOrder - token: SortOrder - user_id: SortOrder - name: SortOrder - created_at: SortOrder -} - -input access_tokenWhereUniqueInput { - id: String - token: String -} - -enum Access_tokenScalarFieldEnum { - id - token - user_id - name - created_at -} - -input namespace_membersOrderByInput { - user_id: SortOrder - namespace_id: SortOrder - membership: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input namespace_membersUser_idNamespace_idCompoundUniqueInput { - user_id: String! - namespace_id: String! -} - -input namespace_membersWhereUniqueInput { - user_id_namespace_id: namespace_membersUser_idNamespace_idCompoundUniqueInput -} - -enum Namespace_membersScalarFieldEnum { - user_id - namespace_id - membership - created_at - updated_at -} - -input namespaceOrderByInput { - id: SortOrder - name: SortOrder - price_plan_id: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input namespaceWhereUniqueInput { - id: String - name: String -} - -enum NamespaceScalarFieldEnum { - id - name - price_plan_id - created_at - updated_at -} - -type price_plan { - id: Int! - name: String! - quota_daily_requests: Int! - quota_environments: Int! - quota_members: Int! - quota_apis: Int! - allow_secondary_environments: Boolean! - namespace(where: namespaceWhereInput, orderBy: [namespaceOrderByInput], cursor: namespaceWhereUniqueInput, take: Int, skip: Int, distinct: [NamespaceScalarFieldEnum]): [namespace] -} - -input apiOrderByInput { - id: SortOrder - namespace_id: SortOrder - name: SortOrder - markdown_description: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input apiApi_namespace_id_name_keyCompoundUniqueInput { - namespace_id: String! - name: String! -} - -input apiWhereUniqueInput { - id: String - api_namespace_id_name_key: apiApi_namespace_id_name_keyCompoundUniqueInput -} - -enum ApiScalarFieldEnum { - id - namespace_id - name - markdown_description - created_at - updated_at -} - -input deploymentOrderByInput { - id: SortOrder - api_id: SortOrder - name: SortOrder - config: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input deploymentDeployment_api_id_name_keyCompoundUniqueInput { - api_id: String! - name: String! -} - -input deploymentWhereUniqueInput { - id: String - deployment_api_id_name_key: deploymentDeployment_api_id_name_keyCompoundUniqueInput -} - -enum DeploymentScalarFieldEnum { - id - api_id - name - config - created_at - updated_at -} - -input deployment_environmentOrderByInput { - deployment_id: SortOrder - environment_id: SortOrder -} - -input deployment_environmentDeployment_idEnvironment_idCompoundUniqueInput { - deployment_id: String! - environment_id: String! -} - -input deployment_environmentWhereUniqueInput { - deployment_id_environment_id: deployment_environmentDeployment_idEnvironment_idCompoundUniqueInput -} - -enum Deployment_environmentScalarFieldEnum { - deployment_id - environment_id -} - -input environment_edgesOrderByInput { - environment_id: SortOrder - edge_id: SortOrder -} - -input environment_edgesEnvironment_idEdge_idCompoundUniqueInput { - environment_id: String! - edge_id: String! -} - -input environment_edgesWhereUniqueInput { - environment_id_edge_id: environment_edgesEnvironment_idEdge_idCompoundUniqueInput -} - -enum Environment_edgesScalarFieldEnum { - environment_id - edge_id -} - -type edge { - id: String! - name: String! - location: String! - created_at: DateTime! - updated_at: DateTime - environment_edges(where: environment_edgesWhereInput, orderBy: [environment_edgesOrderByInput], cursor: environment_edgesWhereUniqueInput, take: Int, skip: Int, distinct: [Environment_edgesScalarFieldEnum]): [environment_edges] -} - -type environment_edges { - environment_id: String! - edge_id: String! - edge: edge! - environment: environment! -} - -input nodepool_environmentOrderByInput { - nodepool_id: SortOrder - environment_id: SortOrder -} - -input nodepool_environmentNodepool_idEnvironment_idCompoundUniqueInput { - nodepool_id: String! - environment_id: String! -} - -input nodepool_environmentWhereUniqueInput { - nodepool_id_environment_id: nodepool_environmentNodepool_idEnvironment_idCompoundUniqueInput -} - -enum Nodepool_environmentScalarFieldEnum { - nodepool_id - environment_id -} - -input nodepoolOrderByInput { - id: SortOrder - wundernode_id: SortOrder - shared: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input nodepoolWhereUniqueInput { - id: String -} - -enum NodepoolScalarFieldEnum { - id - wundernode_id - shared - created_at - updated_at -} - -type wundernode { - id: String! - etag: String! - config: Json! - ipv4: String - ipv6: String - created_at: DateTime! - updated_at: DateTime - nodepool(where: nodepoolWhereInput, orderBy: [nodepoolOrderByInput], cursor: nodepoolWhereUniqueInput, take: Int, skip: Int, distinct: [NodepoolScalarFieldEnum]): [nodepool] -} - -type nodepool { - id: String! - wundernode_id: String! - shared: Boolean! - created_at: DateTime! - updated_at: DateTime - wundernode: wundernode! - nodepool_environment(where: nodepool_environmentWhereInput, orderBy: [nodepool_environmentOrderByInput], cursor: nodepool_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Nodepool_environmentScalarFieldEnum]): [nodepool_environment] -} - -type nodepool_environment { - nodepool_id: String! - environment_id: String! - environment: environment! - nodepool: nodepool! -} - -type environment { - id: String! - name: String! - namespace_id: String! - primary_hostname: String! - hostnames: [String] - primary: Boolean! - namespace: namespace! - deployment_environment(where: deployment_environmentWhereInput, orderBy: [deployment_environmentOrderByInput], cursor: deployment_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Deployment_environmentScalarFieldEnum]): [deployment_environment] - environment_edges(where: environment_edgesWhereInput, orderBy: [environment_edgesOrderByInput], cursor: environment_edgesWhereUniqueInput, take: Int, skip: Int, distinct: [Environment_edgesScalarFieldEnum]): [environment_edges] - nodepool_environment(where: nodepool_environmentWhereInput, orderBy: [nodepool_environmentOrderByInput], cursor: nodepool_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Nodepool_environmentScalarFieldEnum]): [nodepool_environment] -} - -type deployment_environment { - deployment_id: String! - environment_id: String! - deployment: deployment! - environment: environment! -} - -type deployment { - id: String! - api_id: String! - name: String! - config: Json! - created_at: DateTime! - updated_at: DateTime - api: api! - deployment_environment(where: deployment_environmentWhereInput, orderBy: [deployment_environmentOrderByInput], cursor: deployment_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Deployment_environmentScalarFieldEnum]): [deployment_environment] -} - -type api { - id: String! - namespace_id: String! - name: String! - markdown_description: String! - created_at: DateTime! - updated_at: DateTime - namespace: namespace! - deployment(where: deploymentWhereInput, orderBy: [deploymentOrderByInput], cursor: deploymentWhereUniqueInput, take: Int, skip: Int, distinct: [DeploymentScalarFieldEnum]): [deployment] -} - -input environmentOrderByInput { - id: SortOrder - name: SortOrder - namespace_id: SortOrder - primary_hostname: SortOrder - hostnames: SortOrder - primary: SortOrder -} - -input environmentEnvironment_namespace_id_name_keyCompoundUniqueInput { - namespace_id: String! - name: String! -} - -input environmentWhereUniqueInput { - id: String - environment_namespace_id_name_key: environmentEnvironment_namespace_id_name_keyCompoundUniqueInput -} - -enum EnvironmentScalarFieldEnum { - id - name - namespace_id - primary_hostname - hostnames - primary -} - -type namespace { - id: String! - name: String! - price_plan_id: Int! - created_at: DateTime! - updated_at: DateTime - price_plan: price_plan! - api(where: apiWhereInput, orderBy: [apiOrderByInput], cursor: apiWhereUniqueInput, take: Int, skip: Int, distinct: [ApiScalarFieldEnum]): [api] - environment(where: environmentWhereInput, orderBy: [environmentOrderByInput], cursor: environmentWhereUniqueInput, take: Int, skip: Int, distinct: [EnvironmentScalarFieldEnum]): [environment] - namespace_members(where: namespace_membersWhereInput, orderBy: [namespace_membersOrderByInput], cursor: namespace_membersWhereUniqueInput, take: Int, skip: Int, distinct: [Namespace_membersScalarFieldEnum]): [namespace_members] -} - -type namespace_members { - user_id: String! - namespace_id: String! - membership: membership! - created_at: DateTime! - updated_at: DateTime - namespace: namespace! - users: users! -} - -type users { - id: String! - name: String - email: String! - role: user_role! - created_at: DateTime! - updated_at: DateTime - access_token(where: access_tokenWhereInput, orderBy: [access_tokenOrderByInput], cursor: access_tokenWhereUniqueInput, take: Int, skip: Int, distinct: [Access_tokenScalarFieldEnum]): [access_token] - namespace_members(where: namespace_membersWhereInput, orderBy: [namespace_membersOrderByInput], cursor: namespace_membersWhereUniqueInput, take: Int, skip: Int, distinct: [Namespace_membersScalarFieldEnum]): [namespace_members] -} - -type access_token { - id: String! - token: String! - user_id: String! - name: String! - created_at: DateTime! - users: users! -} - -type Access_tokenCountAggregateOutputType { - id: Int! - token: Int! - user_id: Int! - name: Int! - created_at: Int! -} - -type Access_tokenMinAggregateOutputType { - id: String - token: String - user_id: String - name: String - created_at: DateTime -} - -type Access_tokenMaxAggregateOutputType { - id: String - token: String - user_id: String - name: String - created_at: DateTime -} - -type AggregateAccess_token { - count: Access_tokenCountAggregateOutputType - min: Access_tokenMinAggregateOutputType - max: Access_tokenMaxAggregateOutputType -} - -input NestedStringWithAggregatesFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringWithAggregatesFilter - count: NestedIntFilter - min: NestedStringFilter - max: NestedStringFilter -} - -input StringWithAggregatesFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - mode: QueryMode - not: NestedStringWithAggregatesFilter - count: NestedIntFilter - min: NestedStringFilter - max: NestedStringFilter -} - -input NestedDateTimeWithAggregatesFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeWithAggregatesFilter - count: NestedIntFilter - min: NestedDateTimeFilter - max: NestedDateTimeFilter -} - -input DateTimeWithAggregatesFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeWithAggregatesFilter - count: NestedIntFilter - min: NestedDateTimeFilter - max: NestedDateTimeFilter -} - -input access_tokenScalarWhereWithAggregatesInput { - AND: access_tokenScalarWhereWithAggregatesInput - OR: [access_tokenScalarWhereWithAggregatesInput] - NOT: access_tokenScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - token: StringWithAggregatesFilter - user_id: StringWithAggregatesFilter - name: StringWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter -} - -type Access_tokenGroupByOutputType { - id: String! - token: String! - user_id: String! - name: String! - created_at: DateTime! - count: Access_tokenCountAggregateOutputType - min: Access_tokenMinAggregateOutputType - max: Access_tokenMaxAggregateOutputType -} - -input admin_configWhereInput { - AND: admin_configWhereInput - OR: [admin_configWhereInput] - NOT: admin_configWhereInput - id: StringFilter - wundernode_image_tag: StringFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input admin_configOrderByInput { - id: SortOrder - wundernode_image_tag: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input admin_configWhereUniqueInput { - id: String -} - -enum Admin_configScalarFieldEnum { - id - wundernode_image_tag - created_at - updated_at -} - -type admin_config { - id: String! - wundernode_image_tag: String! - created_at: DateTime! - updated_at: DateTime -} - -type Admin_configCountAggregateOutputType { - id: Int! - wundernode_image_tag: Int! - created_at: Int! - updated_at: Int! -} - -type Admin_configMinAggregateOutputType { - id: String - wundernode_image_tag: String - created_at: DateTime - updated_at: DateTime -} - -type Admin_configMaxAggregateOutputType { - id: String - wundernode_image_tag: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateAdmin_config { - count: Admin_configCountAggregateOutputType - min: Admin_configMinAggregateOutputType - max: Admin_configMaxAggregateOutputType -} - -input NestedIntNullableFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: NestedIntNullableFilter -} - -input NestedDateTimeNullableWithAggregatesFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeNullableWithAggregatesFilter - count: NestedIntNullableFilter - min: NestedDateTimeNullableFilter - max: NestedDateTimeNullableFilter -} - -input DateTimeNullableWithAggregatesFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: NestedDateTimeNullableWithAggregatesFilter - count: NestedIntNullableFilter - min: NestedDateTimeNullableFilter - max: NestedDateTimeNullableFilter -} - -input admin_configScalarWhereWithAggregatesInput { - AND: admin_configScalarWhereWithAggregatesInput - OR: [admin_configScalarWhereWithAggregatesInput] - NOT: admin_configScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - wundernode_image_tag: StringWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type Admin_configGroupByOutputType { - id: String! - wundernode_image_tag: String! - created_at: DateTime! - updated_at: DateTime - count: Admin_configCountAggregateOutputType - min: Admin_configMinAggregateOutputType - max: Admin_configMaxAggregateOutputType -} - -type ApiCountAggregateOutputType { - id: Int! - namespace_id: Int! - name: Int! - markdown_description: Int! - created_at: Int! - updated_at: Int! -} - -type ApiMinAggregateOutputType { - id: String - namespace_id: String - name: String - markdown_description: String - created_at: DateTime - updated_at: DateTime -} - -type ApiMaxAggregateOutputType { - id: String - namespace_id: String - name: String - markdown_description: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateApi { - count: ApiCountAggregateOutputType - min: ApiMinAggregateOutputType - max: ApiMaxAggregateOutputType -} - -input apiScalarWhereWithAggregatesInput { - AND: apiScalarWhereWithAggregatesInput - OR: [apiScalarWhereWithAggregatesInput] - NOT: apiScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - namespace_id: StringWithAggregatesFilter - name: StringWithAggregatesFilter - markdown_description: StringWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type ApiGroupByOutputType { - id: String! - namespace_id: String! - name: String! - markdown_description: String! - created_at: DateTime! - updated_at: DateTime - count: ApiCountAggregateOutputType - min: ApiMinAggregateOutputType - max: ApiMaxAggregateOutputType -} - -type DeploymentCountAggregateOutputType { - id: Int! - api_id: Int! - name: Int! - config: Int! - created_at: Int! - updated_at: Int! -} - -type DeploymentMinAggregateOutputType { - id: String - api_id: String - name: String - created_at: DateTime - updated_at: DateTime -} - -type DeploymentMaxAggregateOutputType { - id: String - api_id: String - name: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateDeployment { - count: DeploymentCountAggregateOutputType - min: DeploymentMinAggregateOutputType - max: DeploymentMaxAggregateOutputType -} - -input NestedJsonFilter { - equals: DateTime - not: DateTime -} - -input JsonWithAggregatesFilter { - equals: DateTime - not: DateTime - count: NestedIntFilter - min: NestedJsonFilter - max: NestedJsonFilter -} - -input deploymentScalarWhereWithAggregatesInput { - AND: deploymentScalarWhereWithAggregatesInput - OR: [deploymentScalarWhereWithAggregatesInput] - NOT: deploymentScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - api_id: StringWithAggregatesFilter - name: StringWithAggregatesFilter - config: JsonWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type DeploymentGroupByOutputType { - id: String! - api_id: String! - name: String! - config: Json! - created_at: DateTime! - updated_at: DateTime - count: DeploymentCountAggregateOutputType - min: DeploymentMinAggregateOutputType - max: DeploymentMaxAggregateOutputType -} - -type Deployment_environmentCountAggregateOutputType { - deployment_id: Int! - environment_id: Int! -} - -type Deployment_environmentMinAggregateOutputType { - deployment_id: String - environment_id: String -} - -type Deployment_environmentMaxAggregateOutputType { - deployment_id: String - environment_id: String -} - -type AggregateDeployment_environment { - count: Deployment_environmentCountAggregateOutputType - min: Deployment_environmentMinAggregateOutputType - max: Deployment_environmentMaxAggregateOutputType -} - -input deployment_environmentScalarWhereWithAggregatesInput { - AND: deployment_environmentScalarWhereWithAggregatesInput - OR: [deployment_environmentScalarWhereWithAggregatesInput] - NOT: deployment_environmentScalarWhereWithAggregatesInput - deployment_id: StringWithAggregatesFilter - environment_id: StringWithAggregatesFilter -} - -type Deployment_environmentGroupByOutputType { - deployment_id: String! - environment_id: String! - count: Deployment_environmentCountAggregateOutputType - min: Deployment_environmentMinAggregateOutputType - max: Deployment_environmentMaxAggregateOutputType -} - -input edgeOrderByInput { - id: SortOrder - name: SortOrder - location: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input edgeWhereUniqueInput { - id: String - name: String -} - -enum EdgeScalarFieldEnum { - id - name - location - created_at - updated_at -} - -type EdgeCountAggregateOutputType { - id: Int! - name: Int! - location: Int! - created_at: Int! - updated_at: Int! -} - -type EdgeMinAggregateOutputType { - id: String - name: String - location: String - created_at: DateTime - updated_at: DateTime -} - -type EdgeMaxAggregateOutputType { - id: String - name: String - location: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateEdge { - count: EdgeCountAggregateOutputType - min: EdgeMinAggregateOutputType - max: EdgeMaxAggregateOutputType -} - -input edgeScalarWhereWithAggregatesInput { - AND: edgeScalarWhereWithAggregatesInput - OR: [edgeScalarWhereWithAggregatesInput] - NOT: edgeScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - name: StringWithAggregatesFilter - location: StringWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type EdgeGroupByOutputType { - id: String! - name: String! - location: String! - created_at: DateTime! - updated_at: DateTime - count: EdgeCountAggregateOutputType - min: EdgeMinAggregateOutputType - max: EdgeMaxAggregateOutputType -} - -type EnvironmentCountAggregateOutputType { - id: Int! - name: Int! - namespace_id: Int! - primary_hostname: Int! - hostnames: Int! - primary: Int! -} - -type EnvironmentMinAggregateOutputType { - id: String - name: String - namespace_id: String - primary_hostname: String - primary: Boolean -} - -type EnvironmentMaxAggregateOutputType { - id: String - name: String - namespace_id: String - primary_hostname: String - primary: Boolean -} - -type AggregateEnvironment { - count: EnvironmentCountAggregateOutputType - min: EnvironmentMinAggregateOutputType - max: EnvironmentMaxAggregateOutputType -} - -input NestedBoolWithAggregatesFilter { - equals: Boolean - not: NestedBoolWithAggregatesFilter - count: NestedIntFilter - min: NestedBoolFilter - max: NestedBoolFilter -} - -input BoolWithAggregatesFilter { - equals: Boolean - not: NestedBoolWithAggregatesFilter - count: NestedIntFilter - min: NestedBoolFilter - max: NestedBoolFilter -} - -input environmentScalarWhereWithAggregatesInput { - AND: environmentScalarWhereWithAggregatesInput - OR: [environmentScalarWhereWithAggregatesInput] - NOT: environmentScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - name: StringWithAggregatesFilter - namespace_id: StringWithAggregatesFilter - primary_hostname: StringWithAggregatesFilter - hostnames: StringNullableListFilter - primary: BoolWithAggregatesFilter -} - -type EnvironmentGroupByOutputType { - id: String! - name: String! - namespace_id: String! - primary_hostname: String! - hostnames: [String] - primary: Boolean! - count: EnvironmentCountAggregateOutputType - min: EnvironmentMinAggregateOutputType - max: EnvironmentMaxAggregateOutputType -} - -type Environment_edgesCountAggregateOutputType { - environment_id: Int! - edge_id: Int! -} - -type Environment_edgesMinAggregateOutputType { - environment_id: String - edge_id: String -} - -type Environment_edgesMaxAggregateOutputType { - environment_id: String - edge_id: String -} - -type AggregateEnvironment_edges { - count: Environment_edgesCountAggregateOutputType - min: Environment_edgesMinAggregateOutputType - max: Environment_edgesMaxAggregateOutputType -} - -input environment_edgesScalarWhereWithAggregatesInput { - AND: environment_edgesScalarWhereWithAggregatesInput - OR: [environment_edgesScalarWhereWithAggregatesInput] - NOT: environment_edgesScalarWhereWithAggregatesInput - environment_id: StringWithAggregatesFilter - edge_id: StringWithAggregatesFilter -} - -type Environment_edgesGroupByOutputType { - environment_id: String! - edge_id: String! - count: Environment_edgesCountAggregateOutputType - min: Environment_edgesMinAggregateOutputType - max: Environment_edgesMaxAggregateOutputType -} - -input JsonNullableFilter { - equals: DateTime - not: DateTime -} - -input Letsencrypt_certificateListRelationFilter { - every: letsencrypt_certificateWhereInput - some: letsencrypt_certificateWhereInput - none: letsencrypt_certificateWhereInput -} - -input letsencrypt_userWhereInput { - AND: letsencrypt_userWhereInput - OR: [letsencrypt_userWhereInput] - NOT: letsencrypt_userWhereInput - zone: StringFilter - email: StringFilter - dns_provider_name: StringFilter - dns_provider_token: StringFilter - private_key: StringNullableFilter - registration_resource: JsonNullableFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - letsencrypt_certificate: Letsencrypt_certificateListRelationFilter -} - -input Letsencrypt_userRelationFilter { - is: letsencrypt_userWhereInput - isNot: letsencrypt_userWhereInput -} - -input letsencrypt_certificateWhereInput { - AND: letsencrypt_certificateWhereInput - OR: [letsencrypt_certificateWhereInput] - NOT: letsencrypt_certificateWhereInput - common_name: StringFilter - zone: StringFilter - additional_domains: StringNullableListFilter - issued: DateTimeNullableFilter - renewal: DateTimeNullableFilter - certificate: StringNullableFilter - private_key: StringNullableFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter - letsencrypt_user: Letsencrypt_userRelationFilter -} - -input letsencrypt_certificateOrderByInput { - common_name: SortOrder - zone: SortOrder - additional_domains: SortOrder - issued: SortOrder - renewal: SortOrder - certificate: SortOrder - private_key: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input letsencrypt_certificateWhereUniqueInput { - common_name: String -} - -enum Letsencrypt_certificateScalarFieldEnum { - common_name - zone - additional_domains - issued - renewal - certificate - private_key - created_at - updated_at -} - -type letsencrypt_user { - zone: String! - email: String! - dns_provider_name: String! - dns_provider_token: String! - private_key: String - registration_resource: Json - created_at: DateTime! - updated_at: DateTime - letsencrypt_certificate(where: letsencrypt_certificateWhereInput, orderBy: [letsencrypt_certificateOrderByInput], cursor: letsencrypt_certificateWhereUniqueInput, take: Int, skip: Int, distinct: [Letsencrypt_certificateScalarFieldEnum]): [letsencrypt_certificate] -} - -type letsencrypt_certificate { - common_name: String! - zone: String! - additional_domains: [String] - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime! - updated_at: DateTime - letsencrypt_user: letsencrypt_user! -} - -type Letsencrypt_certificateCountAggregateOutputType { - common_name: Int! - zone: Int! - additional_domains: Int! - issued: Int! - renewal: Int! - certificate: Int! - private_key: Int! - created_at: Int! - updated_at: Int! -} - -type Letsencrypt_certificateMinAggregateOutputType { - common_name: String - zone: String - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime - updated_at: DateTime -} - -type Letsencrypt_certificateMaxAggregateOutputType { - common_name: String - zone: String - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateLetsencrypt_certificate { - count: Letsencrypt_certificateCountAggregateOutputType - min: Letsencrypt_certificateMinAggregateOutputType - max: Letsencrypt_certificateMaxAggregateOutputType -} - -input NestedStringNullableWithAggregatesFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: NestedStringNullableWithAggregatesFilter - count: NestedIntNullableFilter - min: NestedStringNullableFilter - max: NestedStringNullableFilter -} - -input StringNullableWithAggregatesFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - mode: QueryMode - not: NestedStringNullableWithAggregatesFilter - count: NestedIntNullableFilter - min: NestedStringNullableFilter - max: NestedStringNullableFilter -} - -input letsencrypt_certificateScalarWhereWithAggregatesInput { - AND: letsencrypt_certificateScalarWhereWithAggregatesInput - OR: [letsencrypt_certificateScalarWhereWithAggregatesInput] - NOT: letsencrypt_certificateScalarWhereWithAggregatesInput - common_name: StringWithAggregatesFilter - zone: StringWithAggregatesFilter - additional_domains: StringNullableListFilter - issued: DateTimeNullableWithAggregatesFilter - renewal: DateTimeNullableWithAggregatesFilter - certificate: StringNullableWithAggregatesFilter - private_key: StringNullableWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type Letsencrypt_certificateGroupByOutputType { - common_name: String! - zone: String! - additional_domains: [String] - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime! - updated_at: DateTime - count: Letsencrypt_certificateCountAggregateOutputType - min: Letsencrypt_certificateMinAggregateOutputType - max: Letsencrypt_certificateMaxAggregateOutputType -} - -input letsencrypt_userOrderByInput { - zone: SortOrder - email: SortOrder - dns_provider_name: SortOrder - dns_provider_token: SortOrder - private_key: SortOrder - registration_resource: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input letsencrypt_userWhereUniqueInput { - zone: String -} - -enum Letsencrypt_userScalarFieldEnum { - zone - email - dns_provider_name - dns_provider_token - private_key - registration_resource - created_at - updated_at -} - -type Letsencrypt_userCountAggregateOutputType { - zone: Int! - email: Int! - dns_provider_name: Int! - dns_provider_token: Int! - private_key: Int! - registration_resource: Int! - created_at: Int! - updated_at: Int! -} - -type Letsencrypt_userMinAggregateOutputType { - zone: String - email: String - dns_provider_name: String - dns_provider_token: String - private_key: String - created_at: DateTime - updated_at: DateTime -} - -type Letsencrypt_userMaxAggregateOutputType { - zone: String - email: String - dns_provider_name: String - dns_provider_token: String - private_key: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateLetsencrypt_user { - count: Letsencrypt_userCountAggregateOutputType - min: Letsencrypt_userMinAggregateOutputType - max: Letsencrypt_userMaxAggregateOutputType -} - -input NestedJsonNullableFilter { - equals: DateTime - not: DateTime -} - -input JsonNullableWithAggregatesFilter { - equals: DateTime - not: DateTime - count: NestedIntNullableFilter - min: NestedJsonNullableFilter - max: NestedJsonNullableFilter -} - -input letsencrypt_userScalarWhereWithAggregatesInput { - AND: letsencrypt_userScalarWhereWithAggregatesInput - OR: [letsencrypt_userScalarWhereWithAggregatesInput] - NOT: letsencrypt_userScalarWhereWithAggregatesInput - zone: StringWithAggregatesFilter - email: StringWithAggregatesFilter - dns_provider_name: StringWithAggregatesFilter - dns_provider_token: StringWithAggregatesFilter - private_key: StringNullableWithAggregatesFilter - registration_resource: JsonNullableWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type Letsencrypt_userGroupByOutputType { - zone: String! - email: String! - dns_provider_name: String! - dns_provider_token: String! - private_key: String - registration_resource: Json - created_at: DateTime! - updated_at: DateTime - count: Letsencrypt_userCountAggregateOutputType - min: Letsencrypt_userMinAggregateOutputType - max: Letsencrypt_userMaxAggregateOutputType -} - -input NestedBigIntNullableFilter { - equals: BigInt - in: [BigInt] - notIn: [BigInt] - lt: BigInt - lte: BigInt - gt: BigInt - gte: BigInt - not: NestedBigIntNullableFilter -} - -input BigIntNullableFilter { - equals: BigInt - in: [BigInt] - notIn: [BigInt] - lt: BigInt - lte: BigInt - gt: BigInt - gte: BigInt - not: NestedBigIntNullableFilter -} - -input locksWhereInput { - AND: locksWhereInput - OR: [locksWhereInput] - NOT: locksWhereInput - name: StringFilter - record_version_number: BigIntNullableFilter - data: StringNullableFilter - owner: StringNullableFilter -} - -input locksOrderByInput { - name: SortOrder - record_version_number: SortOrder - data: SortOrder - owner: SortOrder -} - -input locksWhereUniqueInput { - name: String -} - -enum LocksScalarFieldEnum { - name - record_version_number - data - owner -} - -type locks { - name: String! - record_version_number: BigInt - data: String - owner: String -} - -type LocksCountAggregateOutputType { - name: Int! - record_version_number: Int! - data: Int! - owner: Int! -} - -type LocksAvgAggregateOutputType { - record_version_number: Float -} - -type LocksSumAggregateOutputType { - record_version_number: BigInt -} - -type LocksMinAggregateOutputType { - name: String - record_version_number: BigInt - data: String - owner: String -} - -type LocksMaxAggregateOutputType { - name: String - record_version_number: BigInt - data: String - owner: String -} - -type AggregateLocks { - count: LocksCountAggregateOutputType - avg: LocksAvgAggregateOutputType - sum: LocksSumAggregateOutputType - min: LocksMinAggregateOutputType - max: LocksMaxAggregateOutputType -} - -input NestedFloatNullableFilter { - equals: Float - in: [Float] - notIn: [Float] - lt: Float - lte: Float - gt: Float - gte: Float - not: NestedFloatNullableFilter -} - -input NestedBigIntNullableWithAggregatesFilter { - equals: BigInt - in: [BigInt] - notIn: [BigInt] - lt: BigInt - lte: BigInt - gt: BigInt - gte: BigInt - not: NestedBigIntNullableWithAggregatesFilter - count: NestedIntNullableFilter - avg: NestedFloatNullableFilter - sum: NestedBigIntNullableFilter - min: NestedBigIntNullableFilter - max: NestedBigIntNullableFilter -} - -input BigIntNullableWithAggregatesFilter { - equals: BigInt - in: [BigInt] - notIn: [BigInt] - lt: BigInt - lte: BigInt - gt: BigInt - gte: BigInt - not: NestedBigIntNullableWithAggregatesFilter - count: NestedIntNullableFilter - avg: NestedFloatNullableFilter - sum: NestedBigIntNullableFilter - min: NestedBigIntNullableFilter - max: NestedBigIntNullableFilter -} - -input locksScalarWhereWithAggregatesInput { - AND: locksScalarWhereWithAggregatesInput - OR: [locksScalarWhereWithAggregatesInput] - NOT: locksScalarWhereWithAggregatesInput - name: StringWithAggregatesFilter - record_version_number: BigIntNullableWithAggregatesFilter - data: StringNullableWithAggregatesFilter - owner: StringNullableWithAggregatesFilter -} - -type LocksGroupByOutputType { - name: String! - record_version_number: BigInt - data: String - owner: String - count: LocksCountAggregateOutputType - avg: LocksAvgAggregateOutputType - sum: LocksSumAggregateOutputType - min: LocksMinAggregateOutputType - max: LocksMaxAggregateOutputType -} - -type NamespaceCountAggregateOutputType { - id: Int! - name: Int! - price_plan_id: Int! - created_at: Int! - updated_at: Int! -} - -type NamespaceAvgAggregateOutputType { - price_plan_id: Float -} - -type NamespaceSumAggregateOutputType { - price_plan_id: Int -} - -type NamespaceMinAggregateOutputType { - id: String - name: String - price_plan_id: Int - created_at: DateTime - updated_at: DateTime -} - -type NamespaceMaxAggregateOutputType { - id: String - name: String - price_plan_id: Int - created_at: DateTime - updated_at: DateTime -} - -type AggregateNamespace { - count: NamespaceCountAggregateOutputType - avg: NamespaceAvgAggregateOutputType - sum: NamespaceSumAggregateOutputType - min: NamespaceMinAggregateOutputType - max: NamespaceMaxAggregateOutputType -} - -input NestedFloatFilter { - equals: Float - in: [Float] - notIn: [Float] - lt: Float - lte: Float - gt: Float - gte: Float - not: NestedFloatFilter -} - -input NestedIntWithAggregatesFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: NestedIntWithAggregatesFilter - count: NestedIntFilter - avg: NestedFloatFilter - sum: NestedIntFilter - min: NestedIntFilter - max: NestedIntFilter -} - -input IntWithAggregatesFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: NestedIntWithAggregatesFilter - count: NestedIntFilter - avg: NestedFloatFilter - sum: NestedIntFilter - min: NestedIntFilter - max: NestedIntFilter -} - -input namespaceScalarWhereWithAggregatesInput { - AND: namespaceScalarWhereWithAggregatesInput - OR: [namespaceScalarWhereWithAggregatesInput] - NOT: namespaceScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - name: StringWithAggregatesFilter - price_plan_id: IntWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type NamespaceGroupByOutputType { - id: String! - name: String! - price_plan_id: Int! - created_at: DateTime! - updated_at: DateTime - count: NamespaceCountAggregateOutputType - avg: NamespaceAvgAggregateOutputType - sum: NamespaceSumAggregateOutputType - min: NamespaceMinAggregateOutputType - max: NamespaceMaxAggregateOutputType -} - -type Namespace_membersCountAggregateOutputType { - user_id: Int! - namespace_id: Int! - membership: Int! - created_at: Int! - updated_at: Int! -} - -type Namespace_membersMinAggregateOutputType { - user_id: String - namespace_id: String - membership: membership - created_at: DateTime - updated_at: DateTime -} - -type Namespace_membersMaxAggregateOutputType { - user_id: String - namespace_id: String - membership: membership - created_at: DateTime - updated_at: DateTime -} - -type AggregateNamespace_members { - count: Namespace_membersCountAggregateOutputType - min: Namespace_membersMinAggregateOutputType - max: Namespace_membersMaxAggregateOutputType -} - -input NestedEnummembershipFilter { - equals: membership - in: [membership] - notIn: [membership] - not: membership -} - -input EnummembershipWithAggregatesFilter { - equals: membership - in: [membership] - notIn: [membership] - not: membership - count: NestedIntFilter - min: NestedEnummembershipFilter - max: NestedEnummembershipFilter -} - -input namespace_membersScalarWhereWithAggregatesInput { - AND: namespace_membersScalarWhereWithAggregatesInput - OR: [namespace_membersScalarWhereWithAggregatesInput] - NOT: namespace_membersScalarWhereWithAggregatesInput - user_id: StringWithAggregatesFilter - namespace_id: StringWithAggregatesFilter - membership: EnummembershipWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type Namespace_membersGroupByOutputType { - user_id: String! - namespace_id: String! - membership: membership! - created_at: DateTime! - updated_at: DateTime - count: Namespace_membersCountAggregateOutputType - min: Namespace_membersMinAggregateOutputType - max: Namespace_membersMaxAggregateOutputType -} - -type NodepoolCountAggregateOutputType { - id: Int! - wundernode_id: Int! - shared: Int! - created_at: Int! - updated_at: Int! -} - -type NodepoolMinAggregateOutputType { - id: String - wundernode_id: String - shared: Boolean - created_at: DateTime - updated_at: DateTime -} - -type NodepoolMaxAggregateOutputType { - id: String - wundernode_id: String - shared: Boolean - created_at: DateTime - updated_at: DateTime -} - -type AggregateNodepool { - count: NodepoolCountAggregateOutputType - min: NodepoolMinAggregateOutputType - max: NodepoolMaxAggregateOutputType -} - -input nodepoolScalarWhereWithAggregatesInput { - AND: nodepoolScalarWhereWithAggregatesInput - OR: [nodepoolScalarWhereWithAggregatesInput] - NOT: nodepoolScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - wundernode_id: StringWithAggregatesFilter - shared: BoolWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type NodepoolGroupByOutputType { - id: String! - wundernode_id: String! - shared: Boolean! - created_at: DateTime! - updated_at: DateTime - count: NodepoolCountAggregateOutputType - min: NodepoolMinAggregateOutputType - max: NodepoolMaxAggregateOutputType -} - -type Nodepool_environmentCountAggregateOutputType { - nodepool_id: Int! - environment_id: Int! -} - -type Nodepool_environmentMinAggregateOutputType { - nodepool_id: String - environment_id: String -} - -type Nodepool_environmentMaxAggregateOutputType { - nodepool_id: String - environment_id: String -} - -type AggregateNodepool_environment { - count: Nodepool_environmentCountAggregateOutputType - min: Nodepool_environmentMinAggregateOutputType - max: Nodepool_environmentMaxAggregateOutputType -} - -input nodepool_environmentScalarWhereWithAggregatesInput { - AND: nodepool_environmentScalarWhereWithAggregatesInput - OR: [nodepool_environmentScalarWhereWithAggregatesInput] - NOT: nodepool_environmentScalarWhereWithAggregatesInput - nodepool_id: StringWithAggregatesFilter - environment_id: StringWithAggregatesFilter -} - -type Nodepool_environmentGroupByOutputType { - nodepool_id: String! - environment_id: String! - count: Nodepool_environmentCountAggregateOutputType - min: Nodepool_environmentMinAggregateOutputType - max: Nodepool_environmentMaxAggregateOutputType -} - -input price_planOrderByInput { - id: SortOrder - name: SortOrder - quota_daily_requests: SortOrder - quota_environments: SortOrder - quota_members: SortOrder - quota_apis: SortOrder - allow_secondary_environments: SortOrder -} - -input price_planWhereUniqueInput { - id: Int -} - -enum Price_planScalarFieldEnum { - id - name - quota_daily_requests - quota_environments - quota_members - quota_apis - allow_secondary_environments -} - -type Price_planCountAggregateOutputType { - id: Int! - name: Int! - quota_daily_requests: Int! - quota_environments: Int! - quota_members: Int! - quota_apis: Int! - allow_secondary_environments: Int! -} - -type Price_planAvgAggregateOutputType { - id: Float - quota_daily_requests: Float - quota_environments: Float - quota_members: Float - quota_apis: Float -} - -type Price_planSumAggregateOutputType { - id: Int - quota_daily_requests: Int - quota_environments: Int - quota_members: Int - quota_apis: Int -} - -type Price_planMinAggregateOutputType { - id: Int - name: String - quota_daily_requests: Int - quota_environments: Int - quota_members: Int - quota_apis: Int - allow_secondary_environments: Boolean -} - -type Price_planMaxAggregateOutputType { - id: Int - name: String - quota_daily_requests: Int - quota_environments: Int - quota_members: Int - quota_apis: Int - allow_secondary_environments: Boolean -} - -type AggregatePrice_plan { - count: Price_planCountAggregateOutputType - avg: Price_planAvgAggregateOutputType - sum: Price_planSumAggregateOutputType - min: Price_planMinAggregateOutputType - max: Price_planMaxAggregateOutputType -} - -input price_planScalarWhereWithAggregatesInput { - AND: price_planScalarWhereWithAggregatesInput - OR: [price_planScalarWhereWithAggregatesInput] - NOT: price_planScalarWhereWithAggregatesInput - id: IntWithAggregatesFilter - name: StringWithAggregatesFilter - quota_daily_requests: IntWithAggregatesFilter - quota_environments: IntWithAggregatesFilter - quota_members: IntWithAggregatesFilter - quota_apis: IntWithAggregatesFilter - allow_secondary_environments: BoolWithAggregatesFilter -} - -type Price_planGroupByOutputType { - id: Int! - name: String! - quota_daily_requests: Int! - quota_environments: Int! - quota_members: Int! - quota_apis: Int! - allow_secondary_environments: Boolean! - count: Price_planCountAggregateOutputType - avg: Price_planAvgAggregateOutputType - sum: Price_planSumAggregateOutputType - min: Price_planMinAggregateOutputType - max: Price_planMaxAggregateOutputType -} - -input usersOrderByInput { - id: SortOrder - name: SortOrder - email: SortOrder - role: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input usersWhereUniqueInput { - id: String - email: String -} - -enum UsersScalarFieldEnum { - id - name - email - role - created_at - updated_at -} - -type UsersCountAggregateOutputType { - id: Int! - name: Int! - email: Int! - role: Int! - created_at: Int! - updated_at: Int! -} - -type UsersMinAggregateOutputType { - id: String - name: String - email: String - role: user_role - created_at: DateTime - updated_at: DateTime -} - -type UsersMaxAggregateOutputType { - id: String - name: String - email: String - role: user_role - created_at: DateTime - updated_at: DateTime -} - -type AggregateUsers { - count: UsersCountAggregateOutputType - min: UsersMinAggregateOutputType - max: UsersMaxAggregateOutputType -} - -input NestedEnumuser_roleFilter { - equals: user_role - in: [user_role] - notIn: [user_role] - not: user_role -} - -input Enumuser_roleWithAggregatesFilter { - equals: user_role - in: [user_role] - notIn: [user_role] - not: user_role - count: NestedIntFilter - min: NestedEnumuser_roleFilter - max: NestedEnumuser_roleFilter -} - -input usersScalarWhereWithAggregatesInput { - AND: usersScalarWhereWithAggregatesInput - OR: [usersScalarWhereWithAggregatesInput] - NOT: usersScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - name: StringNullableWithAggregatesFilter - email: StringWithAggregatesFilter - role: Enumuser_roleWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type UsersGroupByOutputType { - id: String! - name: String - email: String! - role: user_role! - created_at: DateTime! - updated_at: DateTime - count: UsersCountAggregateOutputType - min: UsersMinAggregateOutputType - max: UsersMaxAggregateOutputType -} - -input wundernodeOrderByInput { - id: SortOrder - etag: SortOrder - config: SortOrder - ipv4: SortOrder - ipv6: SortOrder - created_at: SortOrder - updated_at: SortOrder -} - -input wundernodeWhereUniqueInput { - id: String -} - -enum WundernodeScalarFieldEnum { - id - etag - config - ipv4 - ipv6 - created_at - updated_at -} - -type WundernodeCountAggregateOutputType { - id: Int! - etag: Int! - config: Int! - ipv4: Int! - ipv6: Int! - created_at: Int! - updated_at: Int! -} - -type WundernodeMinAggregateOutputType { - id: String - etag: String - ipv4: String - ipv6: String - created_at: DateTime - updated_at: DateTime -} - -type WundernodeMaxAggregateOutputType { - id: String - etag: String - ipv4: String - ipv6: String - created_at: DateTime - updated_at: DateTime -} - -type AggregateWundernode { - count: WundernodeCountAggregateOutputType - min: WundernodeMinAggregateOutputType - max: WundernodeMaxAggregateOutputType -} - -input wundernodeScalarWhereWithAggregatesInput { - AND: wundernodeScalarWhereWithAggregatesInput - OR: [wundernodeScalarWhereWithAggregatesInput] - NOT: wundernodeScalarWhereWithAggregatesInput - id: StringWithAggregatesFilter - etag: StringWithAggregatesFilter - config: JsonWithAggregatesFilter - ipv4: StringNullableWithAggregatesFilter - ipv6: StringNullableWithAggregatesFilter - created_at: DateTimeWithAggregatesFilter - updated_at: DateTimeNullableWithAggregatesFilter -} - -type WundernodeGroupByOutputType { - id: String! - etag: String! - config: Json! - ipv4: String - ipv6: String - created_at: DateTime! - updated_at: DateTime - count: WundernodeCountAggregateOutputType - min: WundernodeMinAggregateOutputType - max: WundernodeMaxAggregateOutputType -} - -type Query { - findFirstaccess_token(where: access_tokenWhereInput, orderBy: [access_tokenOrderByInput], cursor: access_tokenWhereUniqueInput, take: Int, skip: Int, distinct: [Access_tokenScalarFieldEnum]): access_token - findManyaccess_token(where: access_tokenWhereInput, orderBy: [access_tokenOrderByInput], cursor: access_tokenWhereUniqueInput, take: Int, skip: Int, distinct: [Access_tokenScalarFieldEnum]): [access_token]! - aggregateaccess_token(where: access_tokenWhereInput, orderBy: [access_tokenOrderByInput], cursor: access_tokenWhereUniqueInput, take: Int, skip: Int): AggregateAccess_token! - groupByaccess_token(where: access_tokenWhereInput, orderBy: [access_tokenOrderByInput], by: [Access_tokenScalarFieldEnum]!, having: access_tokenScalarWhereWithAggregatesInput, take: Int, skip: Int): [Access_tokenGroupByOutputType]! - findUniqueaccess_token(where: access_tokenWhereUniqueInput!): access_token - findFirstadmin_config(where: admin_configWhereInput, orderBy: [admin_configOrderByInput], cursor: admin_configWhereUniqueInput, take: Int, skip: Int, distinct: [Admin_configScalarFieldEnum]): admin_config - findManyadmin_config(where: admin_configWhereInput, orderBy: [admin_configOrderByInput], cursor: admin_configWhereUniqueInput, take: Int, skip: Int, distinct: [Admin_configScalarFieldEnum]): [admin_config]! - aggregateadmin_config(where: admin_configWhereInput, orderBy: [admin_configOrderByInput], cursor: admin_configWhereUniqueInput, take: Int, skip: Int): AggregateAdmin_config! - groupByadmin_config(where: admin_configWhereInput, orderBy: [admin_configOrderByInput], by: [Admin_configScalarFieldEnum]!, having: admin_configScalarWhereWithAggregatesInput, take: Int, skip: Int): [Admin_configGroupByOutputType]! - findUniqueadmin_config(where: admin_configWhereUniqueInput!): admin_config - findFirstapi(where: apiWhereInput, orderBy: [apiOrderByInput], cursor: apiWhereUniqueInput, take: Int, skip: Int, distinct: [ApiScalarFieldEnum]): api - findManyapi(where: apiWhereInput, orderBy: [apiOrderByInput], cursor: apiWhereUniqueInput, take: Int, skip: Int, distinct: [ApiScalarFieldEnum]): [api]! - aggregateapi(where: apiWhereInput, orderBy: [apiOrderByInput], cursor: apiWhereUniqueInput, take: Int, skip: Int): AggregateApi! - groupByapi(where: apiWhereInput, orderBy: [apiOrderByInput], by: [ApiScalarFieldEnum]!, having: apiScalarWhereWithAggregatesInput, take: Int, skip: Int): [ApiGroupByOutputType]! - findUniqueapi(where: apiWhereUniqueInput!): api - findFirstdeployment(where: deploymentWhereInput, orderBy: [deploymentOrderByInput], cursor: deploymentWhereUniqueInput, take: Int, skip: Int, distinct: [DeploymentScalarFieldEnum]): deployment - findManydeployment(where: deploymentWhereInput, orderBy: [deploymentOrderByInput], cursor: deploymentWhereUniqueInput, take: Int, skip: Int, distinct: [DeploymentScalarFieldEnum]): [deployment]! - aggregatedeployment(where: deploymentWhereInput, orderBy: [deploymentOrderByInput], cursor: deploymentWhereUniqueInput, take: Int, skip: Int): AggregateDeployment! - groupBydeployment(where: deploymentWhereInput, orderBy: [deploymentOrderByInput], by: [DeploymentScalarFieldEnum]!, having: deploymentScalarWhereWithAggregatesInput, take: Int, skip: Int): [DeploymentGroupByOutputType]! - findUniquedeployment(where: deploymentWhereUniqueInput!): deployment - findFirstdeployment_environment(where: deployment_environmentWhereInput, orderBy: [deployment_environmentOrderByInput], cursor: deployment_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Deployment_environmentScalarFieldEnum]): deployment_environment - findManydeployment_environment(where: deployment_environmentWhereInput, orderBy: [deployment_environmentOrderByInput], cursor: deployment_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Deployment_environmentScalarFieldEnum]): [deployment_environment]! - aggregatedeployment_environment(where: deployment_environmentWhereInput, orderBy: [deployment_environmentOrderByInput], cursor: deployment_environmentWhereUniqueInput, take: Int, skip: Int): AggregateDeployment_environment! - groupBydeployment_environment(where: deployment_environmentWhereInput, orderBy: [deployment_environmentOrderByInput], by: [Deployment_environmentScalarFieldEnum]!, having: deployment_environmentScalarWhereWithAggregatesInput, take: Int, skip: Int): [Deployment_environmentGroupByOutputType]! - findUniquedeployment_environment(where: deployment_environmentWhereUniqueInput!): deployment_environment - findFirstedge(where: edgeWhereInput, orderBy: [edgeOrderByInput], cursor: edgeWhereUniqueInput, take: Int, skip: Int, distinct: [EdgeScalarFieldEnum]): edge - findManyedge(where: edgeWhereInput, orderBy: [edgeOrderByInput], cursor: edgeWhereUniqueInput, take: Int, skip: Int, distinct: [EdgeScalarFieldEnum]): [edge]! - aggregateedge(where: edgeWhereInput, orderBy: [edgeOrderByInput], cursor: edgeWhereUniqueInput, take: Int, skip: Int): AggregateEdge! - groupByedge(where: edgeWhereInput, orderBy: [edgeOrderByInput], by: [EdgeScalarFieldEnum]!, having: edgeScalarWhereWithAggregatesInput, take: Int, skip: Int): [EdgeGroupByOutputType]! - findUniqueedge(where: edgeWhereUniqueInput!): edge - findFirstenvironment(where: environmentWhereInput, orderBy: [environmentOrderByInput], cursor: environmentWhereUniqueInput, take: Int, skip: Int, distinct: [EnvironmentScalarFieldEnum]): environment - findManyenvironment(where: environmentWhereInput, orderBy: [environmentOrderByInput], cursor: environmentWhereUniqueInput, take: Int, skip: Int, distinct: [EnvironmentScalarFieldEnum]): [environment]! - aggregateenvironment(where: environmentWhereInput, orderBy: [environmentOrderByInput], cursor: environmentWhereUniqueInput, take: Int, skip: Int): AggregateEnvironment! - groupByenvironment(where: environmentWhereInput, orderBy: [environmentOrderByInput], by: [EnvironmentScalarFieldEnum]!, having: environmentScalarWhereWithAggregatesInput, take: Int, skip: Int): [EnvironmentGroupByOutputType]! - findUniqueenvironment(where: environmentWhereUniqueInput!): environment - findFirstenvironment_edges(where: environment_edgesWhereInput, orderBy: [environment_edgesOrderByInput], cursor: environment_edgesWhereUniqueInput, take: Int, skip: Int, distinct: [Environment_edgesScalarFieldEnum]): environment_edges - findManyenvironment_edges(where: environment_edgesWhereInput, orderBy: [environment_edgesOrderByInput], cursor: environment_edgesWhereUniqueInput, take: Int, skip: Int, distinct: [Environment_edgesScalarFieldEnum]): [environment_edges]! - aggregateenvironment_edges(where: environment_edgesWhereInput, orderBy: [environment_edgesOrderByInput], cursor: environment_edgesWhereUniqueInput, take: Int, skip: Int): AggregateEnvironment_edges! - groupByenvironment_edges(where: environment_edgesWhereInput, orderBy: [environment_edgesOrderByInput], by: [Environment_edgesScalarFieldEnum]!, having: environment_edgesScalarWhereWithAggregatesInput, take: Int, skip: Int): [Environment_edgesGroupByOutputType]! - findUniqueenvironment_edges(where: environment_edgesWhereUniqueInput!): environment_edges - findFirstletsencrypt_certificate(where: letsencrypt_certificateWhereInput, orderBy: [letsencrypt_certificateOrderByInput], cursor: letsencrypt_certificateWhereUniqueInput, take: Int, skip: Int, distinct: [Letsencrypt_certificateScalarFieldEnum]): letsencrypt_certificate - findManyletsencrypt_certificate(where: letsencrypt_certificateWhereInput, orderBy: [letsencrypt_certificateOrderByInput], cursor: letsencrypt_certificateWhereUniqueInput, take: Int, skip: Int, distinct: [Letsencrypt_certificateScalarFieldEnum]): [letsencrypt_certificate]! - aggregateletsencrypt_certificate(where: letsencrypt_certificateWhereInput, orderBy: [letsencrypt_certificateOrderByInput], cursor: letsencrypt_certificateWhereUniqueInput, take: Int, skip: Int): AggregateLetsencrypt_certificate! - groupByletsencrypt_certificate(where: letsencrypt_certificateWhereInput, orderBy: [letsencrypt_certificateOrderByInput], by: [Letsencrypt_certificateScalarFieldEnum]!, having: letsencrypt_certificateScalarWhereWithAggregatesInput, take: Int, skip: Int): [Letsencrypt_certificateGroupByOutputType]! - findUniqueletsencrypt_certificate(where: letsencrypt_certificateWhereUniqueInput!): letsencrypt_certificate - findFirstletsencrypt_user(where: letsencrypt_userWhereInput, orderBy: [letsencrypt_userOrderByInput], cursor: letsencrypt_userWhereUniqueInput, take: Int, skip: Int, distinct: [Letsencrypt_userScalarFieldEnum]): letsencrypt_user - findManyletsencrypt_user(where: letsencrypt_userWhereInput, orderBy: [letsencrypt_userOrderByInput], cursor: letsencrypt_userWhereUniqueInput, take: Int, skip: Int, distinct: [Letsencrypt_userScalarFieldEnum]): [letsencrypt_user]! - aggregateletsencrypt_user(where: letsencrypt_userWhereInput, orderBy: [letsencrypt_userOrderByInput], cursor: letsencrypt_userWhereUniqueInput, take: Int, skip: Int): AggregateLetsencrypt_user! - groupByletsencrypt_user(where: letsencrypt_userWhereInput, orderBy: [letsencrypt_userOrderByInput], by: [Letsencrypt_userScalarFieldEnum]!, having: letsencrypt_userScalarWhereWithAggregatesInput, take: Int, skip: Int): [Letsencrypt_userGroupByOutputType]! - findUniqueletsencrypt_user(where: letsencrypt_userWhereUniqueInput!): letsencrypt_user - findFirstlocks(where: locksWhereInput, orderBy: [locksOrderByInput], cursor: locksWhereUniqueInput, take: Int, skip: Int, distinct: [LocksScalarFieldEnum]): locks - findManylocks(where: locksWhereInput, orderBy: [locksOrderByInput], cursor: locksWhereUniqueInput, take: Int, skip: Int, distinct: [LocksScalarFieldEnum]): [locks]! - aggregatelocks(where: locksWhereInput, orderBy: [locksOrderByInput], cursor: locksWhereUniqueInput, take: Int, skip: Int): AggregateLocks! - groupBylocks(where: locksWhereInput, orderBy: [locksOrderByInput], by: [LocksScalarFieldEnum]!, having: locksScalarWhereWithAggregatesInput, take: Int, skip: Int): [LocksGroupByOutputType]! - findUniquelocks(where: locksWhereUniqueInput!): locks - findFirstnamespace(where: namespaceWhereInput, orderBy: [namespaceOrderByInput], cursor: namespaceWhereUniqueInput, take: Int, skip: Int, distinct: [NamespaceScalarFieldEnum]): namespace - findManynamespace(where: namespaceWhereInput, orderBy: [namespaceOrderByInput], cursor: namespaceWhereUniqueInput, take: Int, skip: Int, distinct: [NamespaceScalarFieldEnum]): [namespace]! - aggregatenamespace(where: namespaceWhereInput, orderBy: [namespaceOrderByInput], cursor: namespaceWhereUniqueInput, take: Int, skip: Int): AggregateNamespace! - groupBynamespace(where: namespaceWhereInput, orderBy: [namespaceOrderByInput], by: [NamespaceScalarFieldEnum]!, having: namespaceScalarWhereWithAggregatesInput, take: Int, skip: Int): [NamespaceGroupByOutputType]! - findUniquenamespace(where: namespaceWhereUniqueInput!): namespace - findFirstnamespace_members(where: namespace_membersWhereInput, orderBy: [namespace_membersOrderByInput], cursor: namespace_membersWhereUniqueInput, take: Int, skip: Int, distinct: [Namespace_membersScalarFieldEnum]): namespace_members - findManynamespace_members(where: namespace_membersWhereInput, orderBy: [namespace_membersOrderByInput], cursor: namespace_membersWhereUniqueInput, take: Int, skip: Int, distinct: [Namespace_membersScalarFieldEnum]): [namespace_members]! - aggregatenamespace_members(where: namespace_membersWhereInput, orderBy: [namespace_membersOrderByInput], cursor: namespace_membersWhereUniqueInput, take: Int, skip: Int): AggregateNamespace_members! - groupBynamespace_members(where: namespace_membersWhereInput, orderBy: [namespace_membersOrderByInput], by: [Namespace_membersScalarFieldEnum]!, having: namespace_membersScalarWhereWithAggregatesInput, take: Int, skip: Int): [Namespace_membersGroupByOutputType]! - findUniquenamespace_members(where: namespace_membersWhereUniqueInput!): namespace_members - findFirstnodepool(where: nodepoolWhereInput, orderBy: [nodepoolOrderByInput], cursor: nodepoolWhereUniqueInput, take: Int, skip: Int, distinct: [NodepoolScalarFieldEnum]): nodepool - findManynodepool(where: nodepoolWhereInput, orderBy: [nodepoolOrderByInput], cursor: nodepoolWhereUniqueInput, take: Int, skip: Int, distinct: [NodepoolScalarFieldEnum]): [nodepool]! - aggregatenodepool(where: nodepoolWhereInput, orderBy: [nodepoolOrderByInput], cursor: nodepoolWhereUniqueInput, take: Int, skip: Int): AggregateNodepool! - groupBynodepool(where: nodepoolWhereInput, orderBy: [nodepoolOrderByInput], by: [NodepoolScalarFieldEnum]!, having: nodepoolScalarWhereWithAggregatesInput, take: Int, skip: Int): [NodepoolGroupByOutputType]! - findUniquenodepool(where: nodepoolWhereUniqueInput!): nodepool - findFirstnodepool_environment(where: nodepool_environmentWhereInput, orderBy: [nodepool_environmentOrderByInput], cursor: nodepool_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Nodepool_environmentScalarFieldEnum]): nodepool_environment - findManynodepool_environment(where: nodepool_environmentWhereInput, orderBy: [nodepool_environmentOrderByInput], cursor: nodepool_environmentWhereUniqueInput, take: Int, skip: Int, distinct: [Nodepool_environmentScalarFieldEnum]): [nodepool_environment]! - aggregatenodepool_environment(where: nodepool_environmentWhereInput, orderBy: [nodepool_environmentOrderByInput], cursor: nodepool_environmentWhereUniqueInput, take: Int, skip: Int): AggregateNodepool_environment! - groupBynodepool_environment(where: nodepool_environmentWhereInput, orderBy: [nodepool_environmentOrderByInput], by: [Nodepool_environmentScalarFieldEnum]!, having: nodepool_environmentScalarWhereWithAggregatesInput, take: Int, skip: Int): [Nodepool_environmentGroupByOutputType]! - findUniquenodepool_environment(where: nodepool_environmentWhereUniqueInput!): nodepool_environment - findFirstprice_plan(where: price_planWhereInput, orderBy: [price_planOrderByInput], cursor: price_planWhereUniqueInput, take: Int, skip: Int, distinct: [Price_planScalarFieldEnum]): price_plan - findManyprice_plan(where: price_planWhereInput, orderBy: [price_planOrderByInput], cursor: price_planWhereUniqueInput, take: Int, skip: Int, distinct: [Price_planScalarFieldEnum]): [price_plan]! - aggregateprice_plan(where: price_planWhereInput, orderBy: [price_planOrderByInput], cursor: price_planWhereUniqueInput, take: Int, skip: Int): AggregatePrice_plan! - groupByprice_plan(where: price_planWhereInput, orderBy: [price_planOrderByInput], by: [Price_planScalarFieldEnum]!, having: price_planScalarWhereWithAggregatesInput, take: Int, skip: Int): [Price_planGroupByOutputType]! - findUniqueprice_plan(where: price_planWhereUniqueInput!): price_plan - findFirstusers(where: usersWhereInput, orderBy: [usersOrderByInput], cursor: usersWhereUniqueInput, take: Int, skip: Int, distinct: [UsersScalarFieldEnum]): users - findManyusers(where: usersWhereInput, orderBy: [usersOrderByInput], cursor: usersWhereUniqueInput, take: Int, skip: Int, distinct: [UsersScalarFieldEnum]): [users]! - aggregateusers(where: usersWhereInput, orderBy: [usersOrderByInput], cursor: usersWhereUniqueInput, take: Int, skip: Int): AggregateUsers! - groupByusers(where: usersWhereInput, orderBy: [usersOrderByInput], by: [UsersScalarFieldEnum]!, having: usersScalarWhereWithAggregatesInput, take: Int, skip: Int): [UsersGroupByOutputType]! - findUniqueusers(where: usersWhereUniqueInput!): users - findFirstwundernode(where: wundernodeWhereInput, orderBy: [wundernodeOrderByInput], cursor: wundernodeWhereUniqueInput, take: Int, skip: Int, distinct: [WundernodeScalarFieldEnum]): wundernode - findManywundernode(where: wundernodeWhereInput, orderBy: [wundernodeOrderByInput], cursor: wundernodeWhereUniqueInput, take: Int, skip: Int, distinct: [WundernodeScalarFieldEnum]): [wundernode]! - aggregatewundernode(where: wundernodeWhereInput, orderBy: [wundernodeOrderByInput], cursor: wundernodeWhereUniqueInput, take: Int, skip: Int): AggregateWundernode! - groupBywundernode(where: wundernodeWhereInput, orderBy: [wundernodeOrderByInput], by: [WundernodeScalarFieldEnum]!, having: wundernodeScalarWhereWithAggregatesInput, take: Int, skip: Int): [WundernodeGroupByOutputType]! - findUniquewundernode(where: wundernodeWhereUniqueInput!): wundernode - posts: [Post] - postComments(postID: String!): [Comment] - users: [User] - userPosts(userID: String!): [Post] -} - -input price_planCreateWithoutNamespaceInput { - name: String! - quota_daily_requests: Int! - quota_environments: Int! - quota_members: Int - quota_apis: Int - allow_secondary_environments: Boolean -} - -input price_planCreateOrConnectWithoutNamespaceInput { - where: price_planWhereUniqueInput! - create: price_planCreateWithoutNamespaceInput! -} - -input price_planCreateNestedOneWithoutNamespaceInput { - create: price_planCreateWithoutNamespaceInput - connectOrCreate: price_planCreateOrConnectWithoutNamespaceInput - connect: price_planWhereUniqueInput -} - -input environmentCreatehostnamesInput { - set: [String]! -} - -input access_tokenCreateWithoutUsersInput { - id: String - token: String - name: String! - created_at: DateTime -} - -input access_tokenCreateOrConnectWithoutUsersInput { - where: access_tokenWhereUniqueInput! - create: access_tokenCreateWithoutUsersInput! -} - -input access_tokenCreateManyUsersInput { - id: String - token: String - name: String! - created_at: DateTime -} - -input access_tokenCreateManyUsersInputEnvelope { - data: [access_tokenCreateManyUsersInput]! - skipDuplicates: Boolean -} - -input access_tokenCreateNestedManyWithoutUsersInput { - create: access_tokenCreateWithoutUsersInput - connectOrCreate: access_tokenCreateOrConnectWithoutUsersInput - createMany: access_tokenCreateManyUsersInputEnvelope - connect: access_tokenWhereUniqueInput -} - -input usersCreateWithoutNamespace_membersInput { - id: String - name: String - email: String! - role: user_role - created_at: DateTime - updated_at: DateTime - access_token: access_tokenCreateNestedManyWithoutUsersInput -} - -input usersCreateOrConnectWithoutNamespace_membersInput { - where: usersWhereUniqueInput! - create: usersCreateWithoutNamespace_membersInput! -} - -input usersCreateNestedOneWithoutNamespace_membersInput { - create: usersCreateWithoutNamespace_membersInput - connectOrCreate: usersCreateOrConnectWithoutNamespace_membersInput - connect: usersWhereUniqueInput -} - -input namespace_membersCreateWithoutNamespaceInput { - membership: membership - created_at: DateTime - updated_at: DateTime - users: usersCreateNestedOneWithoutNamespace_membersInput! -} - -input namespace_membersCreateOrConnectWithoutNamespaceInput { - where: namespace_membersWhereUniqueInput! - create: namespace_membersCreateWithoutNamespaceInput! -} - -input namespace_membersCreateManyNamespaceInput { - user_id: String! - membership: membership - created_at: DateTime - updated_at: DateTime -} - -input namespace_membersCreateManyNamespaceInputEnvelope { - data: [namespace_membersCreateManyNamespaceInput]! - skipDuplicates: Boolean -} - -input namespace_membersCreateNestedManyWithoutNamespaceInput { - create: namespace_membersCreateWithoutNamespaceInput - connectOrCreate: namespace_membersCreateOrConnectWithoutNamespaceInput - createMany: namespace_membersCreateManyNamespaceInputEnvelope - connect: namespace_membersWhereUniqueInput -} - -input namespaceCreateWithoutEnvironmentInput { - id: String - name: String! - created_at: DateTime - updated_at: DateTime - price_plan: price_planCreateNestedOneWithoutNamespaceInput - api: apiCreateNestedManyWithoutNamespaceInput - namespace_members: namespace_membersCreateNestedManyWithoutNamespaceInput -} - -input namespaceCreateOrConnectWithoutEnvironmentInput { - where: namespaceWhereUniqueInput! - create: namespaceCreateWithoutEnvironmentInput! -} - -input namespaceCreateNestedOneWithoutEnvironmentInput { - create: namespaceCreateWithoutEnvironmentInput - connectOrCreate: namespaceCreateOrConnectWithoutEnvironmentInput - connect: namespaceWhereUniqueInput -} - -input edgeCreateWithoutEnvironment_edgesInput { - id: String - name: String! - location: String! - created_at: DateTime - updated_at: DateTime -} - -input edgeCreateOrConnectWithoutEnvironment_edgesInput { - where: edgeWhereUniqueInput! - create: edgeCreateWithoutEnvironment_edgesInput! -} - -input edgeCreateNestedOneWithoutEnvironment_edgesInput { - create: edgeCreateWithoutEnvironment_edgesInput - connectOrCreate: edgeCreateOrConnectWithoutEnvironment_edgesInput - connect: edgeWhereUniqueInput -} - -input environment_edgesCreateWithoutEnvironmentInput { - edge: edgeCreateNestedOneWithoutEnvironment_edgesInput! -} - -input environment_edgesCreateOrConnectWithoutEnvironmentInput { - where: environment_edgesWhereUniqueInput! - create: environment_edgesCreateWithoutEnvironmentInput! -} - -input environment_edgesCreateManyEnvironmentInput { - edge_id: String! -} - -input environment_edgesCreateManyEnvironmentInputEnvelope { - data: [environment_edgesCreateManyEnvironmentInput]! - skipDuplicates: Boolean -} - -input environment_edgesCreateNestedManyWithoutEnvironmentInput { - create: environment_edgesCreateWithoutEnvironmentInput - connectOrCreate: environment_edgesCreateOrConnectWithoutEnvironmentInput - createMany: environment_edgesCreateManyEnvironmentInputEnvelope - connect: environment_edgesWhereUniqueInput -} - -input wundernodeCreateWithoutNodepoolInput { - id: String - etag: String! - config: DateTime! - ipv4: String - ipv6: String - created_at: DateTime - updated_at: DateTime -} - -input wundernodeCreateOrConnectWithoutNodepoolInput { - where: wundernodeWhereUniqueInput! - create: wundernodeCreateWithoutNodepoolInput! -} - -input wundernodeCreateNestedOneWithoutNodepoolInput { - create: wundernodeCreateWithoutNodepoolInput - connectOrCreate: wundernodeCreateOrConnectWithoutNodepoolInput - connect: wundernodeWhereUniqueInput -} - -input nodepoolCreateWithoutNodepool_environmentInput { - id: String - shared: Boolean - created_at: DateTime - updated_at: DateTime - wundernode: wundernodeCreateNestedOneWithoutNodepoolInput! -} - -input nodepoolCreateOrConnectWithoutNodepool_environmentInput { - where: nodepoolWhereUniqueInput! - create: nodepoolCreateWithoutNodepool_environmentInput! -} - -input nodepoolCreateNestedOneWithoutNodepool_environmentInput { - create: nodepoolCreateWithoutNodepool_environmentInput - connectOrCreate: nodepoolCreateOrConnectWithoutNodepool_environmentInput - connect: nodepoolWhereUniqueInput -} - -input nodepool_environmentCreateWithoutEnvironmentInput { - nodepool: nodepoolCreateNestedOneWithoutNodepool_environmentInput! -} - -input nodepool_environmentCreateOrConnectWithoutEnvironmentInput { - where: nodepool_environmentWhereUniqueInput! - create: nodepool_environmentCreateWithoutEnvironmentInput! -} - -input nodepool_environmentCreateManyEnvironmentInput { - nodepool_id: String! -} - -input nodepool_environmentCreateManyEnvironmentInputEnvelope { - data: [nodepool_environmentCreateManyEnvironmentInput]! - skipDuplicates: Boolean -} - -input nodepool_environmentCreateNestedManyWithoutEnvironmentInput { - create: nodepool_environmentCreateWithoutEnvironmentInput - connectOrCreate: nodepool_environmentCreateOrConnectWithoutEnvironmentInput - createMany: nodepool_environmentCreateManyEnvironmentInputEnvelope - connect: nodepool_environmentWhereUniqueInput -} - -input environmentCreateWithoutDeployment_environmentInput { - id: String - name: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreatehostnamesInput - namespace: namespaceCreateNestedOneWithoutEnvironmentInput! - environment_edges: environment_edgesCreateNestedManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentCreateNestedManyWithoutEnvironmentInput -} - -input environmentCreateOrConnectWithoutDeployment_environmentInput { - where: environmentWhereUniqueInput! - create: environmentCreateWithoutDeployment_environmentInput! -} - -input environmentCreateNestedOneWithoutDeployment_environmentInput { - create: environmentCreateWithoutDeployment_environmentInput - connectOrCreate: environmentCreateOrConnectWithoutDeployment_environmentInput - connect: environmentWhereUniqueInput -} - -input deployment_environmentCreateWithoutDeploymentInput { - environment: environmentCreateNestedOneWithoutDeployment_environmentInput! -} - -input deployment_environmentCreateOrConnectWithoutDeploymentInput { - where: deployment_environmentWhereUniqueInput! - create: deployment_environmentCreateWithoutDeploymentInput! -} - -input deployment_environmentCreateManyDeploymentInput { - environment_id: String! -} - -input deployment_environmentCreateManyDeploymentInputEnvelope { - data: [deployment_environmentCreateManyDeploymentInput]! - skipDuplicates: Boolean -} - -input deployment_environmentCreateNestedManyWithoutDeploymentInput { - create: deployment_environmentCreateWithoutDeploymentInput - connectOrCreate: deployment_environmentCreateOrConnectWithoutDeploymentInput - createMany: deployment_environmentCreateManyDeploymentInputEnvelope - connect: deployment_environmentWhereUniqueInput -} - -input deploymentCreateWithoutApiInput { - id: String - name: String! - config: DateTime! - created_at: DateTime - updated_at: DateTime - deployment_environment: deployment_environmentCreateNestedManyWithoutDeploymentInput -} - -input deploymentCreateOrConnectWithoutApiInput { - where: deploymentWhereUniqueInput! - create: deploymentCreateWithoutApiInput! -} - -input deploymentCreateManyApiInput { - id: String - name: String! - config: DateTime! - created_at: DateTime - updated_at: DateTime -} - -input deploymentCreateManyApiInputEnvelope { - data: [deploymentCreateManyApiInput]! - skipDuplicates: Boolean -} - -input deploymentCreateNestedManyWithoutApiInput { - create: deploymentCreateWithoutApiInput - connectOrCreate: deploymentCreateOrConnectWithoutApiInput - createMany: deploymentCreateManyApiInputEnvelope - connect: deploymentWhereUniqueInput -} - -input apiCreateWithoutNamespaceInput { - id: String - name: String! - markdown_description: String! - created_at: DateTime - updated_at: DateTime - deployment: deploymentCreateNestedManyWithoutApiInput -} - -input apiCreateOrConnectWithoutNamespaceInput { - where: apiWhereUniqueInput! - create: apiCreateWithoutNamespaceInput! -} - -input apiCreateManyNamespaceInput { - id: String - name: String! - markdown_description: String! - created_at: DateTime - updated_at: DateTime -} - -input apiCreateManyNamespaceInputEnvelope { - data: [apiCreateManyNamespaceInput]! - skipDuplicates: Boolean -} - -input apiCreateNestedManyWithoutNamespaceInput { - create: apiCreateWithoutNamespaceInput - connectOrCreate: apiCreateOrConnectWithoutNamespaceInput - createMany: apiCreateManyNamespaceInputEnvelope - connect: apiWhereUniqueInput -} - -input namespaceCreateWithoutApiInput { - id: String - name: String! - created_at: DateTime - updated_at: DateTime - price_plan: price_planCreateNestedOneWithoutNamespaceInput - environment: environmentCreateNestedManyWithoutNamespaceInput - namespace_members: namespace_membersCreateNestedManyWithoutNamespaceInput -} - -input namespaceCreateOrConnectWithoutApiInput { - where: namespaceWhereUniqueInput! - create: namespaceCreateWithoutApiInput! -} - -input namespaceCreateNestedOneWithoutApiInput { - create: namespaceCreateWithoutApiInput - connectOrCreate: namespaceCreateOrConnectWithoutApiInput - connect: namespaceWhereUniqueInput -} - -input apiCreateWithoutDeploymentInput { - id: String - name: String! - markdown_description: String! - created_at: DateTime - updated_at: DateTime - namespace: namespaceCreateNestedOneWithoutApiInput! -} - -input apiCreateOrConnectWithoutDeploymentInput { - where: apiWhereUniqueInput! - create: apiCreateWithoutDeploymentInput! -} - -input apiCreateNestedOneWithoutDeploymentInput { - create: apiCreateWithoutDeploymentInput - connectOrCreate: apiCreateOrConnectWithoutDeploymentInput - connect: apiWhereUniqueInput -} - -input deploymentCreateWithoutDeployment_environmentInput { - id: String - name: String! - config: DateTime! - created_at: DateTime - updated_at: DateTime - api: apiCreateNestedOneWithoutDeploymentInput! -} - -input deploymentCreateOrConnectWithoutDeployment_environmentInput { - where: deploymentWhereUniqueInput! - create: deploymentCreateWithoutDeployment_environmentInput! -} - -input deploymentCreateNestedOneWithoutDeployment_environmentInput { - create: deploymentCreateWithoutDeployment_environmentInput - connectOrCreate: deploymentCreateOrConnectWithoutDeployment_environmentInput - connect: deploymentWhereUniqueInput -} - -input deployment_environmentCreateWithoutEnvironmentInput { - deployment: deploymentCreateNestedOneWithoutDeployment_environmentInput! -} - -input deployment_environmentCreateOrConnectWithoutEnvironmentInput { - where: deployment_environmentWhereUniqueInput! - create: deployment_environmentCreateWithoutEnvironmentInput! -} - -input deployment_environmentCreateManyEnvironmentInput { - deployment_id: String! -} - -input deployment_environmentCreateManyEnvironmentInputEnvelope { - data: [deployment_environmentCreateManyEnvironmentInput]! - skipDuplicates: Boolean -} - -input deployment_environmentCreateNestedManyWithoutEnvironmentInput { - create: deployment_environmentCreateWithoutEnvironmentInput - connectOrCreate: deployment_environmentCreateOrConnectWithoutEnvironmentInput - createMany: deployment_environmentCreateManyEnvironmentInputEnvelope - connect: deployment_environmentWhereUniqueInput -} - -input environmentCreateWithoutNamespaceInput { - id: String - name: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreatehostnamesInput - deployment_environment: deployment_environmentCreateNestedManyWithoutEnvironmentInput - environment_edges: environment_edgesCreateNestedManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentCreateNestedManyWithoutEnvironmentInput -} - -input environmentCreateOrConnectWithoutNamespaceInput { - where: environmentWhereUniqueInput! - create: environmentCreateWithoutNamespaceInput! -} - -input environmentCreateManyhostnamesInput { - set: [String]! -} - -input environmentCreateManyNamespaceInput { - id: String - name: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreateManyhostnamesInput -} - -input environmentCreateManyNamespaceInputEnvelope { - data: [environmentCreateManyNamespaceInput]! - skipDuplicates: Boolean -} - -input environmentCreateNestedManyWithoutNamespaceInput { - create: environmentCreateWithoutNamespaceInput - connectOrCreate: environmentCreateOrConnectWithoutNamespaceInput - createMany: environmentCreateManyNamespaceInputEnvelope - connect: environmentWhereUniqueInput -} - -input namespaceCreateWithoutNamespace_membersInput { - id: String - name: String! - created_at: DateTime - updated_at: DateTime - price_plan: price_planCreateNestedOneWithoutNamespaceInput - api: apiCreateNestedManyWithoutNamespaceInput - environment: environmentCreateNestedManyWithoutNamespaceInput -} - -input namespaceCreateOrConnectWithoutNamespace_membersInput { - where: namespaceWhereUniqueInput! - create: namespaceCreateWithoutNamespace_membersInput! -} - -input namespaceCreateNestedOneWithoutNamespace_membersInput { - create: namespaceCreateWithoutNamespace_membersInput - connectOrCreate: namespaceCreateOrConnectWithoutNamespace_membersInput - connect: namespaceWhereUniqueInput -} - -input namespace_membersCreateWithoutUsersInput { - membership: membership - created_at: DateTime - updated_at: DateTime - namespace: namespaceCreateNestedOneWithoutNamespace_membersInput! -} - -input namespace_membersCreateOrConnectWithoutUsersInput { - where: namespace_membersWhereUniqueInput! - create: namespace_membersCreateWithoutUsersInput! -} - -input namespace_membersCreateManyUsersInput { - namespace_id: String! - membership: membership - created_at: DateTime - updated_at: DateTime -} - -input namespace_membersCreateManyUsersInputEnvelope { - data: [namespace_membersCreateManyUsersInput]! - skipDuplicates: Boolean -} - -input namespace_membersCreateNestedManyWithoutUsersInput { - create: namespace_membersCreateWithoutUsersInput - connectOrCreate: namespace_membersCreateOrConnectWithoutUsersInput - createMany: namespace_membersCreateManyUsersInputEnvelope - connect: namespace_membersWhereUniqueInput -} - -input usersCreateWithoutAccess_tokenInput { - id: String - name: String - email: String! - role: user_role - created_at: DateTime - updated_at: DateTime - namespace_members: namespace_membersCreateNestedManyWithoutUsersInput -} - -input usersCreateOrConnectWithoutAccess_tokenInput { - where: usersWhereUniqueInput! - create: usersCreateWithoutAccess_tokenInput! -} - -input usersCreateNestedOneWithoutAccess_tokenInput { - create: usersCreateWithoutAccess_tokenInput - connectOrCreate: usersCreateOrConnectWithoutAccess_tokenInput - connect: usersWhereUniqueInput -} - -input access_tokenCreateInput { - id: String - token: String - name: String! - created_at: DateTime - users: usersCreateNestedOneWithoutAccess_tokenInput! -} - -input StringFieldUpdateOperationsInput { - set: String -} - -input DateTimeFieldUpdateOperationsInput { - set: DateTime -} - -input NullableStringFieldUpdateOperationsInput { - set: String -} - -input NullableDateTimeFieldUpdateOperationsInput { - set: DateTime -} - -input IntFieldUpdateOperationsInput { - set: Int - increment: Int - decrement: Int - multiply: Int - divide: Int -} - -input BoolFieldUpdateOperationsInput { - set: Boolean -} - -input price_planUpdateWithoutNamespaceInput { - name: StringFieldUpdateOperationsInput - quota_daily_requests: IntFieldUpdateOperationsInput - quota_environments: IntFieldUpdateOperationsInput - quota_members: IntFieldUpdateOperationsInput - quota_apis: IntFieldUpdateOperationsInput - allow_secondary_environments: BoolFieldUpdateOperationsInput -} - -input price_planUpsertWithoutNamespaceInput { - update: price_planUpdateWithoutNamespaceInput! - create: price_planCreateWithoutNamespaceInput! -} - -input price_planUpdateOneRequiredWithoutNamespaceInput { - create: price_planCreateWithoutNamespaceInput - connectOrCreate: price_planCreateOrConnectWithoutNamespaceInput - upsert: price_planUpsertWithoutNamespaceInput - connect: price_planWhereUniqueInput - update: price_planUpdateWithoutNamespaceInput -} - -input environmentUpdatehostnamesInput { - set: [String] - push: [String] -} - -input access_tokenUpdateWithoutUsersInput { - id: StringFieldUpdateOperationsInput - token: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput -} - -input access_tokenUpsertWithWhereUniqueWithoutUsersInput { - where: access_tokenWhereUniqueInput! - update: access_tokenUpdateWithoutUsersInput! - create: access_tokenCreateWithoutUsersInput! -} - -input access_tokenUpdateWithWhereUniqueWithoutUsersInput { - where: access_tokenWhereUniqueInput! - data: access_tokenUpdateWithoutUsersInput! -} - -input access_tokenScalarWhereInput { - AND: access_tokenScalarWhereInput - OR: [access_tokenScalarWhereInput] - NOT: access_tokenScalarWhereInput - id: StringFilter - token: StringFilter - user_id: StringFilter - name: StringFilter - created_at: DateTimeFilter -} - -input access_tokenUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - token: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput -} - -input access_tokenUpdateManyWithWhereWithoutUsersInput { - where: access_tokenScalarWhereInput! - data: access_tokenUpdateManyMutationInput! -} - -input access_tokenUpdateManyWithoutUsersInput { - create: access_tokenCreateWithoutUsersInput - connectOrCreate: access_tokenCreateOrConnectWithoutUsersInput - upsert: access_tokenUpsertWithWhereUniqueWithoutUsersInput - createMany: access_tokenCreateManyUsersInputEnvelope - connect: access_tokenWhereUniqueInput - set: access_tokenWhereUniqueInput - disconnect: access_tokenWhereUniqueInput - delete: access_tokenWhereUniqueInput - update: access_tokenUpdateWithWhereUniqueWithoutUsersInput - updateMany: access_tokenUpdateManyWithWhereWithoutUsersInput - deleteMany: access_tokenScalarWhereInput -} - -input usersUpdateWithoutNamespace_membersInput { - id: StringFieldUpdateOperationsInput - name: NullableStringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - role: user_role - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - access_token: access_tokenUpdateManyWithoutUsersInput -} - -input usersUpsertWithoutNamespace_membersInput { - update: usersUpdateWithoutNamespace_membersInput! - create: usersCreateWithoutNamespace_membersInput! -} - -input usersUpdateOneRequiredWithoutNamespace_membersInput { - create: usersCreateWithoutNamespace_membersInput - connectOrCreate: usersCreateOrConnectWithoutNamespace_membersInput - upsert: usersUpsertWithoutNamespace_membersInput - connect: usersWhereUniqueInput - update: usersUpdateWithoutNamespace_membersInput -} - -input namespace_membersUpdateWithoutNamespaceInput { - membership: membership - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - users: usersUpdateOneRequiredWithoutNamespace_membersInput -} - -input namespace_membersUpsertWithWhereUniqueWithoutNamespaceInput { - where: namespace_membersWhereUniqueInput! - update: namespace_membersUpdateWithoutNamespaceInput! - create: namespace_membersCreateWithoutNamespaceInput! -} - -input namespace_membersUpdateWithWhereUniqueWithoutNamespaceInput { - where: namespace_membersWhereUniqueInput! - data: namespace_membersUpdateWithoutNamespaceInput! -} - -input namespace_membersScalarWhereInput { - AND: namespace_membersScalarWhereInput - OR: [namespace_membersScalarWhereInput] - NOT: namespace_membersScalarWhereInput - user_id: StringFilter - namespace_id: StringFilter - membership: EnummembershipFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input namespace_membersUpdateManyMutationInput { - membership: membership - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input namespace_membersUpdateManyWithWhereWithoutNamespaceInput { - where: namespace_membersScalarWhereInput! - data: namespace_membersUpdateManyMutationInput! -} - -input namespace_membersUpdateManyWithoutNamespaceInput { - create: namespace_membersCreateWithoutNamespaceInput - connectOrCreate: namespace_membersCreateOrConnectWithoutNamespaceInput - upsert: namespace_membersUpsertWithWhereUniqueWithoutNamespaceInput - createMany: namespace_membersCreateManyNamespaceInputEnvelope - connect: namespace_membersWhereUniqueInput - set: namespace_membersWhereUniqueInput - disconnect: namespace_membersWhereUniqueInput - delete: namespace_membersWhereUniqueInput - update: namespace_membersUpdateWithWhereUniqueWithoutNamespaceInput - updateMany: namespace_membersUpdateManyWithWhereWithoutNamespaceInput - deleteMany: namespace_membersScalarWhereInput -} - -input namespaceUpdateWithoutEnvironmentInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - price_plan: price_planUpdateOneRequiredWithoutNamespaceInput - api: apiUpdateManyWithoutNamespaceInput - namespace_members: namespace_membersUpdateManyWithoutNamespaceInput -} - -input namespaceUpsertWithoutEnvironmentInput { - update: namespaceUpdateWithoutEnvironmentInput! - create: namespaceCreateWithoutEnvironmentInput! -} - -input namespaceUpdateOneRequiredWithoutEnvironmentInput { - create: namespaceCreateWithoutEnvironmentInput - connectOrCreate: namespaceCreateOrConnectWithoutEnvironmentInput - upsert: namespaceUpsertWithoutEnvironmentInput - connect: namespaceWhereUniqueInput - update: namespaceUpdateWithoutEnvironmentInput -} - -input edgeUpdateWithoutEnvironment_edgesInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - location: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input edgeUpsertWithoutEnvironment_edgesInput { - update: edgeUpdateWithoutEnvironment_edgesInput! - create: edgeCreateWithoutEnvironment_edgesInput! -} - -input edgeUpdateOneRequiredWithoutEnvironment_edgesInput { - create: edgeCreateWithoutEnvironment_edgesInput - connectOrCreate: edgeCreateOrConnectWithoutEnvironment_edgesInput - upsert: edgeUpsertWithoutEnvironment_edgesInput - connect: edgeWhereUniqueInput - update: edgeUpdateWithoutEnvironment_edgesInput -} - -input environment_edgesUpdateWithoutEnvironmentInput { - edge: edgeUpdateOneRequiredWithoutEnvironment_edgesInput -} - -input environment_edgesUpsertWithWhereUniqueWithoutEnvironmentInput { - where: environment_edgesWhereUniqueInput! - update: environment_edgesUpdateWithoutEnvironmentInput! - create: environment_edgesCreateWithoutEnvironmentInput! -} - -input environment_edgesUpdateWithWhereUniqueWithoutEnvironmentInput { - where: environment_edgesWhereUniqueInput! - data: environment_edgesUpdateWithoutEnvironmentInput! -} - -input environment_edgesScalarWhereInput { - AND: environment_edgesScalarWhereInput - OR: [environment_edgesScalarWhereInput] - NOT: environment_edgesScalarWhereInput - environment_id: StringFilter - edge_id: StringFilter -} - -input environment_edgesUpdateManyWithWhereWithoutEnvironmentInput { - where: environment_edgesScalarWhereInput! -} - -input environment_edgesUpdateManyWithoutEnvironmentInput { - create: environment_edgesCreateWithoutEnvironmentInput - connectOrCreate: environment_edgesCreateOrConnectWithoutEnvironmentInput - upsert: environment_edgesUpsertWithWhereUniqueWithoutEnvironmentInput - createMany: environment_edgesCreateManyEnvironmentInputEnvelope - connect: environment_edgesWhereUniqueInput - set: environment_edgesWhereUniqueInput - disconnect: environment_edgesWhereUniqueInput - delete: environment_edgesWhereUniqueInput - update: environment_edgesUpdateWithWhereUniqueWithoutEnvironmentInput - updateMany: environment_edgesUpdateManyWithWhereWithoutEnvironmentInput - deleteMany: environment_edgesScalarWhereInput -} - -input wundernodeUpdateWithoutNodepoolInput { - id: StringFieldUpdateOperationsInput - etag: StringFieldUpdateOperationsInput - config: DateTime - ipv4: NullableStringFieldUpdateOperationsInput - ipv6: NullableStringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input wundernodeUpsertWithoutNodepoolInput { - update: wundernodeUpdateWithoutNodepoolInput! - create: wundernodeCreateWithoutNodepoolInput! -} - -input wundernodeUpdateOneRequiredWithoutNodepoolInput { - create: wundernodeCreateWithoutNodepoolInput - connectOrCreate: wundernodeCreateOrConnectWithoutNodepoolInput - upsert: wundernodeUpsertWithoutNodepoolInput - connect: wundernodeWhereUniqueInput - update: wundernodeUpdateWithoutNodepoolInput -} - -input nodepoolUpdateWithoutNodepool_environmentInput { - id: StringFieldUpdateOperationsInput - shared: BoolFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - wundernode: wundernodeUpdateOneRequiredWithoutNodepoolInput -} - -input nodepoolUpsertWithoutNodepool_environmentInput { - update: nodepoolUpdateWithoutNodepool_environmentInput! - create: nodepoolCreateWithoutNodepool_environmentInput! -} - -input nodepoolUpdateOneRequiredWithoutNodepool_environmentInput { - create: nodepoolCreateWithoutNodepool_environmentInput - connectOrCreate: nodepoolCreateOrConnectWithoutNodepool_environmentInput - upsert: nodepoolUpsertWithoutNodepool_environmentInput - connect: nodepoolWhereUniqueInput - update: nodepoolUpdateWithoutNodepool_environmentInput -} - -input nodepool_environmentUpdateWithoutEnvironmentInput { - nodepool: nodepoolUpdateOneRequiredWithoutNodepool_environmentInput -} - -input nodepool_environmentUpsertWithWhereUniqueWithoutEnvironmentInput { - where: nodepool_environmentWhereUniqueInput! - update: nodepool_environmentUpdateWithoutEnvironmentInput! - create: nodepool_environmentCreateWithoutEnvironmentInput! -} - -input nodepool_environmentUpdateWithWhereUniqueWithoutEnvironmentInput { - where: nodepool_environmentWhereUniqueInput! - data: nodepool_environmentUpdateWithoutEnvironmentInput! -} - -input nodepool_environmentScalarWhereInput { - AND: nodepool_environmentScalarWhereInput - OR: [nodepool_environmentScalarWhereInput] - NOT: nodepool_environmentScalarWhereInput - nodepool_id: StringFilter - environment_id: StringFilter -} - -input nodepool_environmentUpdateManyWithWhereWithoutEnvironmentInput { - where: nodepool_environmentScalarWhereInput! -} - -input nodepool_environmentUpdateManyWithoutEnvironmentInput { - create: nodepool_environmentCreateWithoutEnvironmentInput - connectOrCreate: nodepool_environmentCreateOrConnectWithoutEnvironmentInput - upsert: nodepool_environmentUpsertWithWhereUniqueWithoutEnvironmentInput - createMany: nodepool_environmentCreateManyEnvironmentInputEnvelope - connect: nodepool_environmentWhereUniqueInput - set: nodepool_environmentWhereUniqueInput - disconnect: nodepool_environmentWhereUniqueInput - delete: nodepool_environmentWhereUniqueInput - update: nodepool_environmentUpdateWithWhereUniqueWithoutEnvironmentInput - updateMany: nodepool_environmentUpdateManyWithWhereWithoutEnvironmentInput - deleteMany: nodepool_environmentScalarWhereInput -} - -input environmentUpdateWithoutDeployment_environmentInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - primary_hostname: StringFieldUpdateOperationsInput - primary: BoolFieldUpdateOperationsInput - hostnames: environmentUpdatehostnamesInput - namespace: namespaceUpdateOneRequiredWithoutEnvironmentInput - environment_edges: environment_edgesUpdateManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentUpdateManyWithoutEnvironmentInput -} - -input environmentUpsertWithoutDeployment_environmentInput { - update: environmentUpdateWithoutDeployment_environmentInput! - create: environmentCreateWithoutDeployment_environmentInput! -} - -input environmentUpdateOneRequiredWithoutDeployment_environmentInput { - create: environmentCreateWithoutDeployment_environmentInput - connectOrCreate: environmentCreateOrConnectWithoutDeployment_environmentInput - upsert: environmentUpsertWithoutDeployment_environmentInput - connect: environmentWhereUniqueInput - update: environmentUpdateWithoutDeployment_environmentInput -} - -input deployment_environmentUpdateWithoutDeploymentInput { - environment: environmentUpdateOneRequiredWithoutDeployment_environmentInput -} - -input deployment_environmentUpsertWithWhereUniqueWithoutDeploymentInput { - where: deployment_environmentWhereUniqueInput! - update: deployment_environmentUpdateWithoutDeploymentInput! - create: deployment_environmentCreateWithoutDeploymentInput! -} - -input deployment_environmentUpdateWithWhereUniqueWithoutDeploymentInput { - where: deployment_environmentWhereUniqueInput! - data: deployment_environmentUpdateWithoutDeploymentInput! -} - -input deployment_environmentScalarWhereInput { - AND: deployment_environmentScalarWhereInput - OR: [deployment_environmentScalarWhereInput] - NOT: deployment_environmentScalarWhereInput - deployment_id: StringFilter - environment_id: StringFilter -} - -input deployment_environmentUpdateManyWithWhereWithoutDeploymentInput { - where: deployment_environmentScalarWhereInput! -} - -input deployment_environmentUpdateManyWithoutDeploymentInput { - create: deployment_environmentCreateWithoutDeploymentInput - connectOrCreate: deployment_environmentCreateOrConnectWithoutDeploymentInput - upsert: deployment_environmentUpsertWithWhereUniqueWithoutDeploymentInput - createMany: deployment_environmentCreateManyDeploymentInputEnvelope - connect: deployment_environmentWhereUniqueInput - set: deployment_environmentWhereUniqueInput - disconnect: deployment_environmentWhereUniqueInput - delete: deployment_environmentWhereUniqueInput - update: deployment_environmentUpdateWithWhereUniqueWithoutDeploymentInput - updateMany: deployment_environmentUpdateManyWithWhereWithoutDeploymentInput - deleteMany: deployment_environmentScalarWhereInput -} - -input deploymentUpdateWithoutApiInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - config: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - deployment_environment: deployment_environmentUpdateManyWithoutDeploymentInput -} - -input deploymentUpsertWithWhereUniqueWithoutApiInput { - where: deploymentWhereUniqueInput! - update: deploymentUpdateWithoutApiInput! - create: deploymentCreateWithoutApiInput! -} - -input deploymentUpdateWithWhereUniqueWithoutApiInput { - where: deploymentWhereUniqueInput! - data: deploymentUpdateWithoutApiInput! -} - -input deploymentScalarWhereInput { - AND: deploymentScalarWhereInput - OR: [deploymentScalarWhereInput] - NOT: deploymentScalarWhereInput - id: StringFilter - api_id: StringFilter - name: StringFilter - config: JsonFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input deploymentUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - config: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input deploymentUpdateManyWithWhereWithoutApiInput { - where: deploymentScalarWhereInput! - data: deploymentUpdateManyMutationInput! -} - -input deploymentUpdateManyWithoutApiInput { - create: deploymentCreateWithoutApiInput - connectOrCreate: deploymentCreateOrConnectWithoutApiInput - upsert: deploymentUpsertWithWhereUniqueWithoutApiInput - createMany: deploymentCreateManyApiInputEnvelope - connect: deploymentWhereUniqueInput - set: deploymentWhereUniqueInput - disconnect: deploymentWhereUniqueInput - delete: deploymentWhereUniqueInput - update: deploymentUpdateWithWhereUniqueWithoutApiInput - updateMany: deploymentUpdateManyWithWhereWithoutApiInput - deleteMany: deploymentScalarWhereInput -} - -input apiUpdateWithoutNamespaceInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - markdown_description: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - deployment: deploymentUpdateManyWithoutApiInput -} - -input apiUpsertWithWhereUniqueWithoutNamespaceInput { - where: apiWhereUniqueInput! - update: apiUpdateWithoutNamespaceInput! - create: apiCreateWithoutNamespaceInput! -} - -input apiUpdateWithWhereUniqueWithoutNamespaceInput { - where: apiWhereUniqueInput! - data: apiUpdateWithoutNamespaceInput! -} - -input apiScalarWhereInput { - AND: apiScalarWhereInput - OR: [apiScalarWhereInput] - NOT: apiScalarWhereInput - id: StringFilter - namespace_id: StringFilter - name: StringFilter - markdown_description: StringFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input apiUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - markdown_description: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input apiUpdateManyWithWhereWithoutNamespaceInput { - where: apiScalarWhereInput! - data: apiUpdateManyMutationInput! -} - -input apiUpdateManyWithoutNamespaceInput { - create: apiCreateWithoutNamespaceInput - connectOrCreate: apiCreateOrConnectWithoutNamespaceInput - upsert: apiUpsertWithWhereUniqueWithoutNamespaceInput - createMany: apiCreateManyNamespaceInputEnvelope - connect: apiWhereUniqueInput - set: apiWhereUniqueInput - disconnect: apiWhereUniqueInput - delete: apiWhereUniqueInput - update: apiUpdateWithWhereUniqueWithoutNamespaceInput - updateMany: apiUpdateManyWithWhereWithoutNamespaceInput - deleteMany: apiScalarWhereInput -} - -input namespaceUpdateWithoutApiInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - price_plan: price_planUpdateOneRequiredWithoutNamespaceInput - environment: environmentUpdateManyWithoutNamespaceInput - namespace_members: namespace_membersUpdateManyWithoutNamespaceInput -} - -input namespaceUpsertWithoutApiInput { - update: namespaceUpdateWithoutApiInput! - create: namespaceCreateWithoutApiInput! -} - -input namespaceUpdateOneRequiredWithoutApiInput { - create: namespaceCreateWithoutApiInput - connectOrCreate: namespaceCreateOrConnectWithoutApiInput - upsert: namespaceUpsertWithoutApiInput - connect: namespaceWhereUniqueInput - update: namespaceUpdateWithoutApiInput -} - -input apiUpdateWithoutDeploymentInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - markdown_description: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - namespace: namespaceUpdateOneRequiredWithoutApiInput -} - -input apiUpsertWithoutDeploymentInput { - update: apiUpdateWithoutDeploymentInput! - create: apiCreateWithoutDeploymentInput! -} - -input apiUpdateOneRequiredWithoutDeploymentInput { - create: apiCreateWithoutDeploymentInput - connectOrCreate: apiCreateOrConnectWithoutDeploymentInput - upsert: apiUpsertWithoutDeploymentInput - connect: apiWhereUniqueInput - update: apiUpdateWithoutDeploymentInput -} - -input deploymentUpdateWithoutDeployment_environmentInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - config: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - api: apiUpdateOneRequiredWithoutDeploymentInput -} - -input deploymentUpsertWithoutDeployment_environmentInput { - update: deploymentUpdateWithoutDeployment_environmentInput! - create: deploymentCreateWithoutDeployment_environmentInput! -} - -input deploymentUpdateOneRequiredWithoutDeployment_environmentInput { - create: deploymentCreateWithoutDeployment_environmentInput - connectOrCreate: deploymentCreateOrConnectWithoutDeployment_environmentInput - upsert: deploymentUpsertWithoutDeployment_environmentInput - connect: deploymentWhereUniqueInput - update: deploymentUpdateWithoutDeployment_environmentInput -} - -input deployment_environmentUpdateWithoutEnvironmentInput { - deployment: deploymentUpdateOneRequiredWithoutDeployment_environmentInput -} - -input deployment_environmentUpsertWithWhereUniqueWithoutEnvironmentInput { - where: deployment_environmentWhereUniqueInput! - update: deployment_environmentUpdateWithoutEnvironmentInput! - create: deployment_environmentCreateWithoutEnvironmentInput! -} - -input deployment_environmentUpdateWithWhereUniqueWithoutEnvironmentInput { - where: deployment_environmentWhereUniqueInput! - data: deployment_environmentUpdateWithoutEnvironmentInput! -} - -input deployment_environmentUpdateManyWithWhereWithoutEnvironmentInput { - where: deployment_environmentScalarWhereInput! -} - -input deployment_environmentUpdateManyWithoutEnvironmentInput { - create: deployment_environmentCreateWithoutEnvironmentInput - connectOrCreate: deployment_environmentCreateOrConnectWithoutEnvironmentInput - upsert: deployment_environmentUpsertWithWhereUniqueWithoutEnvironmentInput - createMany: deployment_environmentCreateManyEnvironmentInputEnvelope - connect: deployment_environmentWhereUniqueInput - set: deployment_environmentWhereUniqueInput - disconnect: deployment_environmentWhereUniqueInput - delete: deployment_environmentWhereUniqueInput - update: deployment_environmentUpdateWithWhereUniqueWithoutEnvironmentInput - updateMany: deployment_environmentUpdateManyWithWhereWithoutEnvironmentInput - deleteMany: deployment_environmentScalarWhereInput -} - -input environmentUpdateWithoutNamespaceInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - primary_hostname: StringFieldUpdateOperationsInput - primary: BoolFieldUpdateOperationsInput - hostnames: environmentUpdatehostnamesInput - deployment_environment: deployment_environmentUpdateManyWithoutEnvironmentInput - environment_edges: environment_edgesUpdateManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentUpdateManyWithoutEnvironmentInput -} - -input environmentUpsertWithWhereUniqueWithoutNamespaceInput { - where: environmentWhereUniqueInput! - update: environmentUpdateWithoutNamespaceInput! - create: environmentCreateWithoutNamespaceInput! -} - -input environmentUpdateWithWhereUniqueWithoutNamespaceInput { - where: environmentWhereUniqueInput! - data: environmentUpdateWithoutNamespaceInput! -} - -input environmentScalarWhereInput { - AND: environmentScalarWhereInput - OR: [environmentScalarWhereInput] - NOT: environmentScalarWhereInput - id: StringFilter - name: StringFilter - namespace_id: StringFilter - primary_hostname: StringFilter - hostnames: StringNullableListFilter - primary: BoolFilter -} - -input environmentUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - primary_hostname: StringFieldUpdateOperationsInput - primary: BoolFieldUpdateOperationsInput - hostnames: environmentUpdatehostnamesInput -} - -input environmentUpdateManyWithWhereWithoutNamespaceInput { - where: environmentScalarWhereInput! - data: environmentUpdateManyMutationInput! -} - -input environmentUpdateManyWithoutNamespaceInput { - create: environmentCreateWithoutNamespaceInput - connectOrCreate: environmentCreateOrConnectWithoutNamespaceInput - upsert: environmentUpsertWithWhereUniqueWithoutNamespaceInput - createMany: environmentCreateManyNamespaceInputEnvelope - connect: environmentWhereUniqueInput - set: environmentWhereUniqueInput - disconnect: environmentWhereUniqueInput - delete: environmentWhereUniqueInput - update: environmentUpdateWithWhereUniqueWithoutNamespaceInput - updateMany: environmentUpdateManyWithWhereWithoutNamespaceInput - deleteMany: environmentScalarWhereInput -} - -input namespaceUpdateWithoutNamespace_membersInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - price_plan: price_planUpdateOneRequiredWithoutNamespaceInput - api: apiUpdateManyWithoutNamespaceInput - environment: environmentUpdateManyWithoutNamespaceInput -} - -input namespaceUpsertWithoutNamespace_membersInput { - update: namespaceUpdateWithoutNamespace_membersInput! - create: namespaceCreateWithoutNamespace_membersInput! -} - -input namespaceUpdateOneRequiredWithoutNamespace_membersInput { - create: namespaceCreateWithoutNamespace_membersInput - connectOrCreate: namespaceCreateOrConnectWithoutNamespace_membersInput - upsert: namespaceUpsertWithoutNamespace_membersInput - connect: namespaceWhereUniqueInput - update: namespaceUpdateWithoutNamespace_membersInput -} - -input namespace_membersUpdateWithoutUsersInput { - membership: membership - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - namespace: namespaceUpdateOneRequiredWithoutNamespace_membersInput -} - -input namespace_membersUpsertWithWhereUniqueWithoutUsersInput { - where: namespace_membersWhereUniqueInput! - update: namespace_membersUpdateWithoutUsersInput! - create: namespace_membersCreateWithoutUsersInput! -} - -input namespace_membersUpdateWithWhereUniqueWithoutUsersInput { - where: namespace_membersWhereUniqueInput! - data: namespace_membersUpdateWithoutUsersInput! -} - -input namespace_membersUpdateManyWithWhereWithoutUsersInput { - where: namespace_membersScalarWhereInput! - data: namespace_membersUpdateManyMutationInput! -} - -input namespace_membersUpdateManyWithoutUsersInput { - create: namespace_membersCreateWithoutUsersInput - connectOrCreate: namespace_membersCreateOrConnectWithoutUsersInput - upsert: namespace_membersUpsertWithWhereUniqueWithoutUsersInput - createMany: namespace_membersCreateManyUsersInputEnvelope - connect: namespace_membersWhereUniqueInput - set: namespace_membersWhereUniqueInput - disconnect: namespace_membersWhereUniqueInput - delete: namespace_membersWhereUniqueInput - update: namespace_membersUpdateWithWhereUniqueWithoutUsersInput - updateMany: namespace_membersUpdateManyWithWhereWithoutUsersInput - deleteMany: namespace_membersScalarWhereInput -} - -input usersUpdateWithoutAccess_tokenInput { - id: StringFieldUpdateOperationsInput - name: NullableStringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - role: user_role - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - namespace_members: namespace_membersUpdateManyWithoutUsersInput -} - -input usersUpsertWithoutAccess_tokenInput { - update: usersUpdateWithoutAccess_tokenInput! - create: usersCreateWithoutAccess_tokenInput! -} - -input usersUpdateOneRequiredWithoutAccess_tokenInput { - create: usersCreateWithoutAccess_tokenInput - connectOrCreate: usersCreateOrConnectWithoutAccess_tokenInput - upsert: usersUpsertWithoutAccess_tokenInput - connect: usersWhereUniqueInput - update: usersUpdateWithoutAccess_tokenInput -} - -input access_tokenUpdateInput { - id: StringFieldUpdateOperationsInput - token: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - users: usersUpdateOneRequiredWithoutAccess_tokenInput -} - -input access_tokenCreateManyInput { - id: String - token: String - user_id: String! - name: String! - created_at: DateTime -} - -type AffectedRowsOutput { - count: Int! -} - -input admin_configCreateInput { - id: String - wundernode_image_tag: String! - created_at: DateTime - updated_at: DateTime -} - -input admin_configUpdateInput { - id: StringFieldUpdateOperationsInput - wundernode_image_tag: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input admin_configCreateManyInput { - id: String - wundernode_image_tag: String! - created_at: DateTime - updated_at: DateTime -} - -input admin_configUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - wundernode_image_tag: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input apiCreateInput { - id: String - name: String! - markdown_description: String! - created_at: DateTime - updated_at: DateTime - namespace: namespaceCreateNestedOneWithoutApiInput! - deployment: deploymentCreateNestedManyWithoutApiInput -} - -input apiUpdateInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - markdown_description: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - namespace: namespaceUpdateOneRequiredWithoutApiInput - deployment: deploymentUpdateManyWithoutApiInput -} - -input apiCreateManyInput { - id: String - namespace_id: String! - name: String! - markdown_description: String! - created_at: DateTime - updated_at: DateTime -} - -input deploymentCreateInput { - id: String - name: String! - config: DateTime! - created_at: DateTime - updated_at: DateTime - api: apiCreateNestedOneWithoutDeploymentInput! - deployment_environment: deployment_environmentCreateNestedManyWithoutDeploymentInput -} - -input deploymentUpdateInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - config: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - api: apiUpdateOneRequiredWithoutDeploymentInput - deployment_environment: deployment_environmentUpdateManyWithoutDeploymentInput -} - -input deploymentCreateManyInput { - id: String - api_id: String! - name: String! - config: DateTime! - created_at: DateTime - updated_at: DateTime -} - -input deployment_environmentCreateInput { - deployment: deploymentCreateNestedOneWithoutDeployment_environmentInput! - environment: environmentCreateNestedOneWithoutDeployment_environmentInput! -} - -input deployment_environmentUpdateInput { - deployment: deploymentUpdateOneRequiredWithoutDeployment_environmentInput - environment: environmentUpdateOneRequiredWithoutDeployment_environmentInput -} - -input deployment_environmentCreateManyInput { - deployment_id: String! - environment_id: String! -} - -input environmentCreateWithoutEnvironment_edgesInput { - id: String - name: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreatehostnamesInput - namespace: namespaceCreateNestedOneWithoutEnvironmentInput! - deployment_environment: deployment_environmentCreateNestedManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentCreateNestedManyWithoutEnvironmentInput -} - -input environmentCreateOrConnectWithoutEnvironment_edgesInput { - where: environmentWhereUniqueInput! - create: environmentCreateWithoutEnvironment_edgesInput! -} - -input environmentCreateNestedOneWithoutEnvironment_edgesInput { - create: environmentCreateWithoutEnvironment_edgesInput - connectOrCreate: environmentCreateOrConnectWithoutEnvironment_edgesInput - connect: environmentWhereUniqueInput -} - -input environment_edgesCreateWithoutEdgeInput { - environment: environmentCreateNestedOneWithoutEnvironment_edgesInput! -} - -input environment_edgesCreateOrConnectWithoutEdgeInput { - where: environment_edgesWhereUniqueInput! - create: environment_edgesCreateWithoutEdgeInput! -} - -input environment_edgesCreateManyEdgeInput { - environment_id: String! -} - -input environment_edgesCreateManyEdgeInputEnvelope { - data: [environment_edgesCreateManyEdgeInput]! - skipDuplicates: Boolean -} - -input environment_edgesCreateNestedManyWithoutEdgeInput { - create: environment_edgesCreateWithoutEdgeInput - connectOrCreate: environment_edgesCreateOrConnectWithoutEdgeInput - createMany: environment_edgesCreateManyEdgeInputEnvelope - connect: environment_edgesWhereUniqueInput -} - -input edgeCreateInput { - id: String - name: String! - location: String! - created_at: DateTime - updated_at: DateTime - environment_edges: environment_edgesCreateNestedManyWithoutEdgeInput -} - -input environmentUpdateWithoutEnvironment_edgesInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - primary_hostname: StringFieldUpdateOperationsInput - primary: BoolFieldUpdateOperationsInput - hostnames: environmentUpdatehostnamesInput - namespace: namespaceUpdateOneRequiredWithoutEnvironmentInput - deployment_environment: deployment_environmentUpdateManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentUpdateManyWithoutEnvironmentInput -} - -input environmentUpsertWithoutEnvironment_edgesInput { - update: environmentUpdateWithoutEnvironment_edgesInput! - create: environmentCreateWithoutEnvironment_edgesInput! -} - -input environmentUpdateOneRequiredWithoutEnvironment_edgesInput { - create: environmentCreateWithoutEnvironment_edgesInput - connectOrCreate: environmentCreateOrConnectWithoutEnvironment_edgesInput - upsert: environmentUpsertWithoutEnvironment_edgesInput - connect: environmentWhereUniqueInput - update: environmentUpdateWithoutEnvironment_edgesInput -} - -input environment_edgesUpdateWithoutEdgeInput { - environment: environmentUpdateOneRequiredWithoutEnvironment_edgesInput -} - -input environment_edgesUpsertWithWhereUniqueWithoutEdgeInput { - where: environment_edgesWhereUniqueInput! - update: environment_edgesUpdateWithoutEdgeInput! - create: environment_edgesCreateWithoutEdgeInput! -} - -input environment_edgesUpdateWithWhereUniqueWithoutEdgeInput { - where: environment_edgesWhereUniqueInput! - data: environment_edgesUpdateWithoutEdgeInput! -} - -input environment_edgesUpdateManyWithWhereWithoutEdgeInput { - where: environment_edgesScalarWhereInput! -} - -input environment_edgesUpdateManyWithoutEdgeInput { - create: environment_edgesCreateWithoutEdgeInput - connectOrCreate: environment_edgesCreateOrConnectWithoutEdgeInput - upsert: environment_edgesUpsertWithWhereUniqueWithoutEdgeInput - createMany: environment_edgesCreateManyEdgeInputEnvelope - connect: environment_edgesWhereUniqueInput - set: environment_edgesWhereUniqueInput - disconnect: environment_edgesWhereUniqueInput - delete: environment_edgesWhereUniqueInput - update: environment_edgesUpdateWithWhereUniqueWithoutEdgeInput - updateMany: environment_edgesUpdateManyWithWhereWithoutEdgeInput - deleteMany: environment_edgesScalarWhereInput -} - -input edgeUpdateInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - location: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - environment_edges: environment_edgesUpdateManyWithoutEdgeInput -} - -input edgeCreateManyInput { - id: String - name: String! - location: String! - created_at: DateTime - updated_at: DateTime -} - -input edgeUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - location: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input environmentCreateInput { - id: String - name: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreatehostnamesInput - namespace: namespaceCreateNestedOneWithoutEnvironmentInput! - deployment_environment: deployment_environmentCreateNestedManyWithoutEnvironmentInput - environment_edges: environment_edgesCreateNestedManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentCreateNestedManyWithoutEnvironmentInput -} - -input environmentUpdateInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - primary_hostname: StringFieldUpdateOperationsInput - primary: BoolFieldUpdateOperationsInput - hostnames: environmentUpdatehostnamesInput - namespace: namespaceUpdateOneRequiredWithoutEnvironmentInput - deployment_environment: deployment_environmentUpdateManyWithoutEnvironmentInput - environment_edges: environment_edgesUpdateManyWithoutEnvironmentInput - nodepool_environment: nodepool_environmentUpdateManyWithoutEnvironmentInput -} - -input environmentCreateManyInput { - id: String - name: String! - namespace_id: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreateManyhostnamesInput -} - -input environment_edgesCreateInput { - edge: edgeCreateNestedOneWithoutEnvironment_edgesInput! - environment: environmentCreateNestedOneWithoutEnvironment_edgesInput! -} - -input environment_edgesUpdateInput { - edge: edgeUpdateOneRequiredWithoutEnvironment_edgesInput - environment: environmentUpdateOneRequiredWithoutEnvironment_edgesInput -} - -input environment_edgesCreateManyInput { - environment_id: String! - edge_id: String! -} - -input letsencrypt_certificateCreateadditional_domainsInput { - set: [String]! -} - -input letsencrypt_userCreateWithoutLetsencrypt_certificateInput { - zone: String! - email: String! - dns_provider_name: String! - dns_provider_token: String! - private_key: String - registration_resource: DateTime - created_at: DateTime - updated_at: DateTime -} - -input letsencrypt_userCreateOrConnectWithoutLetsencrypt_certificateInput { - where: letsencrypt_userWhereUniqueInput! - create: letsencrypt_userCreateWithoutLetsencrypt_certificateInput! -} - -input letsencrypt_userCreateNestedOneWithoutLetsencrypt_certificateInput { - create: letsencrypt_userCreateWithoutLetsencrypt_certificateInput - connectOrCreate: letsencrypt_userCreateOrConnectWithoutLetsencrypt_certificateInput - connect: letsencrypt_userWhereUniqueInput -} - -input letsencrypt_certificateCreateInput { - common_name: String! - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime - updated_at: DateTime - additional_domains: letsencrypt_certificateCreateadditional_domainsInput - letsencrypt_user: letsencrypt_userCreateNestedOneWithoutLetsencrypt_certificateInput! -} - -input letsencrypt_certificateUpdateadditional_domainsInput { - set: [String] - push: [String] -} - -input letsencrypt_userUpdateWithoutLetsencrypt_certificateInput { - zone: StringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - dns_provider_name: StringFieldUpdateOperationsInput - dns_provider_token: StringFieldUpdateOperationsInput - private_key: NullableStringFieldUpdateOperationsInput - registration_resource: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input letsencrypt_userUpsertWithoutLetsencrypt_certificateInput { - update: letsencrypt_userUpdateWithoutLetsencrypt_certificateInput! - create: letsencrypt_userCreateWithoutLetsencrypt_certificateInput! -} - -input letsencrypt_userUpdateOneRequiredWithoutLetsencrypt_certificateInput { - create: letsencrypt_userCreateWithoutLetsencrypt_certificateInput - connectOrCreate: letsencrypt_userCreateOrConnectWithoutLetsencrypt_certificateInput - upsert: letsencrypt_userUpsertWithoutLetsencrypt_certificateInput - connect: letsencrypt_userWhereUniqueInput - update: letsencrypt_userUpdateWithoutLetsencrypt_certificateInput -} - -input letsencrypt_certificateUpdateInput { - common_name: StringFieldUpdateOperationsInput - issued: NullableDateTimeFieldUpdateOperationsInput - renewal: NullableDateTimeFieldUpdateOperationsInput - certificate: NullableStringFieldUpdateOperationsInput - private_key: NullableStringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - additional_domains: letsencrypt_certificateUpdateadditional_domainsInput - letsencrypt_user: letsencrypt_userUpdateOneRequiredWithoutLetsencrypt_certificateInput -} - -input letsencrypt_certificateCreateManyadditional_domainsInput { - set: [String]! -} - -input letsencrypt_certificateCreateManyInput { - common_name: String! - zone: String! - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime - updated_at: DateTime - additional_domains: letsencrypt_certificateCreateManyadditional_domainsInput -} - -input letsencrypt_certificateUpdateManyMutationInput { - common_name: StringFieldUpdateOperationsInput - issued: NullableDateTimeFieldUpdateOperationsInput - renewal: NullableDateTimeFieldUpdateOperationsInput - certificate: NullableStringFieldUpdateOperationsInput - private_key: NullableStringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - additional_domains: letsencrypt_certificateUpdateadditional_domainsInput -} - -input letsencrypt_certificateCreateWithoutLetsencrypt_userInput { - common_name: String! - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime - updated_at: DateTime - additional_domains: letsencrypt_certificateCreateadditional_domainsInput -} - -input letsencrypt_certificateCreateOrConnectWithoutLetsencrypt_userInput { - where: letsencrypt_certificateWhereUniqueInput! - create: letsencrypt_certificateCreateWithoutLetsencrypt_userInput! -} - -input letsencrypt_certificateCreateManyLetsencrypt_userInput { - common_name: String! - issued: DateTime - renewal: DateTime - certificate: String - private_key: String - created_at: DateTime - updated_at: DateTime - additional_domains: letsencrypt_certificateCreateManyadditional_domainsInput -} - -input letsencrypt_certificateCreateManyLetsencrypt_userInputEnvelope { - data: [letsencrypt_certificateCreateManyLetsencrypt_userInput]! - skipDuplicates: Boolean -} - -input letsencrypt_certificateCreateNestedManyWithoutLetsencrypt_userInput { - create: letsencrypt_certificateCreateWithoutLetsencrypt_userInput - connectOrCreate: letsencrypt_certificateCreateOrConnectWithoutLetsencrypt_userInput - createMany: letsencrypt_certificateCreateManyLetsencrypt_userInputEnvelope - connect: letsencrypt_certificateWhereUniqueInput -} - -input letsencrypt_userCreateInput { - zone: String! - email: String! - dns_provider_name: String! - dns_provider_token: String! - private_key: String - registration_resource: DateTime - created_at: DateTime - updated_at: DateTime - letsencrypt_certificate: letsencrypt_certificateCreateNestedManyWithoutLetsencrypt_userInput -} - -input letsencrypt_certificateUpdateWithoutLetsencrypt_userInput { - common_name: StringFieldUpdateOperationsInput - issued: NullableDateTimeFieldUpdateOperationsInput - renewal: NullableDateTimeFieldUpdateOperationsInput - certificate: NullableStringFieldUpdateOperationsInput - private_key: NullableStringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - additional_domains: letsencrypt_certificateUpdateadditional_domainsInput -} - -input letsencrypt_certificateUpsertWithWhereUniqueWithoutLetsencrypt_userInput { - where: letsencrypt_certificateWhereUniqueInput! - update: letsencrypt_certificateUpdateWithoutLetsencrypt_userInput! - create: letsencrypt_certificateCreateWithoutLetsencrypt_userInput! -} - -input letsencrypt_certificateUpdateWithWhereUniqueWithoutLetsencrypt_userInput { - where: letsencrypt_certificateWhereUniqueInput! - data: letsencrypt_certificateUpdateWithoutLetsencrypt_userInput! -} - -input letsencrypt_certificateScalarWhereInput { - AND: letsencrypt_certificateScalarWhereInput - OR: [letsencrypt_certificateScalarWhereInput] - NOT: letsencrypt_certificateScalarWhereInput - common_name: StringFilter - zone: StringFilter - additional_domains: StringNullableListFilter - issued: DateTimeNullableFilter - renewal: DateTimeNullableFilter - certificate: StringNullableFilter - private_key: StringNullableFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input letsencrypt_certificateUpdateManyWithWhereWithoutLetsencrypt_userInput { - where: letsencrypt_certificateScalarWhereInput! - data: letsencrypt_certificateUpdateManyMutationInput! -} - -input letsencrypt_certificateUpdateManyWithoutLetsencrypt_userInput { - create: letsencrypt_certificateCreateWithoutLetsencrypt_userInput - connectOrCreate: letsencrypt_certificateCreateOrConnectWithoutLetsencrypt_userInput - upsert: letsencrypt_certificateUpsertWithWhereUniqueWithoutLetsencrypt_userInput - createMany: letsencrypt_certificateCreateManyLetsencrypt_userInputEnvelope - connect: letsencrypt_certificateWhereUniqueInput - set: letsencrypt_certificateWhereUniqueInput - disconnect: letsencrypt_certificateWhereUniqueInput - delete: letsencrypt_certificateWhereUniqueInput - update: letsencrypt_certificateUpdateWithWhereUniqueWithoutLetsencrypt_userInput - updateMany: letsencrypt_certificateUpdateManyWithWhereWithoutLetsencrypt_userInput - deleteMany: letsencrypt_certificateScalarWhereInput -} - -input letsencrypt_userUpdateInput { - zone: StringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - dns_provider_name: StringFieldUpdateOperationsInput - dns_provider_token: StringFieldUpdateOperationsInput - private_key: NullableStringFieldUpdateOperationsInput - registration_resource: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - letsencrypt_certificate: letsencrypt_certificateUpdateManyWithoutLetsencrypt_userInput -} - -input letsencrypt_userCreateManyInput { - zone: String! - email: String! - dns_provider_name: String! - dns_provider_token: String! - private_key: String - registration_resource: DateTime - created_at: DateTime - updated_at: DateTime -} - -input letsencrypt_userUpdateManyMutationInput { - zone: StringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - dns_provider_name: StringFieldUpdateOperationsInput - dns_provider_token: StringFieldUpdateOperationsInput - private_key: NullableStringFieldUpdateOperationsInput - registration_resource: DateTime - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input locksCreateInput { - name: String! - record_version_number: BigInt - data: String - owner: String -} - -input NullableBigIntFieldUpdateOperationsInput { - set: BigInt - increment: BigInt - decrement: BigInt - multiply: BigInt - divide: BigInt -} - -input locksUpdateInput { - name: StringFieldUpdateOperationsInput - record_version_number: NullableBigIntFieldUpdateOperationsInput - data: NullableStringFieldUpdateOperationsInput - owner: NullableStringFieldUpdateOperationsInput -} - -input locksCreateManyInput { - name: String! - record_version_number: BigInt - data: String - owner: String -} - -input locksUpdateManyMutationInput { - name: StringFieldUpdateOperationsInput - record_version_number: NullableBigIntFieldUpdateOperationsInput - data: NullableStringFieldUpdateOperationsInput - owner: NullableStringFieldUpdateOperationsInput -} - -input namespaceCreateInput { - id: String - name: String! - created_at: DateTime - updated_at: DateTime - price_plan: price_planCreateNestedOneWithoutNamespaceInput - api: apiCreateNestedManyWithoutNamespaceInput - environment: environmentCreateNestedManyWithoutNamespaceInput - namespace_members: namespace_membersCreateNestedManyWithoutNamespaceInput -} - -input namespaceUpdateInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - price_plan: price_planUpdateOneRequiredWithoutNamespaceInput - api: apiUpdateManyWithoutNamespaceInput - environment: environmentUpdateManyWithoutNamespaceInput - namespace_members: namespace_membersUpdateManyWithoutNamespaceInput -} - -input namespaceCreateManyInput { - id: String - name: String! - price_plan_id: Int - created_at: DateTime - updated_at: DateTime -} - -input namespaceUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input namespace_membersCreateInput { - membership: membership - created_at: DateTime - updated_at: DateTime - namespace: namespaceCreateNestedOneWithoutNamespace_membersInput! - users: usersCreateNestedOneWithoutNamespace_membersInput! -} - -input namespace_membersUpdateInput { - membership: membership - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - namespace: namespaceUpdateOneRequiredWithoutNamespace_membersInput - users: usersUpdateOneRequiredWithoutNamespace_membersInput -} - -input namespace_membersCreateManyInput { - user_id: String! - namespace_id: String! - membership: membership - created_at: DateTime - updated_at: DateTime -} - -input environmentCreateWithoutNodepool_environmentInput { - id: String - name: String! - primary_hostname: String - primary: Boolean - hostnames: environmentCreatehostnamesInput - namespace: namespaceCreateNestedOneWithoutEnvironmentInput! - deployment_environment: deployment_environmentCreateNestedManyWithoutEnvironmentInput - environment_edges: environment_edgesCreateNestedManyWithoutEnvironmentInput -} - -input environmentCreateOrConnectWithoutNodepool_environmentInput { - where: environmentWhereUniqueInput! - create: environmentCreateWithoutNodepool_environmentInput! -} - -input environmentCreateNestedOneWithoutNodepool_environmentInput { - create: environmentCreateWithoutNodepool_environmentInput - connectOrCreate: environmentCreateOrConnectWithoutNodepool_environmentInput - connect: environmentWhereUniqueInput -} - -input nodepool_environmentCreateWithoutNodepoolInput { - environment: environmentCreateNestedOneWithoutNodepool_environmentInput! -} - -input nodepool_environmentCreateOrConnectWithoutNodepoolInput { - where: nodepool_environmentWhereUniqueInput! - create: nodepool_environmentCreateWithoutNodepoolInput! -} - -input nodepool_environmentCreateManyNodepoolInput { - environment_id: String! -} - -input nodepool_environmentCreateManyNodepoolInputEnvelope { - data: [nodepool_environmentCreateManyNodepoolInput]! - skipDuplicates: Boolean -} - -input nodepool_environmentCreateNestedManyWithoutNodepoolInput { - create: nodepool_environmentCreateWithoutNodepoolInput - connectOrCreate: nodepool_environmentCreateOrConnectWithoutNodepoolInput - createMany: nodepool_environmentCreateManyNodepoolInputEnvelope - connect: nodepool_environmentWhereUniqueInput -} - -input nodepoolCreateInput { - id: String - shared: Boolean - created_at: DateTime - updated_at: DateTime - wundernode: wundernodeCreateNestedOneWithoutNodepoolInput! - nodepool_environment: nodepool_environmentCreateNestedManyWithoutNodepoolInput -} - -input environmentUpdateWithoutNodepool_environmentInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - primary_hostname: StringFieldUpdateOperationsInput - primary: BoolFieldUpdateOperationsInput - hostnames: environmentUpdatehostnamesInput - namespace: namespaceUpdateOneRequiredWithoutEnvironmentInput - deployment_environment: deployment_environmentUpdateManyWithoutEnvironmentInput - environment_edges: environment_edgesUpdateManyWithoutEnvironmentInput -} - -input environmentUpsertWithoutNodepool_environmentInput { - update: environmentUpdateWithoutNodepool_environmentInput! - create: environmentCreateWithoutNodepool_environmentInput! -} - -input environmentUpdateOneRequiredWithoutNodepool_environmentInput { - create: environmentCreateWithoutNodepool_environmentInput - connectOrCreate: environmentCreateOrConnectWithoutNodepool_environmentInput - upsert: environmentUpsertWithoutNodepool_environmentInput - connect: environmentWhereUniqueInput - update: environmentUpdateWithoutNodepool_environmentInput -} - -input nodepool_environmentUpdateWithoutNodepoolInput { - environment: environmentUpdateOneRequiredWithoutNodepool_environmentInput -} - -input nodepool_environmentUpsertWithWhereUniqueWithoutNodepoolInput { - where: nodepool_environmentWhereUniqueInput! - update: nodepool_environmentUpdateWithoutNodepoolInput! - create: nodepool_environmentCreateWithoutNodepoolInput! -} - -input nodepool_environmentUpdateWithWhereUniqueWithoutNodepoolInput { - where: nodepool_environmentWhereUniqueInput! - data: nodepool_environmentUpdateWithoutNodepoolInput! -} - -input nodepool_environmentUpdateManyWithWhereWithoutNodepoolInput { - where: nodepool_environmentScalarWhereInput! -} - -input nodepool_environmentUpdateManyWithoutNodepoolInput { - create: nodepool_environmentCreateWithoutNodepoolInput - connectOrCreate: nodepool_environmentCreateOrConnectWithoutNodepoolInput - upsert: nodepool_environmentUpsertWithWhereUniqueWithoutNodepoolInput - createMany: nodepool_environmentCreateManyNodepoolInputEnvelope - connect: nodepool_environmentWhereUniqueInput - set: nodepool_environmentWhereUniqueInput - disconnect: nodepool_environmentWhereUniqueInput - delete: nodepool_environmentWhereUniqueInput - update: nodepool_environmentUpdateWithWhereUniqueWithoutNodepoolInput - updateMany: nodepool_environmentUpdateManyWithWhereWithoutNodepoolInput - deleteMany: nodepool_environmentScalarWhereInput -} - -input nodepoolUpdateInput { - id: StringFieldUpdateOperationsInput - shared: BoolFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - wundernode: wundernodeUpdateOneRequiredWithoutNodepoolInput - nodepool_environment: nodepool_environmentUpdateManyWithoutNodepoolInput -} - -input nodepoolCreateManyInput { - id: String - wundernode_id: String! - shared: Boolean - created_at: DateTime - updated_at: DateTime -} - -input nodepoolUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - shared: BoolFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input nodepool_environmentCreateInput { - environment: environmentCreateNestedOneWithoutNodepool_environmentInput! - nodepool: nodepoolCreateNestedOneWithoutNodepool_environmentInput! -} - -input nodepool_environmentUpdateInput { - environment: environmentUpdateOneRequiredWithoutNodepool_environmentInput - nodepool: nodepoolUpdateOneRequiredWithoutNodepool_environmentInput -} - -input nodepool_environmentCreateManyInput { - nodepool_id: String! - environment_id: String! -} - -input namespaceCreateWithoutPrice_planInput { - id: String - name: String! - created_at: DateTime - updated_at: DateTime - api: apiCreateNestedManyWithoutNamespaceInput - environment: environmentCreateNestedManyWithoutNamespaceInput - namespace_members: namespace_membersCreateNestedManyWithoutNamespaceInput -} - -input namespaceCreateOrConnectWithoutPrice_planInput { - where: namespaceWhereUniqueInput! - create: namespaceCreateWithoutPrice_planInput! -} - -input namespaceCreateManyPrice_planInput { - id: String - name: String! - created_at: DateTime - updated_at: DateTime -} - -input namespaceCreateManyPrice_planInputEnvelope { - data: [namespaceCreateManyPrice_planInput]! - skipDuplicates: Boolean -} - -input namespaceCreateNestedManyWithoutPrice_planInput { - create: namespaceCreateWithoutPrice_planInput - connectOrCreate: namespaceCreateOrConnectWithoutPrice_planInput - createMany: namespaceCreateManyPrice_planInputEnvelope - connect: namespaceWhereUniqueInput -} - -input price_planCreateInput { - name: String! - quota_daily_requests: Int! - quota_environments: Int! - quota_members: Int - quota_apis: Int - allow_secondary_environments: Boolean - namespace: namespaceCreateNestedManyWithoutPrice_planInput -} - -input namespaceUpdateWithoutPrice_planInput { - id: StringFieldUpdateOperationsInput - name: StringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - api: apiUpdateManyWithoutNamespaceInput - environment: environmentUpdateManyWithoutNamespaceInput - namespace_members: namespace_membersUpdateManyWithoutNamespaceInput -} - -input namespaceUpsertWithWhereUniqueWithoutPrice_planInput { - where: namespaceWhereUniqueInput! - update: namespaceUpdateWithoutPrice_planInput! - create: namespaceCreateWithoutPrice_planInput! -} - -input namespaceUpdateWithWhereUniqueWithoutPrice_planInput { - where: namespaceWhereUniqueInput! - data: namespaceUpdateWithoutPrice_planInput! -} - -input namespaceScalarWhereInput { - AND: namespaceScalarWhereInput - OR: [namespaceScalarWhereInput] - NOT: namespaceScalarWhereInput - id: StringFilter - name: StringFilter - price_plan_id: IntFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input namespaceUpdateManyWithWhereWithoutPrice_planInput { - where: namespaceScalarWhereInput! - data: namespaceUpdateManyMutationInput! -} - -input namespaceUpdateManyWithoutPrice_planInput { - create: namespaceCreateWithoutPrice_planInput - connectOrCreate: namespaceCreateOrConnectWithoutPrice_planInput - upsert: namespaceUpsertWithWhereUniqueWithoutPrice_planInput - createMany: namespaceCreateManyPrice_planInputEnvelope - connect: namespaceWhereUniqueInput - set: namespaceWhereUniqueInput - disconnect: namespaceWhereUniqueInput - delete: namespaceWhereUniqueInput - update: namespaceUpdateWithWhereUniqueWithoutPrice_planInput - updateMany: namespaceUpdateManyWithWhereWithoutPrice_planInput - deleteMany: namespaceScalarWhereInput -} - -input price_planUpdateInput { - name: StringFieldUpdateOperationsInput - quota_daily_requests: IntFieldUpdateOperationsInput - quota_environments: IntFieldUpdateOperationsInput - quota_members: IntFieldUpdateOperationsInput - quota_apis: IntFieldUpdateOperationsInput - allow_secondary_environments: BoolFieldUpdateOperationsInput - namespace: namespaceUpdateManyWithoutPrice_planInput -} - -input price_planCreateManyInput { - id: Int - name: String! - quota_daily_requests: Int! - quota_environments: Int! - quota_members: Int - quota_apis: Int - allow_secondary_environments: Boolean -} - -input price_planUpdateManyMutationInput { - name: StringFieldUpdateOperationsInput - quota_daily_requests: IntFieldUpdateOperationsInput - quota_environments: IntFieldUpdateOperationsInput - quota_members: IntFieldUpdateOperationsInput - quota_apis: IntFieldUpdateOperationsInput - allow_secondary_environments: BoolFieldUpdateOperationsInput -} - -input usersCreateInput { - id: String - name: String - email: String! - role: user_role - created_at: DateTime - updated_at: DateTime - access_token: access_tokenCreateNestedManyWithoutUsersInput - namespace_members: namespace_membersCreateNestedManyWithoutUsersInput -} - -input usersUpdateInput { - id: StringFieldUpdateOperationsInput - name: NullableStringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - role: user_role - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - access_token: access_tokenUpdateManyWithoutUsersInput - namespace_members: namespace_membersUpdateManyWithoutUsersInput -} - -input usersCreateManyInput { - id: String - name: String - email: String! - role: user_role - created_at: DateTime - updated_at: DateTime -} - -input usersUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - name: NullableStringFieldUpdateOperationsInput - email: StringFieldUpdateOperationsInput - role: user_role - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -input nodepoolCreateWithoutWundernodeInput { - id: String - shared: Boolean - created_at: DateTime - updated_at: DateTime - nodepool_environment: nodepool_environmentCreateNestedManyWithoutNodepoolInput -} - -input nodepoolCreateOrConnectWithoutWundernodeInput { - where: nodepoolWhereUniqueInput! - create: nodepoolCreateWithoutWundernodeInput! -} - -input nodepoolCreateManyWundernodeInput { - id: String - shared: Boolean - created_at: DateTime - updated_at: DateTime -} - -input nodepoolCreateManyWundernodeInputEnvelope { - data: [nodepoolCreateManyWundernodeInput]! - skipDuplicates: Boolean -} - -input nodepoolCreateNestedManyWithoutWundernodeInput { - create: nodepoolCreateWithoutWundernodeInput - connectOrCreate: nodepoolCreateOrConnectWithoutWundernodeInput - createMany: nodepoolCreateManyWundernodeInputEnvelope - connect: nodepoolWhereUniqueInput -} - -input wundernodeCreateInput { - id: String - etag: String! - config: DateTime! - ipv4: String - ipv6: String - created_at: DateTime - updated_at: DateTime - nodepool: nodepoolCreateNestedManyWithoutWundernodeInput -} - -input nodepoolUpdateWithoutWundernodeInput { - id: StringFieldUpdateOperationsInput - shared: BoolFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - nodepool_environment: nodepool_environmentUpdateManyWithoutNodepoolInput -} - -input nodepoolUpsertWithWhereUniqueWithoutWundernodeInput { - where: nodepoolWhereUniqueInput! - update: nodepoolUpdateWithoutWundernodeInput! - create: nodepoolCreateWithoutWundernodeInput! -} - -input nodepoolUpdateWithWhereUniqueWithoutWundernodeInput { - where: nodepoolWhereUniqueInput! - data: nodepoolUpdateWithoutWundernodeInput! -} - -input nodepoolScalarWhereInput { - AND: nodepoolScalarWhereInput - OR: [nodepoolScalarWhereInput] - NOT: nodepoolScalarWhereInput - id: StringFilter - wundernode_id: StringFilter - shared: BoolFilter - created_at: DateTimeFilter - updated_at: DateTimeNullableFilter -} - -input nodepoolUpdateManyWithWhereWithoutWundernodeInput { - where: nodepoolScalarWhereInput! - data: nodepoolUpdateManyMutationInput! -} - -input nodepoolUpdateManyWithoutWundernodeInput { - create: nodepoolCreateWithoutWundernodeInput - connectOrCreate: nodepoolCreateOrConnectWithoutWundernodeInput - upsert: nodepoolUpsertWithWhereUniqueWithoutWundernodeInput - createMany: nodepoolCreateManyWundernodeInputEnvelope - connect: nodepoolWhereUniqueInput - set: nodepoolWhereUniqueInput - disconnect: nodepoolWhereUniqueInput - delete: nodepoolWhereUniqueInput - update: nodepoolUpdateWithWhereUniqueWithoutWundernodeInput - updateMany: nodepoolUpdateManyWithWhereWithoutWundernodeInput - deleteMany: nodepoolScalarWhereInput -} - -input wundernodeUpdateInput { - id: StringFieldUpdateOperationsInput - etag: StringFieldUpdateOperationsInput - config: DateTime - ipv4: NullableStringFieldUpdateOperationsInput - ipv6: NullableStringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput - nodepool: nodepoolUpdateManyWithoutWundernodeInput -} - -input wundernodeCreateManyInput { - id: String - etag: String! - config: DateTime! - ipv4: String - ipv6: String - created_at: DateTime - updated_at: DateTime -} - -input wundernodeUpdateManyMutationInput { - id: StringFieldUpdateOperationsInput - etag: StringFieldUpdateOperationsInput - config: DateTime - ipv4: NullableStringFieldUpdateOperationsInput - ipv6: NullableStringFieldUpdateOperationsInput - created_at: DateTimeFieldUpdateOperationsInput - updated_at: NullableDateTimeFieldUpdateOperationsInput -} - -type Mutation { - createOneaccess_token(data: access_tokenCreateInput!): access_token! - upsertOneaccess_token(where: access_tokenWhereUniqueInput!, create: access_tokenCreateInput!, update: access_tokenUpdateInput!): access_token! - createManyaccess_token(data: [access_tokenCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneaccess_token(where: access_tokenWhereUniqueInput!): access_token - updateOneaccess_token(data: access_tokenUpdateInput!, where: access_tokenWhereUniqueInput!): access_token - updateManyaccess_token(data: access_tokenUpdateManyMutationInput!, where: access_tokenWhereInput): AffectedRowsOutput! - deleteManyaccess_token(where: access_tokenWhereInput): AffectedRowsOutput! - createOneadmin_config(data: admin_configCreateInput!): admin_config! - upsertOneadmin_config(where: admin_configWhereUniqueInput!, create: admin_configCreateInput!, update: admin_configUpdateInput!): admin_config! - createManyadmin_config(data: [admin_configCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneadmin_config(where: admin_configWhereUniqueInput!): admin_config - updateOneadmin_config(data: admin_configUpdateInput!, where: admin_configWhereUniqueInput!): admin_config - updateManyadmin_config(data: admin_configUpdateManyMutationInput!, where: admin_configWhereInput): AffectedRowsOutput! - deleteManyadmin_config(where: admin_configWhereInput): AffectedRowsOutput! - createOneapi(data: apiCreateInput!): api! - upsertOneapi(where: apiWhereUniqueInput!, create: apiCreateInput!, update: apiUpdateInput!): api! - createManyapi(data: [apiCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneapi(where: apiWhereUniqueInput!): api - updateOneapi(data: apiUpdateInput!, where: apiWhereUniqueInput!): api - updateManyapi(data: apiUpdateManyMutationInput!, where: apiWhereInput): AffectedRowsOutput! - deleteManyapi(where: apiWhereInput): AffectedRowsOutput! - createOnedeployment(data: deploymentCreateInput!): deployment! - upsertOnedeployment(where: deploymentWhereUniqueInput!, create: deploymentCreateInput!, update: deploymentUpdateInput!): deployment! - createManydeployment(data: [deploymentCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnedeployment(where: deploymentWhereUniqueInput!): deployment - updateOnedeployment(data: deploymentUpdateInput!, where: deploymentWhereUniqueInput!): deployment - updateManydeployment(data: deploymentUpdateManyMutationInput!, where: deploymentWhereInput): AffectedRowsOutput! - deleteManydeployment(where: deploymentWhereInput): AffectedRowsOutput! - createOnedeployment_environment(data: deployment_environmentCreateInput!): deployment_environment! - upsertOnedeployment_environment(where: deployment_environmentWhereUniqueInput!, create: deployment_environmentCreateInput!, update: deployment_environmentUpdateInput!): deployment_environment! - createManydeployment_environment(data: [deployment_environmentCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnedeployment_environment(where: deployment_environmentWhereUniqueInput!): deployment_environment - updateOnedeployment_environment(data: deployment_environmentUpdateInput!, where: deployment_environmentWhereUniqueInput!): deployment_environment - updateManydeployment_environment(where: deployment_environmentWhereInput): AffectedRowsOutput! - deleteManydeployment_environment(where: deployment_environmentWhereInput): AffectedRowsOutput! - createOneedge(data: edgeCreateInput!): edge! - upsertOneedge(where: edgeWhereUniqueInput!, create: edgeCreateInput!, update: edgeUpdateInput!): edge! - createManyedge(data: [edgeCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneedge(where: edgeWhereUniqueInput!): edge - updateOneedge(data: edgeUpdateInput!, where: edgeWhereUniqueInput!): edge - updateManyedge(data: edgeUpdateManyMutationInput!, where: edgeWhereInput): AffectedRowsOutput! - deleteManyedge(where: edgeWhereInput): AffectedRowsOutput! - createOneenvironment(data: environmentCreateInput!): environment! - upsertOneenvironment(where: environmentWhereUniqueInput!, create: environmentCreateInput!, update: environmentUpdateInput!): environment! - createManyenvironment(data: [environmentCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneenvironment(where: environmentWhereUniqueInput!): environment - updateOneenvironment(data: environmentUpdateInput!, where: environmentWhereUniqueInput!): environment - updateManyenvironment(data: environmentUpdateManyMutationInput!, where: environmentWhereInput): AffectedRowsOutput! - deleteManyenvironment(where: environmentWhereInput): AffectedRowsOutput! - createOneenvironment_edges(data: environment_edgesCreateInput!): environment_edges! - upsertOneenvironment_edges(where: environment_edgesWhereUniqueInput!, create: environment_edgesCreateInput!, update: environment_edgesUpdateInput!): environment_edges! - createManyenvironment_edges(data: [environment_edgesCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneenvironment_edges(where: environment_edgesWhereUniqueInput!): environment_edges - updateOneenvironment_edges(data: environment_edgesUpdateInput!, where: environment_edgesWhereUniqueInput!): environment_edges - updateManyenvironment_edges(where: environment_edgesWhereInput): AffectedRowsOutput! - deleteManyenvironment_edges(where: environment_edgesWhereInput): AffectedRowsOutput! - createOneletsencrypt_certificate(data: letsencrypt_certificateCreateInput!): letsencrypt_certificate! - upsertOneletsencrypt_certificate(where: letsencrypt_certificateWhereUniqueInput!, create: letsencrypt_certificateCreateInput!, update: letsencrypt_certificateUpdateInput!): letsencrypt_certificate! - createManyletsencrypt_certificate(data: [letsencrypt_certificateCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneletsencrypt_certificate(where: letsencrypt_certificateWhereUniqueInput!): letsencrypt_certificate - updateOneletsencrypt_certificate(data: letsencrypt_certificateUpdateInput!, where: letsencrypt_certificateWhereUniqueInput!): letsencrypt_certificate - updateManyletsencrypt_certificate(data: letsencrypt_certificateUpdateManyMutationInput!, where: letsencrypt_certificateWhereInput): AffectedRowsOutput! - deleteManyletsencrypt_certificate(where: letsencrypt_certificateWhereInput): AffectedRowsOutput! - createOneletsencrypt_user(data: letsencrypt_userCreateInput!): letsencrypt_user! - upsertOneletsencrypt_user(where: letsencrypt_userWhereUniqueInput!, create: letsencrypt_userCreateInput!, update: letsencrypt_userUpdateInput!): letsencrypt_user! - createManyletsencrypt_user(data: [letsencrypt_userCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneletsencrypt_user(where: letsencrypt_userWhereUniqueInput!): letsencrypt_user - updateOneletsencrypt_user(data: letsencrypt_userUpdateInput!, where: letsencrypt_userWhereUniqueInput!): letsencrypt_user - updateManyletsencrypt_user(data: letsencrypt_userUpdateManyMutationInput!, where: letsencrypt_userWhereInput): AffectedRowsOutput! - deleteManyletsencrypt_user(where: letsencrypt_userWhereInput): AffectedRowsOutput! - createOnelocks(data: locksCreateInput!): locks! - upsertOnelocks(where: locksWhereUniqueInput!, create: locksCreateInput!, update: locksUpdateInput!): locks! - createManylocks(data: [locksCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnelocks(where: locksWhereUniqueInput!): locks - updateOnelocks(data: locksUpdateInput!, where: locksWhereUniqueInput!): locks - updateManylocks(data: locksUpdateManyMutationInput!, where: locksWhereInput): AffectedRowsOutput! - deleteManylocks(where: locksWhereInput): AffectedRowsOutput! - createOnenamespace(data: namespaceCreateInput!): namespace! - upsertOnenamespace(where: namespaceWhereUniqueInput!, create: namespaceCreateInput!, update: namespaceUpdateInput!): namespace! - createManynamespace(data: [namespaceCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnenamespace(where: namespaceWhereUniqueInput!): namespace - updateOnenamespace(data: namespaceUpdateInput!, where: namespaceWhereUniqueInput!): namespace - updateManynamespace(data: namespaceUpdateManyMutationInput!, where: namespaceWhereInput): AffectedRowsOutput! - deleteManynamespace(where: namespaceWhereInput): AffectedRowsOutput! - createOnenamespace_members(data: namespace_membersCreateInput!): namespace_members! - upsertOnenamespace_members(where: namespace_membersWhereUniqueInput!, create: namespace_membersCreateInput!, update: namespace_membersUpdateInput!): namespace_members! - createManynamespace_members(data: [namespace_membersCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnenamespace_members(where: namespace_membersWhereUniqueInput!): namespace_members - updateOnenamespace_members(data: namespace_membersUpdateInput!, where: namespace_membersWhereUniqueInput!): namespace_members - updateManynamespace_members(data: namespace_membersUpdateManyMutationInput!, where: namespace_membersWhereInput): AffectedRowsOutput! - deleteManynamespace_members(where: namespace_membersWhereInput): AffectedRowsOutput! - createOnenodepool(data: nodepoolCreateInput!): nodepool! - upsertOnenodepool(where: nodepoolWhereUniqueInput!, create: nodepoolCreateInput!, update: nodepoolUpdateInput!): nodepool! - createManynodepool(data: [nodepoolCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnenodepool(where: nodepoolWhereUniqueInput!): nodepool - updateOnenodepool(data: nodepoolUpdateInput!, where: nodepoolWhereUniqueInput!): nodepool - updateManynodepool(data: nodepoolUpdateManyMutationInput!, where: nodepoolWhereInput): AffectedRowsOutput! - deleteManynodepool(where: nodepoolWhereInput): AffectedRowsOutput! - createOnenodepool_environment(data: nodepool_environmentCreateInput!): nodepool_environment! - upsertOnenodepool_environment(where: nodepool_environmentWhereUniqueInput!, create: nodepool_environmentCreateInput!, update: nodepool_environmentUpdateInput!): nodepool_environment! - createManynodepool_environment(data: [nodepool_environmentCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnenodepool_environment(where: nodepool_environmentWhereUniqueInput!): nodepool_environment - updateOnenodepool_environment(data: nodepool_environmentUpdateInput!, where: nodepool_environmentWhereUniqueInput!): nodepool_environment - updateManynodepool_environment(where: nodepool_environmentWhereInput): AffectedRowsOutput! - deleteManynodepool_environment(where: nodepool_environmentWhereInput): AffectedRowsOutput! - createOneprice_plan(data: price_planCreateInput!): price_plan! - upsertOneprice_plan(where: price_planWhereUniqueInput!, create: price_planCreateInput!, update: price_planUpdateInput!): price_plan! - createManyprice_plan(data: [price_planCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneprice_plan(where: price_planWhereUniqueInput!): price_plan - updateOneprice_plan(data: price_planUpdateInput!, where: price_planWhereUniqueInput!): price_plan - updateManyprice_plan(data: price_planUpdateManyMutationInput!, where: price_planWhereInput): AffectedRowsOutput! - deleteManyprice_plan(where: price_planWhereInput): AffectedRowsOutput! - createOneusers(data: usersCreateInput!): users! - upsertOneusers(where: usersWhereUniqueInput!, create: usersCreateInput!, update: usersUpdateInput!): users! - createManyusers(data: [usersCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOneusers(where: usersWhereUniqueInput!): users - updateOneusers(data: usersUpdateInput!, where: usersWhereUniqueInput!): users - updateManyusers(data: usersUpdateManyMutationInput!, where: usersWhereInput): AffectedRowsOutput! - deleteManyusers(where: usersWhereInput): AffectedRowsOutput! - createOnewundernode(data: wundernodeCreateInput!): wundernode! - upsertOnewundernode(where: wundernodeWhereUniqueInput!, create: wundernodeCreateInput!, update: wundernodeUpdateInput!): wundernode! - createManywundernode(data: [wundernodeCreateManyInput]!, skipDuplicates: Boolean): AffectedRowsOutput! - deleteOnewundernode(where: wundernodeWhereUniqueInput!): wundernode - updateOnewundernode(data: wundernodeUpdateInput!, where: wundernodeWhereUniqueInput!): wundernode - updateManywundernode(data: wundernodeUpdateManyMutationInput!, where: wundernodeWhereInput): AffectedRowsOutput! - deleteManywundernode(where: wundernodeWhereInput): AffectedRowsOutput! -} - -scalar DateTime - -scalar Json - -scalar UUID - -scalar BigInt - -type Post { - id: Int - userId: Int - title: String - body: String -} - -type Comment { - id: Int - name: String - email: String - body: String - postId: Int -} - -type User { - id: Int - name: String - username: String - email: String - address: Address - phone: String - website: String - company: Company -} - -type Address { - street: String - suite: String - city: String - zipcode: String - geo: Geo -} - -type Geo { - lat: String - lng: String -} - -type Company { - name: String - catchPhrase: String - bs: String -} -` - -const nexusSchema = ` - -schema { - query: Query - mutation: Mutation -} - -scalar ID -scalar Float -scalar String -scalar Boolean -scalar Int - -type Mutation { - postPasswordlessStart(postPasswordlessStartInput: postPasswordlessStartInput): PostPasswordlessStartResponse - postPasswordlessLogin(postPasswordlessLoginInput: postPasswordlessLoginInput): PostPasswordlessLoginResponse - postJwtRefresh(postJwtRefreshInput: postJwtRefreshInput): PostJwtRefreshResponse - acceptPoolInvite(poolId: String!): Boolean! - addCartItem(item: AddCartItemInput!): Cart! - addTicketToPool(poolId: String!, ticketId: String!): Boolean! - archiveAggTicket(archived: Boolean!, id: ID!): AggTicket! - cancelOrder(input: CancelOrderInput!): Order! - createCancelOrderTask(input: CreateCancelOrderTaskInput!): CancelOrderTask! - createLocationGame(locationGame: CreateLocationGameInput!): LocationGame! - createPool(pool: CreatePoolInput!): Pool! - createRecurringOrder(recurringOrder: CreateRecurringOrderInput!): RecurringOrder! - createRegionGame(regionGame: CreateRegionGameInput!): RegionGame! - createRegionGameDraw(regionGameDraw: CreateRegionGameDrawInput!): RegionGameDraw! - deleteLocationGame(id: ID!): Boolean! - deletePool(id: ID!): Boolean! - deleteRecurringOrder(id: ID!): Boolean! - deleteRegionGame(id: ID!): Boolean! - emptyCart: Cart! - expressCheckout: Order! - generateFreeTicket(freeTicket: GenerateFreeTicketInput!): [Ticket]! - inviteToPool(poolId: String!, userId: String!): PoolInvite! - leavePool(poolId: String!): Boolean! - ledgerTransfer(options: TransferOptions, requests: [TransferRequest!]!): [LedgerTransferResponse!]! - markTaskComplete(input: MarkTaskCompleteInput!): Task! - markTaskFailed(input: MarkTaskFailedInput!): Task! - registerDevice(device: RegisterDeviceInput!): Device! - rejectPoolInvite(poolId: String!): Boolean! - removeCartItem(index: Int!): Cart! - removeTicketFromPool(ticketId: String!): Boolean! - sendReceiptDuplicate(orderId: String!): Boolean! - startWinningsProcess(input: StartWinningsProcessInput!): StepFunctionsExecution! - unregisterDevice(device: UnregisterDeviceInput!): Boolean! - updateBigWinningTask(bigWinningTask: UpdateBigWinningTaskInput!): BigWinningTask! - updateCancelOrderTask(input: UpdateCancelOrderTaskInput!): CancelOrderTask! - updateLocationGame(locationGame: UpdateLocationGameInput!): LocationGame! - updatePool(pool: UpdatePoolInput!): Pool! - updatePricingRule(pricingRule: UpdatePricingRuleInput!): PricingRule! - updateProfile(profile: UpdateProfileInput): User! - updateRecurringOrder(recurringOrder: UpdateRecurringOrderInput!): RecurringOrder! - updateRegionGame(regionGame: UpdateRegionGameInput!): RegionGame! - updateRegionGameDraw(regionGameDraw: UpdateRegionGameDrawInput!): RegionGameDraw! - validateBigWinningNotificationTask(id: ID!): BigWinningNotificationTask! -} - -union PostPasswordlessStartResponse = UnspecifiedHttpResponse | PostPasswordlessStartOK | PostPasswordlessStartBadRequest | PostPasswordlessStartNoAuthProvided | PostPasswordlessStartUserNotFound | PostPasswordlessStartInternalError - -type UnspecifiedHttpResponse { - statusCode: Int! -} - -type PostPasswordlessStartOK { - code: String -} - -type PostPasswordlessStartBadRequest { - message: String -} - -type PostPasswordlessStartNoAuthProvided { - message: String -} - -type PostPasswordlessStartUserNotFound { - message: String -} - -type PostPasswordlessStartInternalError { - message: String -} - -input postPasswordlessStartInput { - applicationId: String! - loginId: String! -} - -union PostPasswordlessLoginResponse = UnspecifiedHttpResponse | PostPasswordlessLoginOK | PostPasswordlessLoginNotRegisteredForApp | PostPasswordlessLoginPasswordChangeRequested | PostPasswordlessLoginEmailNotVerified | PostPasswordlessLoginRegistrationNotVerified | PostPasswordlessLoginTwoFactorEnabled | PostPasswordlessLoginBadRequest | PostPasswordlessLoginInternalError - -type PostPasswordlessLoginOK { - refreshToken: String - token: String - user: User -} - -type NexusUser { - username: String - verified: Boolean - firstName: String - lastName: String - email: String - mobilePhone: String - timezone: String -} - -type PostPasswordlessLoginNotRegisteredForApp { - message: String -} - -type PostPasswordlessLoginPasswordChangeRequested { - changePasswordReason: String -} - -type PostPasswordlessLoginEmailNotVerified { - message: String -} - -type PostPasswordlessLoginRegistrationNotVerified { - message: String -} - -type PostPasswordlessLoginTwoFactorEnabled { - twoFactorId: String -} - -type PostPasswordlessLoginBadRequest { - message: String -} - -type PostPasswordlessLoginInternalError { - message: String -} - -input postPasswordlessLoginInput { - code: String! - ipAddress: String - metaData: MetaDataInput -} - -input MetaDataInput { - device: DeviceInput -} - -input DeviceInput { - name: String -} - -union PostJwtRefreshResponse = UnspecifiedHttpResponse | PostJwtRefreshOK | PostJwtRefreshBadRequest | PostJwtRefreshNoAuthProvided | PostJwtRefreshTokenNotFound | PostJwtRefreshInternalError - -type PostJwtRefreshOK { - refreshToken: String - token: String -} - -type PostJwtRefreshBadRequest { - message: String -} - -type PostJwtRefreshNoAuthProvided { - message: String -} - -type PostJwtRefreshTokenNotFound { - message: String -} - -type PostJwtRefreshInternalError { - message: String -} - -input postJwtRefreshInput { - refreshToken: String - token: String -} - -scalar AWSDate - -scalar AWSDateTime - -scalar AWSJSON - -scalar AWSTime - -scalar AWSEmail - -type AggTicket { - archived: Boolean! - draw: RegionGameDraw! - drawDate: AWSDate! - game: RegionGame! - id: ID! - regionGameId: String! - tickets: [Ticket!]! - userId: String! -} - -type AggTicketsResult { - items: [AggTicket!]! - nextToken: String -} - -type BigWinningNotificationTask { - drawDate: AWSDate! - id: ID! - regionGameId: String! - status: BigWinningTaskStatus! -} - -type BigWinningNotificationTasksResult { - items: [BigWinningNotificationTask!] - nextToken: String -} - -type BigWinningTask { - drawDate: AWSDate! - id: ID! - regionGameId: String! - status: BigWinningTaskStatus! -} - -type BigWinningTasksResult { - items: [BigWinningTask!] - nextToken: String -} - -type CancelOrderTask { - createdAt: AWSDateTime! - id: ID! - orderId: String! - status: CancelOrderTaskStatus! - userId: String! -} - -type CancelOrderTasksResult { - items: [CancelOrderTask!] - nextToken: String -} - -type Cart { - id: ID! - items: [CartItem!]! - serviceFee: Price! - total: Price! - userId: String! -} - -type CartItem { - drawDate: AWSDate! - fractional: Boolean! - play: Play! - price: Price! - quantity: Int! - regionGameId: String! -} - -type Currency { - code: String! -} - -type Device { - deviceId: ID! - provider: PushNotificationProvider! - token: String! -} - -type DrawResults { - prizes: AWSJSON - result: AWSJSON -} - -type FreeTicket { - drawDate: AWSDate! - generatedTicketId: String - id: ID! - regionGameId: String! - status: String! -} - -type FreeTicketsResult { - items: [FreeTicket!]! - nextToken: String -} - -type GameSchemas { - play: AWSJSON - prizes: AWSJSON - result: AWSJSON -} - -type Ledger { - balance: Price - id: ID! - transactions: [LedgerTransaction!]! - type: LedgerType -} - -type LedgerTransaction { - amount: Price! - createdAt: AWSDateTime! - description: String - id: ID! - ledgerId: String! - reference: String! - relatedTransactionId: String! -} - -type LedgerTransactionsResult { - items: [LedgerTransaction!]! - nextToken: String -} - -type LedgerTransferResponse { - amount: Price! - description: String - destinationLedgerId: String! - destinationTransactionId: String! - reference: String! - sourceLedgerId: String! - sourceTransactionId: String! -} - -type LedgersResult { - items: [Ledger!]! - nextToken: String -} - -type LocationGame { - enabled: Boolean! - fractions: Int - game: RegionGame! - id: ID! -} - -type LocationGamesResult { - items: [LocationGame!]! - nextToken: String -} - -type Order { - createdAt: AWSDateTime - fulfilledAt: AWSDateTime - id: ID! - isCanceled: Boolean! - items: [OrderItem!]! - locationId: String - refundAmount: Price - refundDestination: RefundDestinationEnum - serviceFee: Price! - status: OrderStatus! - submittedAt: AWSDateTime - total: Price! -} - -type OrderItem { - cancelAction: ActionEnum - fractional: Boolean! - id: ID! - play: Play! - price: Price! - quantity: Int! - regionGameId: String! - ticketId: String -} - -type OrdersResult { - items: [Order!]! - nextToken: String -} - -type Play { - options: AWSJSON - pick: [String!]! -} - -type Pool { - id: ID! - name: String! - userCount: Int! -} - -type PoolInvite { - status: PoolInviteStatus! - user: User! - userId: String! -} - -type PoolInvitesResult { - items: [PoolInvite!]! - nextToken: String -} - -type PoolUser { - joinedAt: AWSDateTime! - user: User! -} - -type PoolUsersResult { - items: [PoolUser!]! - nextToken: String -} - -type PoolsResult { - items: [Pool!]! - nextToken: String -} - -type PreNotifications { - email: Boolean - push: Boolean -} - -type Price { - amount: Float! - currency: Currency! -} - -type PricingRule { - actor: String - id: String! - latest: Int - rules: AWSJSON! - type: PricingRuleType! - version: Int! -} - -type PricingRulesResult { - items: [PricingRule!]! - nextToken: String -} - -type Query { - aggTicket(id: ID!): AggTicket! - aggTickets(filters: AggTicketsFilters, pagination: Pagination): AggTicketsResult! - bigWinningNotificationTask(id: ID!): BigWinningNotificationTask! - bigWinningNotificationTasks(filters: BigWinningNotificationTasksFilters!, pagination: Pagination): BigWinningNotificationTasksResult! - bigWinningTask(id: ID): BigWinningTask! - bigWinningTasks(filters: BigWinningsTaskFilters!, pagination: Pagination): BigWinningTasksResult! - cancelOrderTask(id: ID!): CancelOrderTask! - cancelOrderTasks(filters: CancelOrderTasksFilters!, pagination: Pagination): CancelOrderTasksResult! - cart(userId: ID): Cart! - freeTicket(id: ID!): FreeTicket! - freeTickets(filters: FreeTicketsFilters!, pagination: Pagination): FreeTicketsResult! - ledger(id: ID!): Ledger! - ledgerTransaction(ledgerId: ID!, transactionId: String!): LedgerTransaction - ledgerTransactions(filters: LedgerTransactionsFilters, ledgerId: ID!, pagination: Pagination): LedgerTransactionsResult! - ledgers: LedgersResult! - locationGame(id: ID!): LocationGame! - locationGames(filters: LocationGamesFilters!, pagination: Pagination): LocationGamesResult! - order(id: ID!): Order! - orders(filters: OrderFilters, pagination: Pagination): OrdersResult! - pool(id: ID!): Pool - poolInvites(id: ID!, pagination: Pagination): PoolInvitesResult! - poolUsers(id: ID!, pagination: Pagination): PoolUsersResult! - pools(pagination: Pagination): PoolsResult! - pricingRule(id: ID!): PricingRule - pricingRules(pagination: Pagination, type: ID!): PricingRulesResult! - profile: User! - quoteRegionGame(fractional: Boolean!, play: AWSJSON!, regionGameId: ID!): Price! - recurringOrder(id: ID!): RecurringOrder! - recurringOrders(pagination: Pagination): RecurringOrdersResult! - regionGame(id: ID!): RegionGame! - regionGameDraw(id: ID!): RegionGameDraw! - regionGameDraws(filters: RegionGameDrawsFilters!, pagination: Pagination): RegionGameDrawsResult! - regionGames(filters: RegionGamesFilters!, pagination: Pagination): RegionGamesResult! - task(id: ID): Task! - tasks(filters: TaskFilters): TasksResult! - ticket(id: ID!): Ticket! - tickets(filters: TicketsFilters, pagination: Pagination): TicketsResult! -} - -type RecurringOrder { - enabled: Boolean! - expectedPrice: Price! - fractional: Boolean! - id: ID! - locationId: String! - play: Play! - regionGameId: String! -} - -type RecurringOrdersResult { - items: [RecurringOrder!]! - nextToken: String -} - -type RegionGame { - autoPayoutLimit: Price - closingTime: Int! - currency: String! - drawTime: AWSTime! - draws: [RegionGameDraw!] - gameId: String! - id: ID! - lastDrawDate: AWSDate - lastDrawResult: String - name: String! - nextDrawDate: AWSDate - nextDrawPrize: Float - regionId: String! - regionName: String! - resultUpdatedAt: AWSDateTime - schemas: GameSchemas - timeZone: String! -} - -type RegionGameDraw { - closingDateTime: AWSDateTime - date: AWSDate! - id: ID! - parsedResult: DrawResults - prize: Float - regionGameId: String! - result: String - resultUpdatedAt: AWSDateTime - verifiedResult: DrawResults -} - -type RegionGameDrawsResult { - items: [RegionGameDraw!] - nextToken: String -} - -type RegionGamesResult { - items: [RegionGame!] - nextToken: String -} - -type StepFunctionsExecution { - executionArn: String! - startDate: Float! -} - -type Task { - execution: String - id: String! - input: AWSJSON - output: AWSJSON - process: TaskProcess! - state: TaskState! - status: TaskStatus! - statusReason: String - statusUpdatedAt: AWSDateTime - token: String -} - -type TasksResult { - items: [Task!] - nextToken: String -} - -type Ticket { - drawDate: AWSDate! - fraction: Int - id: ID! - locationId: String - options: AWSJSON - pick: AWSJSON! - poolId: String - regionGameId: String! - totalFractions: Int - totalWinnings: Price - type: String! - winnings: Price -} - -type TicketsResult { - items: [Ticket!]! - nextToken: String -} - -type User { - email: AWSEmail! - id: ID! - name: String! - preferences: UserPreferences! - updatedAt: AWSDateTime! -} - -type UserPreferences { - notifications: PreNotifications! -} - -enum ActionEnum { - Keep - Void -} - -enum BigWinningNotificationTaskStatus { - Complete - Pending -} - -enum BigWinningTaskStatus { - Complete - Pending -} - -enum CancelOrderTaskStatus { - Complete - Pending -} - -enum FreeTicketStatus { - Complete - Pending -} - -enum LedgerType { - Balance - Cash - Credits - Winnings -} - -enum OrderStatus { - Canceled - Draft - Fulfilled - Paid - PaymentFailed - PendingPayment -} - -enum PoolInviteStatus { - Accepted - Pending - Rejected -} - -enum PricingRuleType { - CART - GAME -} - -enum PushNotificationProvider { - FCM -} - -enum RefundDestinationEnum { - Balance - Credits - Exact - PaymentMethod -} - -enum TaskProcess { - Winnings -} - -enum TaskState { - AddPaymentMethod - BigWinner - CalculateWinnings - FulfillOrder - IssueWinnings - PreCalculateWinnings - PreIssueWinnings - PreVerifyResults - ProcessPayment - SendReceipt - SendResults - VerifyResults -} - -enum TaskStatus { - Complete - Failed - Pending -} - -input AddCartItemInput { - drawDate: AWSDate! - fractional: Boolean! - play: PlayInput - quantity: Int! - regionGameId: String! -} - -input AggTicketsFilters { - archived: Boolean - fromDate: AWSDate - regionGameId: String - toDate: AWSDate -} - -input BigWinningNotificationTasksFilters { - regionGameDrawId: String! - status: BigWinningNotificationTaskStatus -} - -input BigWinningsTaskFilters { - regionGameDrawId: String! - status: BigWinningTaskStatus -} - -input CancelItemsInput { - action: ActionEnum! - id: ID! -} - -input CancelOrderInput { - action: ActionEnum! - items: [CancelItemsInput!] - orderId: ID! - refundAmount: PriceInput - refundDestination: RefundDestinationEnum -} - -input CancelOrderTasksFilters { - fromDate: AWSDateTime - status: CancelOrderTaskStatus! - toDate: AWSDateTime - userId: String -} - -input CreateCancelOrderTaskInput { - orderId: String! -} - -input CreateLocationGameInput { - enabled: Boolean! - fractions: Int - gameId: String! - locationId: String! - regionId: String! -} - -input CreatePoolInput { - name: String! -} - -input CreateRecurringOrderInput { - fractional: Boolean! - play: PlayInput! - regionGameId: String! -} - -input CreateRegionGameDrawInput { - closingDateTime: AWSDateTime - date: AWSDate! - regionGameId: String! - result: String - verifiedResult: RegionGameDrawResultInput -} - -input CreateRegionGameInput { - autoPayoutLimit: PriceInput - closingTime: Int! - currency: String! - drawTime: AWSTime! - gameId: ID! - lastDrawDate: AWSDate - lastDrawResult: String - name: String! - nextDrawDate: AWSDate - nextDrawPrize: Float - prizes: AWSJSON - regionId: ID! - regionName: String! - resultUpdatedAt: AWSDateTime - timeZone: String! -} - -input CurrencyInput { - code: String! -} - -input FreeTicketsFilters { - regionGameDrawId: String! - status: FreeTicketStatus -} - -input FulfilledItem { - id: ID! - ticketId: String -} - -input GenerateFreeTicketInput { - drawDate: AWSDate! - id: String! - play: PlayInput! -} - -input LedgerTransactionsFilters { - fromDate: AWSDateTime - toDate: AWSDateTime -} - -input LocationGamesFilters { - locationId: String! -} - -input MarkTaskCompleteInput { - id: ID! -} - -input MarkTaskFailedInput { - id: ID! - reason: String -} - -input OrderFilters { - fromDate: AWSDateTime - status: OrderStatus - toDate: AWSDateTime - userId: String -} - -input Pagination { - limit: Int - nextToken: String -} - -input PlayInput { - options: AWSJSON - pick: [String!]! -} - -input PreNotificationsInput { - email: Boolean - push: Boolean -} - -input PriceInput { - amount: Float! - currency: CurrencyInput! -} - -input RegionGameDrawResultInput { - prizes: AWSJSON! - result: AWSJSON! -} - -input RegionGameDrawsFilters { - regionGameId: String! -} - -input RegionGamesFilters { - regionId: String! -} - -input RegisterDeviceInput { - deviceId: ID! - provider: PushNotificationProvider! - token: String! -} - -input StartWinningsProcessInput { - date: String! - regionGameId: String! -} - -input TaskFilters { - process: TaskProcess - state: TaskState - status: TaskStatus -} - -input TicketsFilters { - fromDate: AWSDate - regionGameId: String - toDate: AWSDate -} - -input TransferOptions { - idempotencyKey: String -} - -input TransferRequest { - amount: PriceInput! - description: String - destinationLedgerId: String! - reference: String! - sourceLedgerId: String! -} - -input UnregisterDeviceInput { - deviceId: ID! - provider: PushNotificationProvider! -} - -input UpdateBigWinningTaskInput { - id: ID! - status: BigWinningTaskStatus! -} - -input UpdateCancelOrderTaskInput { - id: ID! - status: CancelOrderTaskStatus! -} - -input UpdateLocationGameInput { - enabled: Boolean! - fractions: Int - id: ID! - regionId: String! -} - -input UpdatePoolInput { - id: ID! - name: String -} - -input UpdatePricingRuleInput { - latest: Int! - rules: AWSJSON! - type: PricingRuleType! -} - -input UpdateProfileInput { - email: AWSEmail - name: String - preferences: UserPreferencesInput -} - -input UpdateRecurringOrderInput { - enabled: Boolean! - fractional: Boolean! - id: ID! - play: PlayInput! - regionGameId: String! -} - -input UpdateRegionGameDrawInput { - closingDateTime: AWSDateTime - id: ID! - result: String - verifiedResult: RegionGameDrawResultInput -} - -input UpdateRegionGameInput { - autoPayoutLimit: PriceInput - closingTime: Int - currency: String - drawTime: AWSTime - id: ID! - lastDrawDate: AWSDate - lastDrawResult: String - name: String - nextDrawDate: AWSDate - nextDrawPrize: Float - prizes: AWSJSON - regionName: String - resultUpdatedAt: AWSDateTime - timeZone: String -} - -input UserPreferencesInput { - notifications: PreNotificationsInput! -}` diff --git a/pkg/astvalidation/overlapping_fields_test.go b/pkg/astvalidation/overlapping_fields_test.go deleted file mode 100644 index a39af6ac8..000000000 --- a/pkg/astvalidation/overlapping_fields_test.go +++ /dev/null @@ -1,228 +0,0 @@ -package astvalidation - -import ( - "bytes" - "fmt" - "strconv" - "testing" - "text/template" - - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -// inspired by: https://tech.xing.com/graphql-overlapping-fields-can-be-merged-fast-ea6e92e0a01 -func TestOverlappingFieldsCanBeMerged(t *testing.T) { - - t.Run("valid", func(t *testing.T) { - definitionBytes := RenderTemplate(5, OverlappingFieldsDefinition) - operationBytes := RenderTemplate(5, OverlappingFieldsOperationValid) - - fmt.Println(string(operationBytes)) - - definition := unsafeparser.ParseGraphqlDocumentBytes(definitionBytes) - operation := unsafeparser.ParseGraphqlDocumentBytes(operationBytes) - report := operationreport.Report{} - normalizer := astnormalization.NewNormalizer(false, false) - validator := DefaultOperationValidator() - - normalizer.NormalizeOperation(&operation, &definition, &report) - if report.HasErrors() { - panic(report.Error()) - } - - if validator.Validate(&operation, &definition, &report) != Valid { - panic(report.Error()) - } - }) - t.Run("invalid", func(t *testing.T) { - definitionBytes := RenderTemplate(5, OverlappingFieldsDefinition) - operationBytes := RenderTemplate(5, OverlappingFieldsOperationInvalid) - - fmt.Println(string(operationBytes)) - - definition := unsafeparser.ParseGraphqlDocumentBytes(definitionBytes) - operation := unsafeparser.ParseGraphqlDocumentBytes(operationBytes) - report := operationreport.Report{} - normalizer := astnormalization.NewNormalizer(false, false) - validator := DefaultOperationValidator() - - normalizer.NormalizeOperation(&operation, &definition, &report) - if report.HasErrors() { - panic(report.Error()) - } - - if validator.Validate(&operation, &definition, &report) != Invalid { - panic(report.Error()) - } - }) -} - -func BenchmarkOverlappingFieldsCanBeMerged(b *testing.B) { - multipliers := []int{1, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 200} - for _, multiplier := range multipliers { - multiplier := multiplier - b.Run("valid"+strconv.Itoa(multiplier), func(b *testing.B) { - definitionBytes := RenderTemplate(multiplier, OverlappingFieldsDefinition) - operationBytes := RenderTemplate(multiplier, OverlappingFieldsOperationValid) - - definition := unsafeparser.ParseGraphqlDocumentBytes(definitionBytes) - operation := unsafeparser.ParseGraphqlDocumentBytes(operationBytes) - report := operationreport.Report{} - normalizer := astnormalization.NewNormalizer(false, false) - validator := DefaultOperationValidator() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - report.Reset() - definition := definition - normalizer.NormalizeOperation(&operation, &definition, &report) - if report.HasErrors() { - panic(report.Error()) - } - - if validator.Validate(&operation, &definition, &report) != Valid { - panic(report.Error()) - } - } - }) - b.Run("invalid"+strconv.Itoa(multiplier), func(b *testing.B) { - definitionBytes := RenderTemplate(multiplier, OverlappingFieldsDefinition) - operationBytes := RenderTemplate(multiplier, OverlappingFieldsOperationInvalid) - - definition := unsafeparser.ParseGraphqlDocumentBytes(definitionBytes) - operation := unsafeparser.ParseGraphqlDocumentBytes(operationBytes) - report := operationreport.Report{} - normalizer := astnormalization.NewNormalizer(false, false) - validator := DefaultOperationValidator() - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - report.Reset() - definition := definition - normalizer.NormalizeOperation(&operation, &definition, &report) - if report.HasErrors() { - panic(report.Error()) - } - - if validator.Validate(&operation, &definition, &report) != Invalid { - panic(report.Error()) - } - } - }) - } -} - -func RenderTemplate(multiplier int, tmpl string) []byte { - t := template.Must(template.New("tmpl").Parse(tmpl)) - data := make([]int, 0, multiplier) - for i := 0; i < multiplier; i++ { - data = append(data, i+1) - } - buff := bytes.Buffer{} - err := t.Execute(&buff, data) - if err != nil { - panic(err) - } - return buff.Bytes() -} - -const OverlappingFieldsOperationValid = ` -{ - someBox { - ... on StringBox { - scalar - }{{ range $i := . }} - ... on StringBox{{ $i }} { - scalar - }{{ end }} - } -}` - -const OverlappingFieldsOperationInvalid = ` -{ - someBox { - ... on StringBox { - scalar - }{{ range $i := . }} - ... on StringBox{{ $i }} { - scalar - }{{ end }} - ... on NonNullStringBox1 { - scalar - } - } -}` - -const OverlappingFieldsDefinition = ` -scalar String -scalar ID -scalar Int -interface SomeBox { - deepBox: SomeBox - unrelatedField: String -} -type StringBox implements SomeBox { - scalar: String - deepBox: StringBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox -} -{{ range $i := . }}{{ if ne $i 1 }} -{{ end}}type StringBox{{ $i }} implements SomeBox { - scalar: String - deepBox: StringBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox -}{{ end }} -type IntBox implements SomeBox { - scalar: Int - deepBox: IntBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox -} -interface NonNullStringBox1 { - scalar: String! -} -type NonNullStringBox1Impl implements SomeBox & NonNullStringBox1 { - scalar: String! - unrelatedField: String - deepBox: SomeBox -} -interface NonNullStringBox2 { - scalar: String! -} -type NonNullStringBox2Impl implements SomeBox & NonNullStringBox2 { - scalar: String! - unrelatedField: String - deepBox: SomeBox -} -type Connection { - edges: [Edge] -} -type Edge { - node: Node -} -type Node { - id: ID - name: String -} -type Query { - someBox: SomeBox - connection: Connection -} -schema { - query: Query -} -` diff --git a/pkg/astvalidation/reference/.gitignore b/pkg/astvalidation/reference/.gitignore deleted file mode 100644 index 737a4e811..000000000 --- a/pkg/astvalidation/reference/.gitignore +++ /dev/null @@ -1 +0,0 @@ -__tests__ \ No newline at end of file diff --git a/pkg/astvalidation/reference/__tests__/ExecutableDefinitionsRule-test.js b/pkg/astvalidation/reference/__tests__/ExecutableDefinitionsRule-test.js deleted file mode 100644 index 4409767b5..000000000 --- a/pkg/astvalidation/reference/__tests__/ExecutableDefinitionsRule-test.js +++ /dev/null @@ -1,94 +0,0 @@ -import { describe, it } from 'mocha'; - -import { ExecutableDefinitionsRule } from '../rules/ExecutableDefinitionsRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(ExecutableDefinitionsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Executable definitions', () => { - it('with only operation', () => { - expectValid(` - query Foo { - dog { - name - } - } - `); - }); - - it('with operation and fragment', () => { - expectValid(` - query Foo { - dog { - name - ...Frag - } - } - - fragment Frag on Dog { - name - } - `); - }); - - it('with type definition', () => { - expectErrors(` - query Foo { - dog { - name - } - } - - type Cow { - name: String - } - - extend type Dog { - color: String - } - `).to.deep.equal([ - { - message: 'The "Cow" definition is not executable.', - locations: [{ line: 8, column: 7 }], - }, - { - message: 'The "Dog" definition is not executable.', - locations: [{ line: 12, column: 7 }], - }, - ]); - }); - - it('with schema definition', () => { - expectErrors(` - schema { - query: Query - } - - type Query { - test: String - } - - extend schema @directive - `).to.deep.equal([ - { - message: 'The schema definition is not executable.', - locations: [{ line: 2, column: 7 }], - }, - { - message: 'The "Query" definition is not executable.', - locations: [{ line: 6, column: 7 }], - }, - { - message: 'The schema definition is not executable.', - locations: [{ line: 10, column: 7 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/FieldsOnCorrectTypeRule-test.js b/pkg/astvalidation/reference/__tests__/FieldsOnCorrectTypeRule-test.js deleted file mode 100644 index 6ec857a68..000000000 --- a/pkg/astvalidation/reference/__tests__/FieldsOnCorrectTypeRule-test.js +++ /dev/null @@ -1,396 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { parse } from '../../language/parser'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { validate } from '../validate'; -import { FieldsOnCorrectTypeRule } from '../rules/FieldsOnCorrectTypeRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(FieldsOnCorrectTypeRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Fields on correct type', () => { - it('Object field selection', () => { - expectValid(` - fragment objectFieldSelection on Dog { - __typename - name - } - `); - }); - - it('Aliased object field selection', () => { - expectValid(` - fragment aliasedObjectFieldSelection on Dog { - tn : __typename - otherName : name - } - `); - }); - - it('Interface field selection', () => { - expectValid(` - fragment interfaceFieldSelection on Pet { - __typename - name - } - `); - }); - - it('Aliased interface field selection', () => { - expectValid(` - fragment interfaceFieldSelection on Pet { - otherName : name - } - `); - }); - - it('Lying alias selection', () => { - expectValid(` - fragment lyingAliasSelection on Dog { - name : nickname - } - `); - }); - - it('Ignores fields on unknown type', () => { - expectValid(` - fragment unknownSelection on UnknownType { - unknownField - } - `); - }); - - it('reports errors when type is known again', () => { - expectErrors(` - fragment typeKnownAgain on Pet { - unknown_pet_field { - ... on Cat { - unknown_cat_field - } - } - } - `).to.deep.equal([ - { - message: 'Cannot query field "unknown_pet_field" on type "Pet".', - locations: [{ line: 3, column: 9 }], - }, - { - message: 'Cannot query field "unknown_cat_field" on type "Cat".', - locations: [{ line: 5, column: 13 }], - }, - ]); - }); - - it('Field not defined on fragment', () => { - expectErrors(` - fragment fieldNotDefined on Dog { - meowVolume - } - `).to.deep.equal([ - { - message: - 'Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Ignores deeply unknown field', () => { - expectErrors(` - fragment deepFieldNotDefined on Dog { - unknown_field { - deeper_unknown_field - } - } - `).to.deep.equal([ - { - message: 'Cannot query field "unknown_field" on type "Dog".', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Sub-field not defined', () => { - expectErrors(` - fragment subFieldNotDefined on Human { - pets { - unknown_field - } - } - `).to.deep.equal([ - { - message: 'Cannot query field "unknown_field" on type "Pet".', - locations: [{ line: 4, column: 11 }], - }, - ]); - }); - - it('Field not defined on inline fragment', () => { - expectErrors(` - fragment fieldNotDefined on Pet { - ... on Dog { - meowVolume - } - } - `).to.deep.equal([ - { - message: - 'Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?', - locations: [{ line: 4, column: 11 }], - }, - ]); - }); - - it('Aliased field target not defined', () => { - expectErrors(` - fragment aliasedFieldTargetNotDefined on Dog { - volume : mooVolume - } - `).to.deep.equal([ - { - message: - 'Cannot query field "mooVolume" on type "Dog". Did you mean "barkVolume"?', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Aliased lying field target not defined', () => { - expectErrors(` - fragment aliasedLyingFieldTargetNotDefined on Dog { - barkVolume : kawVolume - } - `).to.deep.equal([ - { - message: - 'Cannot query field "kawVolume" on type "Dog". Did you mean "barkVolume"?', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Not defined on interface', () => { - expectErrors(` - fragment notDefinedOnInterface on Pet { - tailLength - } - `).to.deep.equal([ - { - message: 'Cannot query field "tailLength" on type "Pet".', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Defined on implementors but not on interface', () => { - expectErrors(` - fragment definedOnImplementorsButNotInterface on Pet { - nickname - } - `).to.deep.equal([ - { - message: - 'Cannot query field "nickname" on type "Pet". Did you mean to use an inline fragment on "Cat" or "Dog"?', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Meta field selection on union', () => { - expectValid(` - fragment directFieldSelectionOnUnion on CatOrDog { - __typename - } - `); - }); - - it('Direct field selection on union', () => { - expectErrors(` - fragment directFieldSelectionOnUnion on CatOrDog { - directField - } - `).to.deep.equal([ - { - message: 'Cannot query field "directField" on type "CatOrDog".', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('Defined on implementors queried on union', () => { - expectErrors(` - fragment definedOnImplementorsQueriedOnUnion on CatOrDog { - name - } - `).to.deep.equal([ - { - message: - 'Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Being", "Pet", "Canine", "Cat", or "Dog"?', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('valid field in inline fragment', () => { - expectValid(` - fragment objectFieldSelection on Pet { - ... on Dog { - name - } - ... { - name - } - } - `); - }); - - describe('Fields on correct type error message', () => { - function expectErrorMessage(schema: GraphQLSchema, queryStr: string) { - const errors = validate(schema, parse(queryStr), [ - FieldsOnCorrectTypeRule, - ]); - expect(errors.length).to.equal(1); - return expect(errors[0].message); - } - - it('Works with no suggestions', () => { - const schema = buildSchema(` - type T { - fieldWithVeryLongNameThatWillNeverBeSuggested: String - } - type Query { t: T } - `); - - expectErrorMessage(schema, '{ t { f } }').to.equal( - 'Cannot query field "f" on type "T".', - ); - }); - - it('Works with no small numbers of type suggestions', () => { - const schema = buildSchema(` - union T = A | B - type Query { t: T } - - type A { f: String } - type B { f: String } - `); - - expectErrorMessage(schema, '{ t { f } }').to.equal( - 'Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A" or "B"?', - ); - }); - - it('Works with no small numbers of field suggestions', () => { - const schema = buildSchema(` - type T { - y: String - z: String - } - type Query { t: T } - `); - - expectErrorMessage(schema, '{ t { f } }').to.equal( - 'Cannot query field "f" on type "T". Did you mean "y" or "z"?', - ); - }); - - it('Only shows one set of suggestions at a time, preferring types', () => { - const schema = buildSchema(` - interface T { - y: String - z: String - } - type Query { t: T } - - type A implements T { - f: String - y: String - z: String - } - type B implements T { - f: String - y: String - z: String - } - `); - - expectErrorMessage(schema, '{ t { f } }').to.equal( - 'Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A" or "B"?', - ); - }); - - it('Sort type suggestions based on inheritance order', () => { - const schema = buildSchema(` - interface T { bar: String } - type Query { t: T } - - interface Z implements T { - foo: String - bar: String - } - - interface Y implements Z & T { - foo: String - bar: String - } - - type X implements Y & Z & T { - foo: String - bar: String - } - `); - - expectErrorMessage(schema, '{ t { foo } }').to.equal( - 'Cannot query field "foo" on type "T". Did you mean to use an inline fragment on "Z", "Y", or "X"?', - ); - }); - - it('Limits lots of type suggestions', () => { - const schema = buildSchema(` - union T = A | B | C | D | E | F - type Query { t: T } - - type A { f: String } - type B { f: String } - type C { f: String } - type D { f: String } - type E { f: String } - type F { f: String } - `); - - expectErrorMessage(schema, '{ t { f } }').to.equal( - 'Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A", "B", "C", "D", or "E"?', - ); - }); - - it('Limits lots of field suggestions', () => { - const schema = buildSchema(` - type T { - u: String - v: String - w: String - x: String - y: String - z: String - } - type Query { t: T } - `); - - expectErrorMessage(schema, '{ t { f } }').to.equal( - 'Cannot query field "f" on type "T". Did you mean "u", "v", "w", "x", or "y"?', - ); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/FragmentsOnCompositeTypesRule-test.js b/pkg/astvalidation/reference/__tests__/FragmentsOnCompositeTypesRule-test.js deleted file mode 100644 index a9b7ec17d..000000000 --- a/pkg/astvalidation/reference/__tests__/FragmentsOnCompositeTypesRule-test.js +++ /dev/null @@ -1,126 +0,0 @@ -import { describe, it } from 'mocha'; - -import { FragmentsOnCompositeTypesRule } from '../rules/FragmentsOnCompositeTypesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(FragmentsOnCompositeTypesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Fragments on composite types', () => { - it('object is valid fragment type', () => { - expectValid(` - fragment validFragment on Dog { - barks - } - `); - }); - - it('interface is valid fragment type', () => { - expectValid(` - fragment validFragment on Pet { - name - } - `); - }); - - it('object is valid inline fragment type', () => { - expectValid(` - fragment validFragment on Pet { - ... on Dog { - barks - } - } - `); - }); - - it('interface is valid inline fragment type', () => { - expectValid(` - fragment validFragment on Mammal { - ... on Canine { - name - } - } - `); - }); - - it('inline fragment without type is valid', () => { - expectValid(` - fragment validFragment on Pet { - ... { - name - } - } - `); - }); - - it('union is valid fragment type', () => { - expectValid(` - fragment validFragment on CatOrDog { - __typename - } - `); - }); - - it('scalar is invalid fragment type', () => { - expectErrors(` - fragment scalarFragment on Boolean { - bad - } - `).to.deep.equal([ - { - message: - 'Fragment "scalarFragment" cannot condition on non composite type "Boolean".', - locations: [{ line: 2, column: 34 }], - }, - ]); - }); - - it('enum is invalid fragment type', () => { - expectErrors(` - fragment scalarFragment on FurColor { - bad - } - `).to.deep.equal([ - { - message: - 'Fragment "scalarFragment" cannot condition on non composite type "FurColor".', - locations: [{ line: 2, column: 34 }], - }, - ]); - }); - - it('input object is invalid fragment type', () => { - expectErrors(` - fragment inputFragment on ComplexInput { - stringField - } - `).to.deep.equal([ - { - message: - 'Fragment "inputFragment" cannot condition on non composite type "ComplexInput".', - locations: [{ line: 2, column: 33 }], - }, - ]); - }); - - it('scalar is invalid inline fragment type', () => { - expectErrors(` - fragment invalidFragment on Pet { - ... on String { - barks - } - } - `).to.deep.equal([ - { - message: 'Fragment cannot condition on non composite type "String".', - locations: [{ line: 3, column: 16 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/KnownArgumentNamesRule-test.js b/pkg/astvalidation/reference/__tests__/KnownArgumentNamesRule-test.js deleted file mode 100644 index 8bf7567c5..000000000 --- a/pkg/astvalidation/reference/__tests__/KnownArgumentNamesRule-test.js +++ /dev/null @@ -1,329 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { - KnownArgumentNamesRule, - KnownArgumentNamesOnDirectivesRule, -} from '../rules/KnownArgumentNamesRule'; - -import { expectValidationErrors, expectSDLValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(KnownArgumentNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors( - schema, - KnownArgumentNamesOnDirectivesRule, - sdlStr, - ); -} - -function expectValidSDL(sdlStr: string) { - expectSDLErrors(sdlStr).to.deep.equal([]); -} - -describe('Validate: Known argument names', () => { - it('single arg is known', () => { - expectValid(` - fragment argOnRequiredArg on Dog { - doesKnowCommand(dogCommand: SIT) - } - `); - }); - - it('multiple args are known', () => { - expectValid(` - fragment multipleArgs on ComplicatedArgs { - multipleReqs(req1: 1, req2: 2) - } - `); - }); - - it('ignores args of unknown fields', () => { - expectValid(` - fragment argOnUnknownField on Dog { - unknownField(unknownArg: SIT) - } - `); - }); - - it('multiple args in reverse order are known', () => { - expectValid(` - fragment multipleArgsReverseOrder on ComplicatedArgs { - multipleReqs(req2: 2, req1: 1) - } - `); - }); - - it('no args on optional arg', () => { - expectValid(` - fragment noArgOnOptionalArg on Dog { - isHouseTrained - } - `); - }); - - it('args are known deeply', () => { - expectValid(` - { - dog { - doesKnowCommand(dogCommand: SIT) - } - human { - pet { - ... on Dog { - doesKnowCommand(dogCommand: SIT) - } - } - } - } - `); - }); - - it('directive args are known', () => { - expectValid(` - { - dog @skip(if: true) - } - `); - }); - - it('field args are invalid', () => { - expectErrors(` - { - dog @skip(unless: true) - } - `).to.deep.equal([ - { - message: 'Unknown argument "unless" on directive "@skip".', - locations: [{ line: 3, column: 19 }], - }, - ]); - }); - - it('directive without args is valid', () => { - expectValid(` - { - dog @onField - } - `); - }); - - it('arg passed to directive without arg is reported', () => { - expectErrors(` - { - dog @onField(if: true) - } - `).to.deep.equal([ - { - message: 'Unknown argument "if" on directive "@onField".', - locations: [{ line: 3, column: 22 }], - }, - ]); - }); - - it('misspelled directive args are reported', () => { - expectErrors(` - { - dog @skip(iff: true) - } - `).to.deep.equal([ - { - message: - 'Unknown argument "iff" on directive "@skip". Did you mean "if"?', - locations: [{ line: 3, column: 19 }], - }, - ]); - }); - - it('invalid arg name', () => { - expectErrors(` - fragment invalidArgName on Dog { - doesKnowCommand(unknown: true) - } - `).to.deep.equal([ - { - message: 'Unknown argument "unknown" on field "Dog.doesKnowCommand".', - locations: [{ line: 3, column: 25 }], - }, - ]); - }); - - it('misspelled arg name is reported', () => { - expectErrors(` - fragment invalidArgName on Dog { - doesKnowCommand(DogCommand: true) - } - `).to.deep.equal([ - { - message: - 'Unknown argument "DogCommand" on field "Dog.doesKnowCommand". Did you mean "dogCommand"?', - locations: [{ line: 3, column: 25 }], - }, - ]); - }); - - it('unknown args amongst known args', () => { - expectErrors(` - fragment oneGoodArgOneInvalidArg on Dog { - doesKnowCommand(whoKnows: 1, dogCommand: SIT, unknown: true) - } - `).to.deep.equal([ - { - message: 'Unknown argument "whoKnows" on field "Dog.doesKnowCommand".', - locations: [{ line: 3, column: 25 }], - }, - { - message: 'Unknown argument "unknown" on field "Dog.doesKnowCommand".', - locations: [{ line: 3, column: 55 }], - }, - ]); - }); - - it('unknown args deeply', () => { - expectErrors(` - { - dog { - doesKnowCommand(unknown: true) - } - human { - pet { - ... on Dog { - doesKnowCommand(unknown: true) - } - } - } - } - `).to.deep.equal([ - { - message: 'Unknown argument "unknown" on field "Dog.doesKnowCommand".', - locations: [{ line: 4, column: 27 }], - }, - { - message: 'Unknown argument "unknown" on field "Dog.doesKnowCommand".', - locations: [{ line: 9, column: 31 }], - }, - ]); - }); - - describe('within SDL', () => { - it('known arg on directive defined inside SDL', () => { - expectValidSDL(` - type Query { - foo: String @test(arg: "") - } - - directive @test(arg: String) on FIELD_DEFINITION - `); - }); - - it('unknown arg on directive defined inside SDL', () => { - expectSDLErrors(` - type Query { - foo: String @test(unknown: "") - } - - directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([ - { - message: 'Unknown argument "unknown" on directive "@test".', - locations: [{ line: 3, column: 29 }], - }, - ]); - }); - - it('misspelled arg name is reported on directive defined inside SDL', () => { - expectSDLErrors(` - type Query { - foo: String @test(agr: "") - } - - directive @test(arg: String) on FIELD_DEFINITION - `).to.deep.equal([ - { - message: - 'Unknown argument "agr" on directive "@test". Did you mean "arg"?', - locations: [{ line: 3, column: 29 }], - }, - ]); - }); - - it('unknown arg on standard directive', () => { - expectSDLErrors(` - type Query { - foo: String @deprecated(unknown: "") - } - `).to.deep.equal([ - { - message: 'Unknown argument "unknown" on directive "@deprecated".', - locations: [{ line: 3, column: 35 }], - }, - ]); - }); - - it('unknown arg on overridden standard directive', () => { - expectSDLErrors(` - type Query { - foo: String @deprecated(reason: "") - } - directive @deprecated(arg: String) on FIELD - `).to.deep.equal([ - { - message: 'Unknown argument "reason" on directive "@deprecated".', - locations: [{ line: 3, column: 35 }], - }, - ]); - }); - - it('unknown arg on directive defined in schema extension', () => { - const schema = buildSchema(` - type Query { - foo: String - } - `); - expectSDLErrors( - ` - directive @test(arg: String) on OBJECT - - extend type Query @test(unknown: "") - `, - schema, - ).to.deep.equal([ - { - message: 'Unknown argument "unknown" on directive "@test".', - locations: [{ line: 4, column: 36 }], - }, - ]); - }); - - it('unknown arg on directive used in schema extension', () => { - const schema = buildSchema(` - directive @test(arg: String) on OBJECT - - type Query { - foo: String - } - `); - expectSDLErrors( - ` - extend type Query @test(unknown: "") - `, - schema, - ).to.deep.equal([ - { - message: 'Unknown argument "unknown" on directive "@test".', - locations: [{ line: 2, column: 35 }], - }, - ]); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/KnownDirectivesRule-test.js b/pkg/astvalidation/reference/__tests__/KnownDirectivesRule-test.js deleted file mode 100644 index 13491bc6c..000000000 --- a/pkg/astvalidation/reference/__tests__/KnownDirectivesRule-test.js +++ /dev/null @@ -1,409 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { KnownDirectivesRule } from '../rules/KnownDirectivesRule'; - -import { expectValidationErrors, expectSDLValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(KnownDirectivesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, KnownDirectivesRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -const schemaWithSDLDirectives = buildSchema(` - directive @onSchema on SCHEMA - directive @onScalar on SCALAR - directive @onObject on OBJECT - directive @onFieldDefinition on FIELD_DEFINITION - directive @onArgumentDefinition on ARGUMENT_DEFINITION - directive @onInterface on INTERFACE - directive @onUnion on UNION - directive @onEnum on ENUM - directive @onEnumValue on ENUM_VALUE - directive @onInputObject on INPUT_OBJECT - directive @onInputFieldDefinition on INPUT_FIELD_DEFINITION -`); - -describe('Validate: Known directives', () => { - it('with no directives', () => { - expectValid(` - query Foo { - name - ...Frag - } - - fragment Frag on Dog { - name - } - `); - }); - - it('with known directives', () => { - expectValid(` - { - dog @include(if: true) { - name - } - human @skip(if: false) { - name - } - } - `); - }); - - it('with unknown directive', () => { - expectErrors(` - { - dog @unknown(directive: "value") { - name - } - } - `).to.deep.equal([ - { - message: 'Unknown directive "@unknown".', - locations: [{ line: 3, column: 13 }], - }, - ]); - }); - - it('with many unknown directives', () => { - expectErrors(` - { - dog @unknown(directive: "value") { - name - } - human @unknown(directive: "value") { - name - pets @unknown(directive: "value") { - name - } - } - } - `).to.deep.equal([ - { - message: 'Unknown directive "@unknown".', - locations: [{ line: 3, column: 13 }], - }, - { - message: 'Unknown directive "@unknown".', - locations: [{ line: 6, column: 15 }], - }, - { - message: 'Unknown directive "@unknown".', - locations: [{ line: 8, column: 16 }], - }, - ]); - }); - - it('with well placed directives', () => { - expectValid(` - query ($var: Boolean) @onQuery { - name @include(if: $var) - ...Frag @include(if: true) - skippedField @skip(if: true) - ...SkippedFrag @skip(if: true) - - ... @skip(if: true) { - skippedField - } - } - - mutation @onMutation { - someField - } - - subscription @onSubscription { - someField - } - - fragment Frag on SomeType @onFragmentDefinition { - someField - } - `); - }); - - it('with well placed variable definition directive', () => { - expectValid(` - query Foo($var: Boolean @onVariableDefinition) { - name - } - `); - }); - - it('with misplaced directives', () => { - expectErrors(` - query Foo($var: Boolean) @include(if: true) { - name @onQuery @include(if: $var) - ...Frag @onQuery - } - - mutation Bar @onQuery { - someField - } - `).to.deep.equal([ - { - message: 'Directive "@include" may not be used on QUERY.', - locations: [{ line: 2, column: 32 }], - }, - { - message: 'Directive "@onQuery" may not be used on FIELD.', - locations: [{ line: 3, column: 14 }], - }, - { - message: 'Directive "@onQuery" may not be used on FRAGMENT_SPREAD.', - locations: [{ line: 4, column: 17 }], - }, - { - message: 'Directive "@onQuery" may not be used on MUTATION.', - locations: [{ line: 7, column: 20 }], - }, - ]); - }); - - it('with misplaced variable definition directive', () => { - expectErrors(` - query Foo($var: Boolean @onField) { - name - } - `).to.deep.equal([ - { - message: 'Directive "@onField" may not be used on VARIABLE_DEFINITION.', - locations: [{ line: 2, column: 31 }], - }, - ]); - }); - - describe('within SDL', () => { - it('with directive defined inside SDL', () => { - expectValidSDL(` - type Query { - foo: String @test - } - - directive @test on FIELD_DEFINITION - `); - }); - - it('with standard directive', () => { - expectValidSDL(` - type Query { - foo: String @deprecated - } - `); - }); - - it('with overridden standard directive', () => { - expectValidSDL(` - schema @deprecated { - query: Query - } - directive @deprecated on SCHEMA - `); - }); - - it('with directive defined in schema extension', () => { - const schema = buildSchema(` - type Query { - foo: String - } - `); - expectValidSDL( - ` - directive @test on OBJECT - - extend type Query @test - `, - schema, - ); - }); - - it('with directive used in schema extension', () => { - const schema = buildSchema(` - directive @test on OBJECT - - type Query { - foo: String - } - `); - expectValidSDL( - ` - extend type Query @test - `, - schema, - ); - }); - - it('with unknown directive in schema extension', () => { - const schema = buildSchema(` - type Query { - foo: String - } - `); - expectSDLErrors( - ` - extend type Query @unknown - `, - schema, - ).to.deep.equal([ - { - message: 'Unknown directive "@unknown".', - locations: [{ line: 2, column: 29 }], - }, - ]); - }); - - it('with well placed directives', () => { - expectValidSDL( - ` - type MyObj implements MyInterface @onObject { - myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition - } - - extend type MyObj @onObject - - scalar MyScalar @onScalar - - extend scalar MyScalar @onScalar - - interface MyInterface @onInterface { - myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition - } - - extend interface MyInterface @onInterface - - union MyUnion @onUnion = MyObj | Other - - extend union MyUnion @onUnion - - enum MyEnum @onEnum { - MY_VALUE @onEnumValue - } - - extend enum MyEnum @onEnum - - input MyInput @onInputObject { - myField: Int @onInputFieldDefinition - } - - extend input MyInput @onInputObject - - schema @onSchema { - query: MyQuery - } - - extend schema @onSchema - `, - schemaWithSDLDirectives, - ); - }); - - it('with misplaced directives', () => { - expectSDLErrors( - ` - type MyObj implements MyInterface @onInterface { - myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition - } - - scalar MyScalar @onEnum - - interface MyInterface @onObject { - myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition - } - - union MyUnion @onEnumValue = MyObj | Other - - enum MyEnum @onScalar { - MY_VALUE @onUnion - } - - input MyInput @onEnum { - myField: Int @onArgumentDefinition - } - - schema @onObject { - query: MyQuery - } - - extend schema @onObject - `, - schemaWithSDLDirectives, - ).to.deep.equal([ - { - message: 'Directive "@onInterface" may not be used on OBJECT.', - locations: [{ line: 2, column: 45 }], - }, - { - message: - 'Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.', - locations: [{ line: 3, column: 32 }], - }, - { - message: - 'Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION.', - locations: [{ line: 3, column: 65 }], - }, - { - message: 'Directive "@onEnum" may not be used on SCALAR.', - locations: [{ line: 6, column: 27 }], - }, - { - message: 'Directive "@onObject" may not be used on INTERFACE.', - locations: [{ line: 8, column: 33 }], - }, - { - message: - 'Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.', - locations: [{ line: 9, column: 32 }], - }, - { - message: - 'Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION.', - locations: [{ line: 9, column: 65 }], - }, - { - message: 'Directive "@onEnumValue" may not be used on UNION.', - locations: [{ line: 12, column: 25 }], - }, - { - message: 'Directive "@onScalar" may not be used on ENUM.', - locations: [{ line: 14, column: 23 }], - }, - { - message: 'Directive "@onUnion" may not be used on ENUM_VALUE.', - locations: [{ line: 15, column: 22 }], - }, - { - message: 'Directive "@onEnum" may not be used on INPUT_OBJECT.', - locations: [{ line: 18, column: 25 }], - }, - { - message: - 'Directive "@onArgumentDefinition" may not be used on INPUT_FIELD_DEFINITION.', - locations: [{ line: 19, column: 26 }], - }, - { - message: 'Directive "@onObject" may not be used on SCHEMA.', - locations: [{ line: 22, column: 18 }], - }, - { - message: 'Directive "@onObject" may not be used on SCHEMA.', - locations: [{ line: 26, column: 25 }], - }, - ]); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/KnownFragmentNamesRule-test.js b/pkg/astvalidation/reference/__tests__/KnownFragmentNamesRule-test.js deleted file mode 100644 index 68477de86..000000000 --- a/pkg/astvalidation/reference/__tests__/KnownFragmentNamesRule-test.js +++ /dev/null @@ -1,71 +0,0 @@ -import { describe, it } from 'mocha'; - -import { KnownFragmentNamesRule } from '../rules/KnownFragmentNamesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(KnownFragmentNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Known fragment names', () => { - it('known fragment names are valid', () => { - expectValid(` - { - human(id: 4) { - ...HumanFields1 - ... on Human { - ...HumanFields2 - } - ... { - name - } - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - `); - }); - - it('unknown fragment names are invalid', () => { - expectErrors(` - { - human(id: 4) { - ...UnknownFragment1 - ... on Human { - ...UnknownFragment2 - } - } - } - fragment HumanFields on Human { - name - ...UnknownFragment3 - } - `).to.deep.equal([ - { - message: 'Unknown fragment "UnknownFragment1".', - locations: [{ line: 4, column: 14 }], - }, - { - message: 'Unknown fragment "UnknownFragment2".', - locations: [{ line: 6, column: 16 }], - }, - { - message: 'Unknown fragment "UnknownFragment3".', - locations: [{ line: 12, column: 12 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/KnownTypeNamesRule-test.js b/pkg/astvalidation/reference/__tests__/KnownTypeNamesRule-test.js deleted file mode 100644 index f56ef4cea..000000000 --- a/pkg/astvalidation/reference/__tests__/KnownTypeNamesRule-test.js +++ /dev/null @@ -1,362 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { KnownTypeNamesRule } from '../rules/KnownTypeNamesRule'; - -import { - expectValidationErrors, - expectValidationErrorsWithSchema, - expectSDLValidationErrors, -} from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(KnownTypeNamesRule, queryStr); -} - -function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { - return expectValidationErrorsWithSchema(schema, KnownTypeNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, KnownTypeNamesRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Known type names', () => { - it('known type names are valid', () => { - expectValid(` - query Foo( - $var: String - $required: [Int!]! - $introspectionType: __EnumValue - ) { - user(id: 4) { - pets { ... on Pet { name }, ...PetFields, ... { name } } - } - } - - fragment PetFields on Pet { - name - } - `); - }); - - it('unknown type names are invalid', () => { - expectErrors(` - query Foo($var: JumbledUpLetters) { - user(id: 4) { - name - pets { ... on Badger { name }, ...PetFields } - } - } - fragment PetFields on Peat { - name - } - `).to.deep.equal([ - { - message: 'Unknown type "JumbledUpLetters".', - locations: [{ line: 2, column: 23 }], - }, - { - message: 'Unknown type "Badger".', - locations: [{ line: 5, column: 25 }], - }, - { - message: 'Unknown type "Peat". Did you mean "Pet" or "Cat"?', - locations: [{ line: 8, column: 29 }], - }, - ]); - }); - - it('references to standard scalars that are missing in schema', () => { - const schema = buildSchema('type Query { foo: String }'); - const query = ` - query ($id: ID, $float: Float, $int: Int) { - __typename - } - `; - expectErrorsWithSchema(schema, query).to.deep.equal([ - { - message: 'Unknown type "ID".', - locations: [{ line: 2, column: 19 }], - }, - { - message: 'Unknown type "Float".', - locations: [{ line: 2, column: 31 }], - }, - { - message: 'Unknown type "Int".', - locations: [{ line: 2, column: 44 }], - }, - ]); - }); - - describe('within SDL', () => { - it('use standard types', () => { - expectValidSDL(` - type Query { - string: String - int: Int - float: Float - boolean: Boolean - id: ID - introspectionType: __EnumValue - } - `); - }); - - it('reference types defined inside the same document', () => { - expectValidSDL(` - union SomeUnion = SomeObject | AnotherObject - - type SomeObject implements SomeInterface { - someScalar(arg: SomeInputObject): SomeScalar - } - - type AnotherObject { - foo(arg: SomeInputObject): String - } - - type SomeInterface { - someScalar(arg: SomeInputObject): SomeScalar - } - - input SomeInputObject { - someScalar: SomeScalar - } - - scalar SomeScalar - - type RootQuery { - someInterface: SomeInterface - someUnion: SomeUnion - someScalar: SomeScalar - someObject: SomeObject - } - - schema { - query: RootQuery - } - `); - }); - - it('unknown type references', () => { - expectSDLErrors(` - type A - type B - - type SomeObject implements C { - e(d: D): E - } - - union SomeUnion = F | G - - interface SomeInterface { - i(h: H): I - } - - input SomeInput { - j: J - } - - directive @SomeDirective(k: K) on QUERY - - schema { - query: L - mutation: M - subscription: N - } - `).to.deep.equal([ - { - message: 'Unknown type "C". Did you mean "A" or "B"?', - locations: [{ line: 5, column: 36 }], - }, - { - message: 'Unknown type "D". Did you mean "A", "B", or "ID"?', - locations: [{ line: 6, column: 16 }], - }, - { - message: 'Unknown type "E". Did you mean "A" or "B"?', - locations: [{ line: 6, column: 20 }], - }, - { - message: 'Unknown type "F". Did you mean "A" or "B"?', - locations: [{ line: 9, column: 27 }], - }, - { - message: 'Unknown type "G". Did you mean "A" or "B"?', - locations: [{ line: 9, column: 31 }], - }, - { - message: 'Unknown type "H". Did you mean "A" or "B"?', - locations: [{ line: 12, column: 16 }], - }, - { - message: 'Unknown type "I". Did you mean "A", "B", or "ID"?', - locations: [{ line: 12, column: 20 }], - }, - { - message: 'Unknown type "J". Did you mean "A" or "B"?', - locations: [{ line: 16, column: 14 }], - }, - { - message: 'Unknown type "K". Did you mean "A" or "B"?', - locations: [{ line: 19, column: 37 }], - }, - { - message: 'Unknown type "L". Did you mean "A" or "B"?', - locations: [{ line: 22, column: 18 }], - }, - { - message: 'Unknown type "M". Did you mean "A" or "B"?', - locations: [{ line: 23, column: 21 }], - }, - { - message: 'Unknown type "N". Did you mean "A" or "B"?', - locations: [{ line: 24, column: 25 }], - }, - ]); - }); - - it('does not consider non-type definitions', () => { - expectSDLErrors(` - query Foo { __typename } - fragment Foo on Query { __typename } - directive @Foo on QUERY - - type Query { - foo: Foo - } - `).to.deep.equal([ - { - message: 'Unknown type "Foo".', - locations: [{ line: 7, column: 16 }], - }, - ]); - }); - - it('reference standard types inside extension document', () => { - const schema = buildSchema('type Foo'); - const sdl = ` - type SomeType { - string: String - int: Int - float: Float - boolean: Boolean - id: ID - introspectionType: __EnumValue - } - `; - - expectValidSDL(sdl, schema); - }); - - it('reference types inside extension document', () => { - const schema = buildSchema('type Foo'); - const sdl = ` - type QueryRoot { - foo: Foo - bar: Bar - } - - scalar Bar - - schema { - query: QueryRoot - } - `; - - expectValidSDL(sdl, schema); - }); - - it('unknown type references inside extension document', () => { - const schema = buildSchema('type A'); - const sdl = ` - type B - - type SomeObject implements C { - e(d: D): E - } - - union SomeUnion = F | G - - interface SomeInterface { - i(h: H): I - } - - input SomeInput { - j: J - } - - directive @SomeDirective(k: K) on QUERY - - schema { - query: L - mutation: M - subscription: N - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: 'Unknown type "C". Did you mean "A" or "B"?', - locations: [{ line: 4, column: 36 }], - }, - { - message: 'Unknown type "D". Did you mean "A", "B", or "ID"?', - locations: [{ line: 5, column: 16 }], - }, - { - message: 'Unknown type "E". Did you mean "A" or "B"?', - locations: [{ line: 5, column: 20 }], - }, - { - message: 'Unknown type "F". Did you mean "A" or "B"?', - locations: [{ line: 8, column: 27 }], - }, - { - message: 'Unknown type "G". Did you mean "A" or "B"?', - locations: [{ line: 8, column: 31 }], - }, - { - message: 'Unknown type "H". Did you mean "A" or "B"?', - locations: [{ line: 11, column: 16 }], - }, - { - message: 'Unknown type "I". Did you mean "A", "B", or "ID"?', - locations: [{ line: 11, column: 20 }], - }, - { - message: 'Unknown type "J". Did you mean "A" or "B"?', - locations: [{ line: 15, column: 14 }], - }, - { - message: 'Unknown type "K". Did you mean "A" or "B"?', - locations: [{ line: 18, column: 37 }], - }, - { - message: 'Unknown type "L". Did you mean "A" or "B"?', - locations: [{ line: 21, column: 18 }], - }, - { - message: 'Unknown type "M". Did you mean "A" or "B"?', - locations: [{ line: 22, column: 21 }], - }, - { - message: 'Unknown type "N". Did you mean "A" or "B"?', - locations: [{ line: 23, column: 25 }], - }, - ]); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/LoneAnonymousOperationRule-test.js b/pkg/astvalidation/reference/__tests__/LoneAnonymousOperationRule-test.js deleted file mode 100644 index 191870dd0..000000000 --- a/pkg/astvalidation/reference/__tests__/LoneAnonymousOperationRule-test.js +++ /dev/null @@ -1,106 +0,0 @@ -import { describe, it } from 'mocha'; - -import { LoneAnonymousOperationRule } from '../rules/LoneAnonymousOperationRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(LoneAnonymousOperationRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Anonymous operation must be alone', () => { - it('no operations', () => { - expectValid(` - fragment fragA on Type { - field - } - `); - }); - - it('one anon operation', () => { - expectValid(` - { - field - } - `); - }); - - it('multiple named operations', () => { - expectValid(` - query Foo { - field - } - - query Bar { - field - } - `); - }); - - it('anon operation with fragment', () => { - expectValid(` - { - ...Foo - } - fragment Foo on Type { - field - } - `); - }); - - it('multiple anon operations', () => { - expectErrors(` - { - fieldA - } - { - fieldB - } - `).to.deep.equal([ - { - message: 'This anonymous operation must be the only defined operation.', - locations: [{ line: 2, column: 7 }], - }, - { - message: 'This anonymous operation must be the only defined operation.', - locations: [{ line: 5, column: 7 }], - }, - ]); - }); - - it('anon operation with a mutation', () => { - expectErrors(` - { - fieldA - } - mutation Foo { - fieldB - } - `).to.deep.equal([ - { - message: 'This anonymous operation must be the only defined operation.', - locations: [{ line: 2, column: 7 }], - }, - ]); - }); - - it('anon operation with a subscription', () => { - expectErrors(` - { - fieldA - } - subscription Foo { - fieldB - } - `).to.deep.equal([ - { - message: 'This anonymous operation must be the only defined operation.', - locations: [{ line: 2, column: 7 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/LoneSchemaDefinitionRule-test.js b/pkg/astvalidation/reference/__tests__/LoneSchemaDefinitionRule-test.js deleted file mode 100644 index 6e040576b..000000000 --- a/pkg/astvalidation/reference/__tests__/LoneSchemaDefinitionRule-test.js +++ /dev/null @@ -1,158 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { LoneSchemaDefinitionRule } from '../rules/LoneSchemaDefinitionRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, LoneSchemaDefinitionRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Schema definition should be alone', () => { - it('no schema', () => { - expectValidSDL(` - type Query { - foo: String - } - `); - }); - - it('one schema definition', () => { - expectValidSDL(` - schema { - query: Foo - } - - type Foo { - foo: String - } - `); - }); - - it('multiple schema definitions', () => { - expectSDLErrors(` - schema { - query: Foo - } - - type Foo { - foo: String - } - - schema { - mutation: Foo - } - - schema { - subscription: Foo - } - `).to.deep.equal([ - { - message: 'Must provide only one schema definition.', - locations: [{ line: 10, column: 7 }], - }, - { - message: 'Must provide only one schema definition.', - locations: [{ line: 14, column: 7 }], - }, - ]); - }); - - it('define schema in schema extension', () => { - const schema = buildSchema(` - type Foo { - foo: String - } - `); - - expectSDLErrors( - ` - schema { - query: Foo - } - `, - schema, - ).to.deep.equal([]); - }); - - it('redefine schema in schema extension', () => { - const schema = buildSchema(` - schema { - query: Foo - } - - type Foo { - foo: String - } - `); - - expectSDLErrors( - ` - schema { - mutation: Foo - } - `, - schema, - ).to.deep.equal([ - { - message: 'Cannot define a new schema within a schema extension.', - locations: [{ line: 2, column: 9 }], - }, - ]); - }); - - it('redefine implicit schema in schema extension', () => { - const schema = buildSchema(` - type Query { - fooField: Foo - } - - type Foo { - foo: String - } - `); - - expectSDLErrors( - ` - schema { - mutation: Foo - } - `, - schema, - ).to.deep.equal([ - { - message: 'Cannot define a new schema within a schema extension.', - locations: [{ line: 2, column: 9 }], - }, - ]); - }); - - it('extend schema in schema extension', () => { - const schema = buildSchema(` - type Query { - fooField: Foo - } - - type Foo { - foo: String - } - `); - - expectValidSDL( - ` - extend schema { - mutation: Foo - } - `, - schema, - ); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/NoDeprecatedCustomRule-test.js b/pkg/astvalidation/reference/__tests__/NoDeprecatedCustomRule-test.js deleted file mode 100644 index 12d66eafc..000000000 --- a/pkg/astvalidation/reference/__tests__/NoDeprecatedCustomRule-test.js +++ /dev/null @@ -1,272 +0,0 @@ -import { describe, it } from 'mocha'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { NoDeprecatedCustomRule } from '../rules/custom/NoDeprecatedCustomRule'; - -import { expectValidationErrorsWithSchema } from './harness'; - -function buildAssertion(sdlStr: string) { - const schema = buildSchema(sdlStr); - return { expectErrors, expectValid }; - - function expectErrors(queryStr: string) { - return expectValidationErrorsWithSchema( - schema, - NoDeprecatedCustomRule, - queryStr, - ); - } - - function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); - } -} - -describe('Validate: no deprecated', () => { - describe('no deprecated fields', () => { - const { expectValid, expectErrors } = buildAssertion(` - type Query { - normalField: String - deprecatedField: String @deprecated(reason: "Some field reason.") - } - `); - - it('ignores fields that are not deprecated', () => { - expectValid(` - { - normalField - } - `); - }); - - it('ignores unknown fields', () => { - expectValid(` - { - unknownField - } - - fragment UnknownFragment on UnknownType { - deprecatedField - } - `); - }); - - it('reports error when a deprecated field is selected', () => { - const message = - 'The field Query.deprecatedField is deprecated. Some field reason.'; - - expectErrors(` - { - deprecatedField - } - - fragment QueryFragment on Query { - deprecatedField - } - `).to.deep.equal([ - { message, locations: [{ line: 3, column: 11 }] }, - { message, locations: [{ line: 7, column: 11 }] }, - ]); - }); - }); - - describe('no deprecated arguments on fields', () => { - const { expectValid, expectErrors } = buildAssertion(` - type Query { - someField( - normalArg: String, - deprecatedArg: String @deprecated(reason: "Some arg reason."), - ): String - } - `); - - it('ignores arguments that are not deprecated', () => { - expectValid(` - { - normalField(normalArg: "") - } - `); - }); - - it('ignores unknown arguments', () => { - expectValid(` - { - someField(unknownArg: "") - unknownField(deprecatedArg: "") - } - `); - }); - - it('reports error when a deprecated argument is used', () => { - expectErrors(` - { - someField(deprecatedArg: "") - } - `).to.deep.equal([ - { - message: - 'Field "Query.someField" argument "deprecatedArg" is deprecated. Some arg reason.', - locations: [{ line: 3, column: 21 }], - }, - ]); - }); - }); - - describe('no deprecated arguments on directives', () => { - const { expectValid, expectErrors } = buildAssertion(` - type Query { - someField: String - } - - directive @someDirective( - normalArg: String, - deprecatedArg: String @deprecated(reason: "Some arg reason."), - ) on FIELD - `); - - it('ignores arguments that are not deprecated', () => { - expectValid(` - { - someField @someDirective(normalArg: "") - } - `); - }); - - it('ignores unknown arguments', () => { - expectValid(` - { - someField @someDirective(unknownArg: "") - someField @unknownDirective(deprecatedArg: "") - } - `); - }); - - it('reports error when a deprecated argument is used', () => { - expectErrors(` - { - someField @someDirective(deprecatedArg: "") - } - `).to.deep.equal([ - { - message: - 'Directive "@someDirective" argument "deprecatedArg" is deprecated. Some arg reason.', - locations: [{ line: 3, column: 36 }], - }, - ]); - }); - }); - - describe('no deprecated input fields', () => { - const { expectValid, expectErrors } = buildAssertion(` - input InputType { - normalField: String - deprecatedField: String @deprecated(reason: "Some input field reason.") - } - - type Query { - someField(someArg: InputType): String - } - - directive @someDirective(someArg: InputType) on FIELD - `); - - it('ignores input fields that are not deprecated', () => { - expectValid(` - { - someField( - someArg: { normalField: "" } - ) @someDirective(someArg: { normalField: "" }) - } - `); - }); - - it('ignores unknown input fields', () => { - expectValid(` - { - someField( - someArg: { unknownField: "" } - ) - - someField( - unknownArg: { unknownField: "" } - ) - - unknownField( - unknownArg: { unknownField: "" } - ) - } - `); - }); - - it('reports error when a deprecated input field is used', () => { - const message = - 'The input field InputType.deprecatedField is deprecated. Some input field reason.'; - - expectErrors(` - { - someField( - someArg: { deprecatedField: "" } - ) @someDirective(someArg: { deprecatedField: "" }) - } - `).to.deep.equal([ - { message, locations: [{ line: 4, column: 24 }] }, - { message, locations: [{ line: 5, column: 39 }] }, - ]); - }); - }); - - describe('no deprecated enum values', () => { - const { expectValid, expectErrors } = buildAssertion(` - enum EnumType { - NORMAL_VALUE - DEPRECATED_VALUE @deprecated(reason: "Some enum reason.") - } - - type Query { - someField(enumArg: EnumType): String - } - `); - - it('ignores enum values that are not deprecated', () => { - expectValid(` - { - normalField(enumArg: NORMAL_VALUE) - } - `); - }); - - it('ignores unknown enum values', () => { - expectValid(` - query ( - $unknownValue: EnumType = UNKNOWN_VALUE - $unknownType: UnknownType = UNKNOWN_VALUE - ) { - someField(enumArg: UNKNOWN_VALUE) - someField(unknownArg: UNKNOWN_VALUE) - unknownField(unknownArg: UNKNOWN_VALUE) - } - - fragment SomeFragment on Query { - someField(enumArg: UNKNOWN_VALUE) - } - `); - }); - - it('reports error when a deprecated enum value is used', () => { - const message = - 'The enum value "EnumType.DEPRECATED_VALUE" is deprecated. Some enum reason.'; - - expectErrors(` - query ( - $variable: EnumType = DEPRECATED_VALUE - ) { - someField(enumArg: DEPRECATED_VALUE) - } - `).to.deep.equal([ - { message, locations: [{ line: 3, column: 33 }] }, - { message, locations: [{ line: 5, column: 30 }] }, - ]); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/NoFragmentCyclesRule-test.js b/pkg/astvalidation/reference/__tests__/NoFragmentCyclesRule-test.js deleted file mode 100644 index 94c3d1879..000000000 --- a/pkg/astvalidation/reference/__tests__/NoFragmentCyclesRule-test.js +++ /dev/null @@ -1,260 +0,0 @@ -import { describe, it } from 'mocha'; - -import { NoFragmentCyclesRule } from '../rules/NoFragmentCyclesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(NoFragmentCyclesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: No circular fragment spreads', () => { - it('single reference is valid', () => { - expectValid(` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { name } - `); - }); - - it('spreading twice is not circular', () => { - expectValid(` - fragment fragA on Dog { ...fragB, ...fragB } - fragment fragB on Dog { name } - `); - }); - - it('spreading twice indirectly is not circular', () => { - expectValid(` - fragment fragA on Dog { ...fragB, ...fragC } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { name } - `); - }); - - it('double spread within abstract types', () => { - expectValid(` - fragment nameFragment on Pet { - ... on Dog { name } - ... on Cat { name } - } - - fragment spreadsInAnon on Pet { - ... on Dog { ...nameFragment } - ... on Cat { ...nameFragment } - } - `); - }); - - it('does not false positive on unknown fragment', () => { - expectValid(` - fragment nameFragment on Pet { - ...UnknownFragment - } - `); - }); - - it('spreading recursively within field fails', () => { - expectErrors(` - fragment fragA on Human { relatives { ...fragA } }, - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself.', - locations: [{ line: 2, column: 45 }], - }, - ]); - }); - - it('no spreading itself directly', () => { - expectErrors(` - fragment fragA on Dog { ...fragA } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself.', - locations: [{ line: 2, column: 31 }], - }, - ]); - }); - - it('no spreading itself directly within inline fragment', () => { - expectErrors(` - fragment fragA on Pet { - ... on Dog { - ...fragA - } - } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself.', - locations: [{ line: 4, column: 11 }], - }, - ]); - }); - - it('no spreading itself indirectly', () => { - expectErrors(` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragA } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself via "fragB".', - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 31 }, - ], - }, - ]); - }); - - it('no spreading itself indirectly reports opposite order', () => { - expectErrors(` - fragment fragB on Dog { ...fragA } - fragment fragA on Dog { ...fragB } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragB" within itself via "fragA".', - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 31 }, - ], - }, - ]); - }); - - it('no spreading itself indirectly within inline fragment', () => { - expectErrors(` - fragment fragA on Pet { - ... on Dog { - ...fragB - } - } - fragment fragB on Pet { - ... on Dog { - ...fragA - } - } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself via "fragB".', - locations: [ - { line: 4, column: 11 }, - { line: 9, column: 11 }, - ], - }, - ]); - }); - - it('no spreading itself deeply', () => { - expectErrors(` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { ...fragO } - fragment fragX on Dog { ...fragY } - fragment fragY on Dog { ...fragZ } - fragment fragZ on Dog { ...fragO } - fragment fragO on Dog { ...fragP } - fragment fragP on Dog { ...fragA, ...fragX } - `).to.deep.equal([ - { - message: - 'Cannot spread fragment "fragA" within itself via "fragB", "fragC", "fragO", "fragP".', - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 31 }, - { line: 4, column: 31 }, - { line: 8, column: 31 }, - { line: 9, column: 31 }, - ], - }, - { - message: - 'Cannot spread fragment "fragO" within itself via "fragP", "fragX", "fragY", "fragZ".', - locations: [ - { line: 8, column: 31 }, - { line: 9, column: 41 }, - { line: 5, column: 31 }, - { line: 6, column: 31 }, - { line: 7, column: 31 }, - ], - }, - ]); - }); - - it('no spreading itself deeply two paths', () => { - expectErrors(` - fragment fragA on Dog { ...fragB, ...fragC } - fragment fragB on Dog { ...fragA } - fragment fragC on Dog { ...fragA } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself via "fragB".', - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 31 }, - ], - }, - { - message: 'Cannot spread fragment "fragA" within itself via "fragC".', - locations: [ - { line: 2, column: 41 }, - { line: 4, column: 31 }, - ], - }, - ]); - }); - - it('no spreading itself deeply two paths -- alt traverse order', () => { - expectErrors(` - fragment fragA on Dog { ...fragC } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { ...fragA, ...fragB } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragA" within itself via "fragC".', - locations: [ - { line: 2, column: 31 }, - { line: 4, column: 31 }, - ], - }, - { - message: 'Cannot spread fragment "fragC" within itself via "fragB".', - locations: [ - { line: 4, column: 41 }, - { line: 3, column: 31 }, - ], - }, - ]); - }); - - it('no spreading itself deeply and immediately', () => { - expectErrors(` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragB, ...fragC } - fragment fragC on Dog { ...fragA, ...fragB } - `).to.deep.equal([ - { - message: 'Cannot spread fragment "fragB" within itself.', - locations: [{ line: 3, column: 31 }], - }, - { - message: - 'Cannot spread fragment "fragA" within itself via "fragB", "fragC".', - locations: [ - { line: 2, column: 31 }, - { line: 3, column: 41 }, - { line: 4, column: 31 }, - ], - }, - { - message: 'Cannot spread fragment "fragB" within itself via "fragC".', - locations: [ - { line: 3, column: 41 }, - { line: 4, column: 41 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/NoSchemaIntrospectionCustomRule-test.js b/pkg/astvalidation/reference/__tests__/NoSchemaIntrospectionCustomRule-test.js deleted file mode 100644 index 85a6dd0e3..000000000 --- a/pkg/astvalidation/reference/__tests__/NoSchemaIntrospectionCustomRule-test.js +++ /dev/null @@ -1,140 +0,0 @@ -import { describe, it } from 'mocha'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { NoSchemaIntrospectionCustomRule } from '../rules/custom/NoSchemaIntrospectionCustomRule'; - -import { expectValidationErrorsWithSchema } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrorsWithSchema( - schema, - NoSchemaIntrospectionCustomRule, - queryStr, - ); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -const schema = buildSchema(` - type Query { - someQuery: SomeType - } - - type SomeType { - someField: String - introspectionField: __EnumValue - } -`); - -describe('Validate: Prohibit introspection queries', () => { - it('ignores valid fields including __typename', () => { - expectValid(` - { - someQuery { - __typename - someField - } - } - `); - }); - - it('ignores fields not in the schema', () => { - expectValid(` - { - __introspect - } - `); - }); - - it('reports error when a field with an introspection type is requested', () => { - expectErrors(` - { - __schema { - queryType { - name - } - } - } - `).to.deep.equal([ - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', - locations: [{ line: 3, column: 9 }], - }, - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "queryType".', - locations: [{ line: 4, column: 11 }], - }, - ]); - }); - - it('reports error when a field with an introspection type is requested and aliased', () => { - expectErrors(` - { - s: __schema { - queryType { - name - } - } - } - `).to.deep.equal([ - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', - locations: [{ line: 3, column: 9 }], - }, - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "queryType".', - locations: [{ line: 4, column: 11 }], - }, - ]); - }); - - it('reports error when using a fragment with a field with an introspection type', () => { - expectErrors(` - { - ...QueryFragment - } - - fragment QueryFragment on Query { - __schema { - queryType { - name - } - } - } - `).to.deep.equal([ - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "__schema".', - locations: [{ line: 7, column: 9 }], - }, - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "queryType".', - locations: [{ line: 8, column: 11 }], - }, - ]); - }); - - it('reports error for non-standard introspection fields', () => { - expectErrors(` - { - someQuery { - introspectionField - } - } - `).to.deep.equal([ - { - message: - 'GraphQL introspection has been disabled, but the requested query contained the field "introspectionField".', - locations: [{ line: 4, column: 11 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/NoUndefinedVariablesRule-test.js b/pkg/astvalidation/reference/__tests__/NoUndefinedVariablesRule-test.js deleted file mode 100644 index 6969c89d8..000000000 --- a/pkg/astvalidation/reference/__tests__/NoUndefinedVariablesRule-test.js +++ /dev/null @@ -1,407 +0,0 @@ -import { describe, it } from 'mocha'; - -import { NoUndefinedVariablesRule } from '../rules/NoUndefinedVariablesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(NoUndefinedVariablesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: No undefined variables', () => { - it('all variables defined', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c) - } - `); - }); - - it('all variables deeply defined', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - field(a: $a) { - field(b: $b) { - field(c: $c) - } - } - } - `); - }); - - it('all variables deeply in inline fragments defined', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - ... on Type { - field(a: $a) { - field(b: $b) { - ... on Type { - field(c: $c) - } - } - } - } - } - `); - }); - - it('all variables in fragments deeply defined', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `); - }); - - it('variable within single fragment defined in multiple operations', () => { - expectValid(` - query Foo($a: String) { - ...FragA - } - query Bar($a: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - `); - }); - - it('variable within fragments defined in operations', () => { - expectValid(` - query Foo($a: String) { - ...FragA - } - query Bar($b: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `); - }); - - it('variable within recursive fragment defined', () => { - expectValid(` - query Foo($a: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragA - } - } - `); - }); - - it('variable not defined', () => { - expectErrors(` - query Foo($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c, d: $d) - } - `).to.deep.equal([ - { - message: 'Variable "$d" is not defined by operation "Foo".', - locations: [ - { line: 3, column: 39 }, - { line: 2, column: 7 }, - ], - }, - ]); - }); - - it('variable not defined by un-named query', () => { - expectErrors(` - { - field(a: $a) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined.', - locations: [ - { line: 3, column: 18 }, - { line: 2, column: 7 }, - ], - }, - ]); - }); - - it('multiple variables not defined', () => { - expectErrors(` - query Foo($b: String) { - field(a: $a, b: $b, c: $c) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined by operation "Foo".', - locations: [ - { line: 3, column: 18 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$c" is not defined by operation "Foo".', - locations: [ - { line: 3, column: 32 }, - { line: 2, column: 7 }, - ], - }, - ]); - }); - - it('variable in fragment not defined by un-named query', () => { - expectErrors(` - { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined.', - locations: [ - { line: 6, column: 18 }, - { line: 2, column: 7 }, - ], - }, - ]); - }); - - it('variable in fragment not defined by operation', () => { - expectErrors(` - query Foo($a: String, $b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `).to.deep.equal([ - { - message: 'Variable "$c" is not defined by operation "Foo".', - locations: [ - { line: 16, column: 18 }, - { line: 2, column: 7 }, - ], - }, - ]); - }); - - it('multiple variables in fragments not defined', () => { - expectErrors(` - query Foo($b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined by operation "Foo".', - locations: [ - { line: 6, column: 18 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$c" is not defined by operation "Foo".', - locations: [ - { line: 16, column: 18 }, - { line: 2, column: 7 }, - ], - }, - ]); - }); - - it('single variable in fragment not defined by multiple operations', () => { - expectErrors(` - query Foo($a: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field(a: $a, b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$b" is not defined by operation "Foo".', - locations: [ - { line: 9, column: 25 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$b" is not defined by operation "Bar".', - locations: [ - { line: 9, column: 25 }, - { line: 5, column: 7 }, - ], - }, - ]); - }); - - it('variables in fragment not defined by multiple operations', () => { - expectErrors(` - query Foo($b: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field(a: $a, b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined by operation "Foo".', - locations: [ - { line: 9, column: 18 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$b" is not defined by operation "Bar".', - locations: [ - { line: 9, column: 25 }, - { line: 5, column: 7 }, - ], - }, - ]); - }); - - it('variable in fragment used by other operation', () => { - expectErrors(` - query Foo($b: String) { - ...FragA - } - query Bar($a: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined by operation "Foo".', - locations: [ - { line: 9, column: 18 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$b" is not defined by operation "Bar".', - locations: [ - { line: 12, column: 18 }, - { line: 5, column: 7 }, - ], - }, - ]); - }); - - it('multiple undefined variables produce multiple errors', () => { - expectErrors(` - query Foo($b: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field1(a: $a, b: $b) - ...FragC - field3(a: $a, b: $b) - } - fragment FragC on Type { - field2(c: $c) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is not defined by operation "Foo".', - locations: [ - { line: 9, column: 19 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$a" is not defined by operation "Foo".', - locations: [ - { line: 11, column: 19 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$c" is not defined by operation "Foo".', - locations: [ - { line: 14, column: 19 }, - { line: 2, column: 7 }, - ], - }, - { - message: 'Variable "$b" is not defined by operation "Bar".', - locations: [ - { line: 9, column: 26 }, - { line: 5, column: 7 }, - ], - }, - { - message: 'Variable "$b" is not defined by operation "Bar".', - locations: [ - { line: 11, column: 26 }, - { line: 5, column: 7 }, - ], - }, - { - message: 'Variable "$c" is not defined by operation "Bar".', - locations: [ - { line: 14, column: 19 }, - { line: 5, column: 7 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/NoUnusedFragmentsRule-test.js b/pkg/astvalidation/reference/__tests__/NoUnusedFragmentsRule-test.js deleted file mode 100644 index d90b1b271..000000000 --- a/pkg/astvalidation/reference/__tests__/NoUnusedFragmentsRule-test.js +++ /dev/null @@ -1,163 +0,0 @@ -import { describe, it } from 'mocha'; - -import { NoUnusedFragmentsRule } from '../rules/NoUnusedFragmentsRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(NoUnusedFragmentsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: No unused fragments', () => { - it('all fragment names are used', () => { - expectValid(` - { - human(id: 4) { - ...HumanFields1 - ... on Human { - ...HumanFields2 - } - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - `); - }); - - it('all fragment names are used by multiple operations', () => { - expectValid(` - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - `); - }); - - it('contains unknown fragments', () => { - expectErrors(` - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - fragment Unused1 on Human { - name - } - fragment Unused2 on Human { - name - } - `).to.deep.equal([ - { - message: 'Fragment "Unused1" is never used.', - locations: [{ line: 22, column: 7 }], - }, - { - message: 'Fragment "Unused2" is never used.', - locations: [{ line: 25, column: 7 }], - }, - ]); - }); - - it('contains unknown fragments with ref cycle', () => { - expectErrors(` - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - fragment Unused1 on Human { - name - ...Unused2 - } - fragment Unused2 on Human { - name - ...Unused1 - } - `).to.deep.equal([ - { - message: 'Fragment "Unused1" is never used.', - locations: [{ line: 22, column: 7 }], - }, - { - message: 'Fragment "Unused2" is never used.', - locations: [{ line: 26, column: 7 }], - }, - ]); - }); - - it('contains unknown and undef fragments', () => { - expectErrors(` - query Foo { - human(id: 4) { - ...bar - } - } - fragment foo on Human { - name - } - `).to.deep.equal([ - { - message: 'Fragment "foo" is never used.', - locations: [{ line: 7, column: 7 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/NoUnusedVariablesRule-test.js b/pkg/astvalidation/reference/__tests__/NoUnusedVariablesRule-test.js deleted file mode 100644 index aa111b11f..000000000 --- a/pkg/astvalidation/reference/__tests__/NoUnusedVariablesRule-test.js +++ /dev/null @@ -1,233 +0,0 @@ -import { describe, it } from 'mocha'; - -import { NoUnusedVariablesRule } from '../rules/NoUnusedVariablesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(NoUnusedVariablesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: No unused variables', () => { - it('uses all variables', () => { - expectValid(` - query ($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c) - } - `); - }); - - it('uses all variables deeply', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - field(a: $a) { - field(b: $b) { - field(c: $c) - } - } - } - `); - }); - - it('uses all variables deeply in inline fragments', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - ... on Type { - field(a: $a) { - field(b: $b) { - ... on Type { - field(c: $c) - } - } - } - } - } - `); - }); - - it('uses all variables in fragments', () => { - expectValid(` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `); - }); - - it('variable used by fragment in multiple operations', () => { - expectValid(` - query Foo($a: String) { - ...FragA - } - query Bar($b: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `); - }); - - it('variable used by recursive fragment', () => { - expectValid(` - query Foo($a: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragA - } - } - `); - }); - - it('variable not used', () => { - expectErrors(` - query ($a: String, $b: String, $c: String) { - field(a: $a, b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$c" is never used.', - locations: [{ line: 2, column: 38 }], - }, - ]); - }); - - it('multiple variables not used', () => { - expectErrors(` - query Foo($a: String, $b: String, $c: String) { - field(b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$a" is never used in operation "Foo".', - locations: [{ line: 2, column: 17 }], - }, - { - message: 'Variable "$c" is never used in operation "Foo".', - locations: [{ line: 2, column: 41 }], - }, - ]); - }); - - it('variable not used in fragments', () => { - expectErrors(` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field - } - `).to.deep.equal([ - { - message: 'Variable "$c" is never used in operation "Foo".', - locations: [{ line: 2, column: 41 }], - }, - ]); - }); - - it('multiple variables not used in fragments', () => { - expectErrors(` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field - } - `).to.deep.equal([ - { - message: 'Variable "$a" is never used in operation "Foo".', - locations: [{ line: 2, column: 17 }], - }, - { - message: 'Variable "$c" is never used in operation "Foo".', - locations: [{ line: 2, column: 41 }], - }, - ]); - }); - - it('variable not used by unreferenced fragment', () => { - expectErrors(` - query Foo($b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$b" is never used in operation "Foo".', - locations: [{ line: 2, column: 17 }], - }, - ]); - }); - - it('variable not used by fragment used by other operation', () => { - expectErrors(` - query Foo($b: String) { - ...FragA - } - query Bar($a: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `).to.deep.equal([ - { - message: 'Variable "$b" is never used in operation "Foo".', - locations: [{ line: 2, column: 17 }], - }, - { - message: 'Variable "$a" is never used in operation "Bar".', - locations: [{ line: 5, column: 17 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/OverlappingFieldsCanBeMergedRule-test.js b/pkg/astvalidation/reference/__tests__/OverlappingFieldsCanBeMergedRule-test.js deleted file mode 100644 index 080f859b8..000000000 --- a/pkg/astvalidation/reference/__tests__/OverlappingFieldsCanBeMergedRule-test.js +++ /dev/null @@ -1,1050 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { OverlappingFieldsCanBeMergedRule } from '../rules/OverlappingFieldsCanBeMergedRule'; - -import { - expectValidationErrors, - expectValidationErrorsWithSchema, -} from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(OverlappingFieldsCanBeMergedRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { - return expectValidationErrorsWithSchema( - schema, - OverlappingFieldsCanBeMergedRule, - queryStr, - ); -} - -function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { - expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); -} - -describe('Validate: Overlapping fields can be merged', () => { - it('unique fields', () => { - expectValid(` - fragment uniqueFields on Dog { - name - nickname - } - `); - }); - - it('identical fields', () => { - expectValid(` - fragment mergeIdenticalFields on Dog { - name - name - } - `); - }); - - it('identical fields with identical args', () => { - expectValid(` - fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: SIT) - } - `); - }); - - it('identical fields with identical directives', () => { - expectValid(` - fragment mergeSameFieldsWithSameDirectives on Dog { - name @include(if: true) - name @include(if: true) - } - `); - }); - - it('different args with different aliases', () => { - expectValid(` - fragment differentArgsWithDifferentAliases on Dog { - knowsSit: doesKnowCommand(dogCommand: SIT) - knowsDown: doesKnowCommand(dogCommand: DOWN) - } - `); - }); - - it('different directives with different aliases', () => { - expectValid(` - fragment differentDirectivesWithDifferentAliases on Dog { - nameIfTrue: name @include(if: true) - nameIfFalse: name @include(if: false) - } - `); - }); - - it('different skip/include directives accepted', () => { - // Note: Differing skip/include directives don't create an ambiguous return - // value and are acceptable in conditions where differing runtime values - // may have the same desired effect of including or skipping a field. - expectValid(` - fragment differentDirectivesWithDifferentAliases on Dog { - name @include(if: true) - name @include(if: false) - } - `); - }); - - it('Same aliases with different field targets', () => { - expectErrors(` - fragment sameAliasesWithDifferentFieldTargets on Dog { - fido: name - fido: nickname - } - `).to.deep.equal([ - { - message: - 'Fields "fido" conflict because "name" and "nickname" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 9 }, - ], - }, - ]); - }); - - it('Same aliases allowed on non-overlapping fields', () => { - // This is valid since no object can be both a "Dog" and a "Cat", thus - // these fields can never overlap. - expectValid(` - fragment sameAliasesWithDifferentFieldTargets on Pet { - ... on Dog { - name - } - ... on Cat { - name: nickname - } - } - `); - }); - - it('Alias masking direct field access', () => { - expectErrors(` - fragment aliasMaskingDirectFieldAccess on Dog { - name: nickname - name - } - `).to.deep.equal([ - { - message: - 'Fields "name" conflict because "nickname" and "name" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 9 }, - ], - }, - ]); - }); - - it('different args, second adds an argument', () => { - expectErrors(` - fragment conflictingArgs on Dog { - doesKnowCommand - doesKnowCommand(dogCommand: HEEL) - } - `).to.deep.equal([ - { - message: - 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 9 }, - ], - }, - ]); - }); - - it('different args, second missing an argument', () => { - expectErrors(` - fragment conflictingArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand - } - `).to.deep.equal([ - { - message: - 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 9 }, - ], - }, - ]); - }); - - it('conflicting arg values', () => { - expectErrors(` - fragment conflictingArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: HEEL) - } - `).to.deep.equal([ - { - message: - 'Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 9 }, - ], - }, - ]); - }); - - it('conflicting arg names', () => { - expectErrors(` - fragment conflictingArgs on Dog { - isAtLocation(x: 0) - isAtLocation(y: 0) - } - `).to.deep.equal([ - { - message: - 'Fields "isAtLocation" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 9 }, - ], - }, - ]); - }); - - it('allows different args where no conflict is possible', () => { - // This is valid since no object can be both a "Dog" and a "Cat", thus - // these fields can never overlap. - expectValid(` - fragment conflictingArgs on Pet { - ... on Dog { - name(surname: true) - } - ... on Cat { - name - } - } - `); - }); - - it('encounters conflict in fragments', () => { - expectErrors(` - { - ...A - ...B - } - fragment A on Type { - x: a - } - fragment B on Type { - x: b - } - `).to.deep.equal([ - { - message: - 'Fields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 7, column: 9 }, - { line: 10, column: 9 }, - ], - }, - ]); - }); - - it('reports each conflict once', () => { - expectErrors(` - { - f1 { - ...A - ...B - } - f2 { - ...B - ...A - } - f3 { - ...A - ...B - x: c - } - } - fragment A on Type { - x: a - } - fragment B on Type { - x: b - } - `).to.deep.equal([ - { - message: - 'Fields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 18, column: 9 }, - { line: 21, column: 9 }, - ], - }, - { - message: - 'Fields "x" conflict because "c" and "a" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 14, column: 11 }, - { line: 18, column: 9 }, - ], - }, - { - message: - 'Fields "x" conflict because "c" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 14, column: 11 }, - { line: 21, column: 9 }, - ], - }, - ]); - }); - - it('deep conflict', () => { - expectErrors(` - { - field { - x: a - }, - field { - x: b - } - } - `).to.deep.equal([ - { - message: - 'Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 11 }, - { line: 6, column: 9 }, - { line: 7, column: 11 }, - ], - }, - ]); - }); - - it('deep conflict with multiple issues', () => { - expectErrors(` - { - field { - x: a - y: c - }, - field { - x: b - y: d - } - } - `).to.deep.equal([ - { - message: - 'Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields and subfields "y" conflict because "c" and "d" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 11 }, - { line: 5, column: 11 }, - { line: 7, column: 9 }, - { line: 8, column: 11 }, - { line: 9, column: 11 }, - ], - }, - ]); - }); - - it('very deep conflict', () => { - expectErrors(` - { - field { - deepField { - x: a - } - }, - field { - deepField { - x: b - } - } - } - `).to.deep.equal([ - { - message: - 'Fields "field" conflict because subfields "deepField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 4, column: 11 }, - { line: 5, column: 13 }, - { line: 8, column: 9 }, - { line: 9, column: 11 }, - { line: 10, column: 13 }, - ], - }, - ]); - }); - - it('reports deep conflict to nearest common ancestor', () => { - expectErrors(` - { - field { - deepField { - x: a - } - deepField { - x: b - } - }, - field { - deepField { - y - } - } - } - `).to.deep.equal([ - { - message: - 'Fields "deepField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 4, column: 11 }, - { line: 5, column: 13 }, - { line: 7, column: 11 }, - { line: 8, column: 13 }, - ], - }, - ]); - }); - - it('reports deep conflict to nearest common ancestor in fragments', () => { - expectErrors(` - { - field { - ...F - } - field { - ...F - } - } - fragment F on T { - deepField { - deeperField { - x: a - } - deeperField { - x: b - } - }, - deepField { - deeperField { - y - } - } - } - `).to.deep.equal([ - { - message: - 'Fields "deeperField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 12, column: 11 }, - { line: 13, column: 13 }, - { line: 15, column: 11 }, - { line: 16, column: 13 }, - ], - }, - ]); - }); - - it('reports deep conflict in nested fragments', () => { - expectErrors(` - { - field { - ...F - } - field { - ...I - } - } - fragment F on T { - x: a - ...G - } - fragment G on T { - y: c - } - fragment I on T { - y: d - ...J - } - fragment J on T { - x: b - } - `).to.deep.equal([ - { - message: - 'Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields and subfields "y" conflict because "c" and "d" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 3, column: 9 }, - { line: 11, column: 9 }, - { line: 15, column: 9 }, - { line: 6, column: 9 }, - { line: 22, column: 9 }, - { line: 18, column: 9 }, - ], - }, - ]); - }); - - it('ignores unknown fragments', () => { - expectValid(` - { - field - ...Unknown - ...Known - } - - fragment Known on T { - field - ...OtherUnknown - } - `); - }); - - describe('return types must be unambiguous', () => { - const schema = buildSchema(` - interface SomeBox { - deepBox: SomeBox - unrelatedField: String - } - - type StringBox implements SomeBox { - scalar: String - deepBox: StringBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox - } - - type IntBox implements SomeBox { - scalar: Int - deepBox: IntBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox - } - - interface NonNullStringBox1 { - scalar: String! - } - - type NonNullStringBox1Impl implements SomeBox & NonNullStringBox1 { - scalar: String! - unrelatedField: String - deepBox: SomeBox - } - - interface NonNullStringBox2 { - scalar: String! - } - - type NonNullStringBox2Impl implements SomeBox & NonNullStringBox2 { - scalar: String! - unrelatedField: String - deepBox: SomeBox - } - - type Connection { - edges: [Edge] - } - - type Edge { - node: Node - } - - type Node { - id: ID - name: String - } - - type Query { - someBox: SomeBox - connection: Connection - } - `); - - it('conflicting return types which potentially overlap', () => { - // This is invalid since an object could potentially be both the Object - // type IntBox and the interface type NonNullStringBox1. While that - // condition does not exist in the current schema, the schema could - // expand in the future to allow this. Thus it is invalid. - expectErrorsWithSchema( - schema, - ` - { - someBox { - ...on IntBox { - scalar - } - ...on NonNullStringBox1 { - scalar - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "scalar" conflict because they return conflicting types "Int" and "String!". Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 17 }, - { line: 8, column: 17 }, - ], - }, - ]); - }); - - it('compatible return shapes on different return types', () => { - // In this case `deepBox` returns `SomeBox` in the first usage, and - // `StringBox` in the second usage. These return types are not the same! - // however this is valid because the return *shapes* are compatible. - expectValidWithSchema( - schema, - ` - { - someBox { - ... on SomeBox { - deepBox { - unrelatedField - } - } - ... on StringBox { - deepBox { - unrelatedField - } - } - } - } - `, - ); - }); - - it('disallows differing return types despite no overlap', () => { - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - scalar - } - ... on StringBox { - scalar - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "scalar" conflict because they return conflicting types "Int" and "String". Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 17 }, - { line: 8, column: 17 }, - ], - }, - ]); - }); - - it('reports correctly when a non-exclusive follows an exclusive', () => { - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - deepBox { - ...X - } - } - } - someBox { - ... on StringBox { - deepBox { - ...Y - } - } - } - memoed: someBox { - ... on IntBox { - deepBox { - ...X - } - } - } - memoed: someBox { - ... on StringBox { - deepBox { - ...Y - } - } - } - other: someBox { - ...X - } - other: someBox { - ...Y - } - } - fragment X on SomeBox { - scalar - } - fragment Y on SomeBox { - scalar: unrelatedField - } - `, - ).to.deep.equal([ - { - message: - 'Fields "other" conflict because subfields "scalar" conflict because "scalar" and "unrelatedField" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 31, column: 13 }, - { line: 39, column: 13 }, - { line: 34, column: 13 }, - { line: 42, column: 13 }, - ], - }, - ]); - }); - - it('disallows differing return type nullability despite no overlap', () => { - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on NonNullStringBox1 { - scalar - } - ... on StringBox { - scalar - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "scalar" conflict because they return conflicting types "String!" and "String". Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 17 }, - { line: 8, column: 17 }, - ], - }, - ]); - }); - - it('disallows differing return type list despite no overlap', () => { - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - box: listStringBox { - scalar - } - } - ... on StringBox { - box: stringBox { - scalar - } - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "box" conflict because they return conflicting types "[StringBox]" and "StringBox". Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 17 }, - { line: 10, column: 17 }, - ], - }, - ]); - - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar - } - } - ... on StringBox { - box: listStringBox { - scalar - } - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "box" conflict because they return conflicting types "StringBox" and "[StringBox]". Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 17 }, - { line: 10, column: 17 }, - ], - }, - ]); - }); - - it('disallows differing subfields', () => { - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - box: stringBox { - val: scalar - val: unrelatedField - } - } - ... on StringBox { - box: stringBox { - val: scalar - } - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "val" conflict because "scalar" and "unrelatedField" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 6, column: 19 }, - { line: 7, column: 19 }, - ], - }, - ]); - }); - - it('disallows differing deep return types despite no overlap', () => { - expectErrorsWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar - } - } - ... on StringBox { - box: intBox { - scalar - } - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "box" conflict because subfields "scalar" conflict because they return conflicting types "String" and "Int". Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 17 }, - { line: 6, column: 19 }, - { line: 10, column: 17 }, - { line: 11, column: 19 }, - ], - }, - ]); - }); - - it('allows non-conflicting overlapping types', () => { - expectValidWithSchema( - schema, - ` - { - someBox { - ... on IntBox { - scalar: unrelatedField - } - ... on StringBox { - scalar - } - } - } - `, - ); - }); - - it('same wrapped scalar return types', () => { - expectValidWithSchema( - schema, - ` - { - someBox { - ...on NonNullStringBox1 { - scalar - } - ...on NonNullStringBox2 { - scalar - } - } - } - `, - ); - }); - - it('allows inline fragments without type condition', () => { - expectValidWithSchema( - schema, - ` - { - a - ... { - a - } - } - `, - ); - }); - - it('compares deep types including list', () => { - expectErrorsWithSchema( - schema, - ` - { - connection { - ...edgeID - edges { - node { - id: name - } - } - } - } - - fragment edgeID on Connection { - edges { - node { - id - } - } - } - `, - ).to.deep.equal([ - { - message: - 'Fields "edges" conflict because subfields "node" conflict because subfields "id" conflict because "name" and "id" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 5, column: 15 }, - { line: 6, column: 17 }, - { line: 7, column: 19 }, - { line: 14, column: 13 }, - { line: 15, column: 15 }, - { line: 16, column: 17 }, - ], - }, - ]); - }); - - it('ignores unknown types', () => { - expectValidWithSchema( - schema, - ` - { - someBox { - ...on UnknownType { - scalar - } - ...on NonNullStringBox2 { - scalar - } - } - } - `, - ); - }); - - it('works for field names that are JS keywords', () => { - const schemaWithKeywords = buildSchema(` - type Foo { - constructor: String - } - - type Query { - foo: Foo - } - `); - - expectValidWithSchema( - schemaWithKeywords, - ` - { - foo { - constructor - } - } - `, - ); - }); - }); - - it('does not infinite loop on recursive fragment', () => { - expectValid(` - fragment fragA on Human { name, relatives { name, ...fragA } } - `); - }); - - it('does not infinite loop on immediately recursive fragment', () => { - expectValid(` - fragment fragA on Human { name, ...fragA } - `); - }); - - it('does not infinite loop on transitively recursive fragment', () => { - expectValid(` - fragment fragA on Human { name, ...fragB } - fragment fragB on Human { name, ...fragC } - fragment fragC on Human { name, ...fragA } - `); - }); - - it('finds invalid case even with immediately recursive fragment', () => { - expectErrors(` - fragment sameAliasesWithDifferentFieldTargets on Dog { - ...sameAliasesWithDifferentFieldTargets - fido: name - fido: nickname - } - `).to.deep.equal([ - { - message: - 'Fields "fido" conflict because "name" and "nickname" are different fields. Use different aliases on the fields to fetch both if this was intentional.', - locations: [ - { line: 4, column: 9 }, - { line: 5, column: 9 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/PossibleFragmentSpreadsRule-test.js b/pkg/astvalidation/reference/__tests__/PossibleFragmentSpreadsRule-test.js deleted file mode 100644 index 267dbd3b3..000000000 --- a/pkg/astvalidation/reference/__tests__/PossibleFragmentSpreadsRule-test.js +++ /dev/null @@ -1,250 +0,0 @@ -import { describe, it } from 'mocha'; - -import { PossibleFragmentSpreadsRule } from '../rules/PossibleFragmentSpreadsRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(PossibleFragmentSpreadsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Possible fragment spreads', () => { - it('of the same object', () => { - expectValid(` - fragment objectWithinObject on Dog { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `); - }); - - it('of the same object with inline fragment', () => { - expectValid(` - fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } - `); - }); - - it('object into an implemented interface', () => { - expectValid(` - fragment objectWithinInterface on Pet { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `); - }); - - it('object into containing union', () => { - expectValid(` - fragment objectWithinUnion on CatOrDog { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `); - }); - - it('union into contained object', () => { - expectValid(` - fragment unionWithinObject on Dog { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `); - }); - - it('union into overlapping interface', () => { - expectValid(` - fragment unionWithinInterface on Pet { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `); - }); - - it('union into overlapping union', () => { - expectValid(` - fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `); - }); - - it('interface into implemented object', () => { - expectValid(` - fragment interfaceWithinObject on Dog { ...petFragment } - fragment petFragment on Pet { name } - `); - }); - - it('interface into overlapping interface', () => { - expectValid(` - fragment interfaceWithinInterface on Pet { ...beingFragment } - fragment beingFragment on Being { name } - `); - }); - - it('interface into overlapping interface in inline fragment', () => { - expectValid(` - fragment interfaceWithinInterface on Pet { ... on Being { name } } - `); - }); - - it('interface into overlapping union', () => { - expectValid(` - fragment interfaceWithinUnion on CatOrDog { ...petFragment } - fragment petFragment on Pet { name } - `); - }); - - it('ignores incorrect type (caught by FragmentsOnCompositeTypesRule)', () => { - expectValid(` - fragment petFragment on Pet { ...badInADifferentWay } - fragment badInADifferentWay on String { name } - `); - }); - - it('ignores unknown fragments (caught by KnownFragmentNamesRule)', () => { - expectValid(` - fragment petFragment on Pet { ...UnknownFragment } - `); - }); - - it('different object into object', () => { - expectErrors(` - fragment invalidObjectWithinObject on Cat { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `).to.deep.equal([ - { - message: - 'Fragment "dogFragment" cannot be spread here as objects of type "Cat" can never be of type "Dog".', - locations: [{ line: 2, column: 51 }], - }, - ]); - }); - - it('different object into object in inline fragment', () => { - expectErrors(` - fragment invalidObjectWithinObjectAnon on Cat { - ... on Dog { barkVolume } - } - `).to.deep.equal([ - { - message: - 'Fragment cannot be spread here as objects of type "Cat" can never be of type "Dog".', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('object into not implementing interface', () => { - expectErrors(` - fragment invalidObjectWithinInterface on Pet { ...humanFragment } - fragment humanFragment on Human { pets { name } } - `).to.deep.equal([ - { - message: - 'Fragment "humanFragment" cannot be spread here as objects of type "Pet" can never be of type "Human".', - locations: [{ line: 2, column: 54 }], - }, - ]); - }); - - it('object into not containing union', () => { - expectErrors(` - fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } - fragment humanFragment on Human { pets { name } } - `).to.deep.equal([ - { - message: - 'Fragment "humanFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "Human".', - locations: [{ line: 2, column: 55 }], - }, - ]); - }); - - it('union into not contained object', () => { - expectErrors(` - fragment invalidUnionWithinObject on Human { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `).to.deep.equal([ - { - message: - 'Fragment "catOrDogFragment" cannot be spread here as objects of type "Human" can never be of type "CatOrDog".', - locations: [{ line: 2, column: 52 }], - }, - ]); - }); - - it('union into non overlapping interface', () => { - expectErrors(` - fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } - fragment humanOrAlienFragment on HumanOrAlien { __typename } - `).to.deep.equal([ - { - message: - 'Fragment "humanOrAlienFragment" cannot be spread here as objects of type "Pet" can never be of type "HumanOrAlien".', - locations: [{ line: 2, column: 53 }], - }, - ]); - }); - - it('union into non overlapping union', () => { - expectErrors(` - fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } - fragment humanOrAlienFragment on HumanOrAlien { __typename } - `).to.deep.equal([ - { - message: - 'Fragment "humanOrAlienFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "HumanOrAlien".', - locations: [{ line: 2, column: 54 }], - }, - ]); - }); - - it('interface into non implementing object', () => { - expectErrors(` - fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } - fragment intelligentFragment on Intelligent { iq } - `).to.deep.equal([ - { - message: - 'Fragment "intelligentFragment" cannot be spread here as objects of type "Cat" can never be of type "Intelligent".', - locations: [{ line: 2, column: 54 }], - }, - ]); - }); - - it('interface into non overlapping interface', () => { - expectErrors(` - fragment invalidInterfaceWithinInterface on Pet { - ...intelligentFragment - } - fragment intelligentFragment on Intelligent { iq } - `).to.deep.equal([ - { - message: - 'Fragment "intelligentFragment" cannot be spread here as objects of type "Pet" can never be of type "Intelligent".', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('interface into non overlapping interface in inline fragment', () => { - expectErrors(` - fragment invalidInterfaceWithinInterfaceAnon on Pet { - ...on Intelligent { iq } - } - `).to.deep.equal([ - { - message: - 'Fragment cannot be spread here as objects of type "Pet" can never be of type "Intelligent".', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('interface into non overlapping union', () => { - expectErrors(` - fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } - fragment petFragment on Pet { name } - `).to.deep.equal([ - { - message: - 'Fragment "petFragment" cannot be spread here as objects of type "HumanOrAlien" can never be of type "Pet".', - locations: [{ line: 2, column: 62 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/PossibleTypeExtensionsRule-test.js b/pkg/astvalidation/reference/__tests__/PossibleTypeExtensionsRule-test.js deleted file mode 100644 index 932f7ccef..000000000 --- a/pkg/astvalidation/reference/__tests__/PossibleTypeExtensionsRule-test.js +++ /dev/null @@ -1,271 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { PossibleTypeExtensionsRule } from '../rules/PossibleTypeExtensionsRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, PossibleTypeExtensionsRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Possible type extensions', () => { - it('no extensions', () => { - expectValidSDL(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - `); - }); - - it('one extension per type', () => { - expectValidSDL(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - `); - }); - - it('many extensions per type', () => { - expectValidSDL(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - `); - }); - - it('extending unknown type', () => { - const message = - 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?'; - - expectSDLErrors(` - type Known - - extend scalar Unknown @dummy - extend type Unknown @dummy - extend interface Unknown @dummy - extend union Unknown @dummy - extend enum Unknown @dummy - extend input Unknown @dummy - `).to.deep.equal([ - { message, locations: [{ line: 4, column: 21 }] }, - { message, locations: [{ line: 5, column: 19 }] }, - { message, locations: [{ line: 6, column: 24 }] }, - { message, locations: [{ line: 7, column: 20 }] }, - { message, locations: [{ line: 8, column: 19 }] }, - { message, locations: [{ line: 9, column: 20 }] }, - ]); - }); - - it('does not consider non-type definitions', () => { - const message = 'Cannot extend type "Foo" because it is not defined.'; - - expectSDLErrors(` - query Foo { __typename } - fragment Foo on Query { __typename } - directive @Foo on SCHEMA - - extend scalar Foo @dummy - extend type Foo @dummy - extend interface Foo @dummy - extend union Foo @dummy - extend enum Foo @dummy - extend input Foo @dummy - `).to.deep.equal([ - { message, locations: [{ line: 6, column: 21 }] }, - { message, locations: [{ line: 7, column: 19 }] }, - { message, locations: [{ line: 8, column: 24 }] }, - { message, locations: [{ line: 9, column: 20 }] }, - { message, locations: [{ line: 10, column: 19 }] }, - { message, locations: [{ line: 11, column: 20 }] }, - ]); - }); - - it('extending with different kinds', () => { - expectSDLErrors(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - - extend type FooScalar @dummy - extend interface FooObject @dummy - extend union FooInterface @dummy - extend enum FooUnion @dummy - extend input FooEnum @dummy - extend scalar FooInputObject @dummy - `).to.deep.equal([ - { - message: 'Cannot extend non-object type "FooScalar".', - locations: [ - { line: 2, column: 7 }, - { line: 9, column: 7 }, - ], - }, - { - message: 'Cannot extend non-interface type "FooObject".', - locations: [ - { line: 3, column: 7 }, - { line: 10, column: 7 }, - ], - }, - { - message: 'Cannot extend non-union type "FooInterface".', - locations: [ - { line: 4, column: 7 }, - { line: 11, column: 7 }, - ], - }, - { - message: 'Cannot extend non-enum type "FooUnion".', - locations: [ - { line: 5, column: 7 }, - { line: 12, column: 7 }, - ], - }, - { - message: 'Cannot extend non-input object type "FooEnum".', - locations: [ - { line: 6, column: 7 }, - { line: 13, column: 7 }, - ], - }, - { - message: 'Cannot extend non-scalar type "FooInputObject".', - locations: [ - { line: 7, column: 7 }, - { line: 14, column: 7 }, - ], - }, - ]); - }); - - it('extending types within existing schema', () => { - const schema = buildSchema(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - `); - const sdl = ` - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - `; - - expectValidSDL(sdl, schema); - }); - - it('extending unknown types within existing schema', () => { - const schema = buildSchema('type Known'); - const sdl = ` - extend scalar Unknown @dummy - extend type Unknown @dummy - extend interface Unknown @dummy - extend union Unknown @dummy - extend enum Unknown @dummy - extend input Unknown @dummy - `; - - const message = - 'Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?'; - expectSDLErrors(sdl, schema).to.deep.equal([ - { message, locations: [{ line: 2, column: 21 }] }, - { message, locations: [{ line: 3, column: 19 }] }, - { message, locations: [{ line: 4, column: 24 }] }, - { message, locations: [{ line: 5, column: 20 }] }, - { message, locations: [{ line: 6, column: 19 }] }, - { message, locations: [{ line: 7, column: 20 }] }, - ]); - }); - - it('extending types with different kinds within existing schema', () => { - const schema = buildSchema(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - `); - const sdl = ` - extend type FooScalar @dummy - extend interface FooObject @dummy - extend union FooInterface @dummy - extend enum FooUnion @dummy - extend input FooEnum @dummy - extend scalar FooInputObject @dummy - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: 'Cannot extend non-object type "FooScalar".', - locations: [{ line: 2, column: 7 }], - }, - { - message: 'Cannot extend non-interface type "FooObject".', - locations: [{ line: 3, column: 7 }], - }, - { - message: 'Cannot extend non-union type "FooInterface".', - locations: [{ line: 4, column: 7 }], - }, - { - message: 'Cannot extend non-enum type "FooUnion".', - locations: [{ line: 5, column: 7 }], - }, - { - message: 'Cannot extend non-input object type "FooEnum".', - locations: [{ line: 6, column: 7 }], - }, - { - message: 'Cannot extend non-scalar type "FooInputObject".', - locations: [{ line: 7, column: 7 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/ProvidedRequiredArgumentsRule-test.js b/pkg/astvalidation/reference/__tests__/ProvidedRequiredArgumentsRule-test.js deleted file mode 100644 index 7976f46bd..000000000 --- a/pkg/astvalidation/reference/__tests__/ProvidedRequiredArgumentsRule-test.js +++ /dev/null @@ -1,356 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { - ProvidedRequiredArgumentsRule, - ProvidedRequiredArgumentsOnDirectivesRule, -} from '../rules/ProvidedRequiredArgumentsRule'; - -import { expectValidationErrors, expectSDLValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(ProvidedRequiredArgumentsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors( - schema, - ProvidedRequiredArgumentsOnDirectivesRule, - sdlStr, - ); -} - -function expectValidSDL(sdlStr: string) { - expectSDLErrors(sdlStr).to.deep.equal([]); -} - -describe('Validate: Provided required arguments', () => { - it('ignores unknown arguments', () => { - expectValid(` - { - dog { - isHouseTrained(unknownArgument: true) - } - } - `); - }); - - describe('Valid non-nullable value', () => { - it('Arg on optional arg', () => { - expectValid(` - { - dog { - isHouseTrained(atOtherHomes: true) - } - } - `); - }); - - it('No Arg on optional arg', () => { - expectValid(` - { - dog { - isHouseTrained - } - } - `); - }); - - it('No arg on non-null field with default', () => { - expectValid(` - { - complicatedArgs { - nonNullFieldWithDefault - } - } - `); - }); - - it('Multiple args', () => { - expectValid(` - { - complicatedArgs { - multipleReqs(req1: 1, req2: 2) - } - } - `); - }); - - it('Multiple args reverse order', () => { - expectValid(` - { - complicatedArgs { - multipleReqs(req2: 2, req1: 1) - } - } - `); - }); - - it('No args on multiple optional', () => { - expectValid(` - { - complicatedArgs { - multipleOpts - } - } - `); - }); - - it('One arg on multiple optional', () => { - expectValid(` - { - complicatedArgs { - multipleOpts(opt1: 1) - } - } - `); - }); - - it('Second arg on multiple optional', () => { - expectValid(` - { - complicatedArgs { - multipleOpts(opt2: 1) - } - } - `); - }); - - it('Multiple required args on mixedList', () => { - expectValid(` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4) - } - } - `); - }); - - it('Multiple required and one optional arg on mixedList', () => { - expectValid(` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5) - } - } - `); - }); - - it('All required and optional args on mixedList', () => { - expectValid(` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) - } - } - `); - }); - }); - - describe('Invalid non-nullable value', () => { - it('Missing one non-nullable argument', () => { - expectErrors(` - { - complicatedArgs { - multipleReqs(req2: 2) - } - } - `).to.deep.equal([ - { - message: - 'Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.', - locations: [{ line: 4, column: 13 }], - }, - ]); - }); - - it('Missing multiple non-nullable arguments', () => { - expectErrors(` - { - complicatedArgs { - multipleReqs - } - } - `).to.deep.equal([ - { - message: - 'Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.', - locations: [{ line: 4, column: 13 }], - }, - { - message: - 'Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.', - locations: [{ line: 4, column: 13 }], - }, - ]); - }); - - it('Incorrect value and missing argument', () => { - expectErrors(` - { - complicatedArgs { - multipleReqs(req1: "one") - } - } - `).to.deep.equal([ - { - message: - 'Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.', - locations: [{ line: 4, column: 13 }], - }, - ]); - }); - }); - - describe('Directive arguments', () => { - it('ignores unknown directives', () => { - expectValid(` - { - dog @unknown - } - `); - }); - - it('with directives of valid types', () => { - expectValid(` - { - dog @include(if: true) { - name - } - human @skip(if: false) { - name - } - } - `); - }); - - it('with directive with missing types', () => { - expectErrors(` - { - dog @include { - name @skip - } - } - `).to.deep.equal([ - { - message: - 'Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.', - locations: [{ line: 3, column: 15 }], - }, - { - message: - 'Directive "@skip" argument "if" of type "Boolean!" is required, but it was not provided.', - locations: [{ line: 4, column: 18 }], - }, - ]); - }); - }); - - describe('within SDL', () => { - it('Missing optional args on directive defined inside SDL', () => { - expectValidSDL(` - type Query { - foo: String @test - } - - directive @test(arg1: String, arg2: String! = "") on FIELD_DEFINITION - `); - }); - - it('Missing arg on directive defined inside SDL', () => { - expectSDLErrors(` - type Query { - foo: String @test - } - - directive @test(arg: String!) on FIELD_DEFINITION - `).to.deep.equal([ - { - message: - 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', - locations: [{ line: 3, column: 23 }], - }, - ]); - }); - - it('Missing arg on standard directive', () => { - expectSDLErrors(` - type Query { - foo: String @include - } - `).to.deep.equal([ - { - message: - 'Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.', - locations: [{ line: 3, column: 23 }], - }, - ]); - }); - - it('Missing arg on overridden standard directive', () => { - expectSDLErrors(` - type Query { - foo: String @deprecated - } - directive @deprecated(reason: String!) on FIELD - `).to.deep.equal([ - { - message: - 'Directive "@deprecated" argument "reason" of type "String!" is required, but it was not provided.', - locations: [{ line: 3, column: 23 }], - }, - ]); - }); - - it('Missing arg on directive defined in schema extension', () => { - const schema = buildSchema(` - type Query { - foo: String - } - `); - expectSDLErrors( - ` - directive @test(arg: String!) on OBJECT - - extend type Query @test - `, - schema, - ).to.deep.equal([ - { - message: - 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', - locations: [{ line: 4, column: 30 }], - }, - ]); - }); - - it('Missing arg on directive used in schema extension', () => { - const schema = buildSchema(` - directive @test(arg: String!) on OBJECT - - type Query { - foo: String - } - `); - expectSDLErrors( - ` - extend type Query @test - `, - schema, - ).to.deep.equal([ - { - message: - 'Directive "@test" argument "arg" of type "String!" is required, but it was not provided.', - locations: [{ line: 2, column: 29 }], - }, - ]); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/ScalarLeafsRule-test.js b/pkg/astvalidation/reference/__tests__/ScalarLeafsRule-test.js deleted file mode 100644 index a441d4fcc..000000000 --- a/pkg/astvalidation/reference/__tests__/ScalarLeafsRule-test.js +++ /dev/null @@ -1,129 +0,0 @@ -import { describe, it } from 'mocha'; - -import { ScalarLeafsRule } from '../rules/ScalarLeafsRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(ScalarLeafsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Scalar leafs', () => { - it('valid scalar selection', () => { - expectValid(` - fragment scalarSelection on Dog { - barks - } - `); - }); - - it('object type missing selection', () => { - expectErrors(` - query directQueryOnObjectWithoutSubFields { - human - } - `).to.deep.equal([ - { - message: - 'Field "human" of type "Human" must have a selection of subfields. Did you mean "human { ... }"?', - locations: [{ line: 3, column: 9 }], - }, - ]); - }); - - it('interface type missing selection', () => { - expectErrors(` - { - human { pets } - } - `).to.deep.equal([ - { - message: - 'Field "pets" of type "[Pet]" must have a selection of subfields. Did you mean "pets { ... }"?', - locations: [{ line: 3, column: 17 }], - }, - ]); - }); - - it('valid scalar selection with args', () => { - expectValid(` - fragment scalarSelectionWithArgs on Dog { - doesKnowCommand(dogCommand: SIT) - } - `); - }); - - it('scalar selection not allowed on Boolean', () => { - expectErrors(` - fragment scalarSelectionsNotAllowedOnBoolean on Dog { - barks { sinceWhen } - } - `).to.deep.equal([ - { - message: - 'Field "barks" must not have a selection since type "Boolean" has no subfields.', - locations: [{ line: 3, column: 15 }], - }, - ]); - }); - - it('scalar selection not allowed on Enum', () => { - expectErrors(` - fragment scalarSelectionsNotAllowedOnEnum on Cat { - furColor { inHexDec } - } - `).to.deep.equal([ - { - message: - 'Field "furColor" must not have a selection since type "FurColor" has no subfields.', - locations: [{ line: 3, column: 18 }], - }, - ]); - }); - - it('scalar selection not allowed with args', () => { - expectErrors(` - fragment scalarSelectionsNotAllowedWithArgs on Dog { - doesKnowCommand(dogCommand: SIT) { sinceWhen } - } - `).to.deep.equal([ - { - message: - 'Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.', - locations: [{ line: 3, column: 42 }], - }, - ]); - }); - - it('Scalar selection not allowed with directives', () => { - expectErrors(` - fragment scalarSelectionsNotAllowedWithDirectives on Dog { - name @include(if: true) { isAlsoHumanName } - } - `).to.deep.equal([ - { - message: - 'Field "name" must not have a selection since type "String" has no subfields.', - locations: [{ line: 3, column: 33 }], - }, - ]); - }); - - it('Scalar selection not allowed with directives and args', () => { - expectErrors(` - fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { - doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } - } - `).to.deep.equal([ - { - message: - 'Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.', - locations: [{ line: 3, column: 61 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/SingleFieldSubscriptionsRule-test.js b/pkg/astvalidation/reference/__tests__/SingleFieldSubscriptionsRule-test.js deleted file mode 100644 index c8ddc5add..000000000 --- a/pkg/astvalidation/reference/__tests__/SingleFieldSubscriptionsRule-test.js +++ /dev/null @@ -1,86 +0,0 @@ -import { describe, it } from 'mocha'; - -import { SingleFieldSubscriptionsRule } from '../rules/SingleFieldSubscriptionsRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(SingleFieldSubscriptionsRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Subscriptions with single field', () => { - it('valid subscription', () => { - expectValid(` - subscription ImportantEmails { - importantEmails - } - `); - }); - - it('fails with more than one root field', () => { - expectErrors(` - subscription ImportantEmails { - importantEmails - notImportantEmails - } - `).to.deep.equal([ - { - message: - 'Subscription "ImportantEmails" must select only one top level field.', - locations: [{ line: 4, column: 9 }], - }, - ]); - }); - - it('fails with more than one root field including introspection', () => { - expectErrors(` - subscription ImportantEmails { - importantEmails - __typename - } - `).to.deep.equal([ - { - message: - 'Subscription "ImportantEmails" must select only one top level field.', - locations: [{ line: 4, column: 9 }], - }, - ]); - }); - - it('fails with many more than one root field', () => { - expectErrors(` - subscription ImportantEmails { - importantEmails - notImportantEmails - spamEmails - } - `).to.deep.equal([ - { - message: - 'Subscription "ImportantEmails" must select only one top level field.', - locations: [ - { line: 4, column: 9 }, - { line: 5, column: 9 }, - ], - }, - ]); - }); - - it('fails with more than one root field in anonymous subscriptions', () => { - expectErrors(` - subscription { - importantEmails - notImportantEmails - } - `).to.deep.equal([ - { - message: 'Anonymous Subscription must select only one top level field.', - locations: [{ line: 4, column: 9 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueArgumentNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueArgumentNamesRule-test.js deleted file mode 100644 index a18c56bd8..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueArgumentNamesRule-test.js +++ /dev/null @@ -1,166 +0,0 @@ -import { describe, it } from 'mocha'; - -import { UniqueArgumentNamesRule } from '../rules/UniqueArgumentNamesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(UniqueArgumentNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Unique argument names', () => { - it('no arguments on field', () => { - expectValid(` - { - field - } - `); - }); - - it('no arguments on directive', () => { - expectValid(` - { - field @directive - } - `); - }); - - it('argument on field', () => { - expectValid(` - { - field(arg: "value") - } - `); - }); - - it('argument on directive', () => { - expectValid(` - { - field @directive(arg: "value") - } - `); - }); - - it('same argument on two fields', () => { - expectValid(` - { - one: field(arg: "value") - two: field(arg: "value") - } - `); - }); - - it('same argument on field and directive', () => { - expectValid(` - { - field(arg: "value") @directive(arg: "value") - } - `); - }); - - it('same argument on two directives', () => { - expectValid(` - { - field @directive1(arg: "value") @directive2(arg: "value") - } - `); - }); - - it('multiple field arguments', () => { - expectValid(` - { - field(arg1: "value", arg2: "value", arg3: "value") - } - `); - }); - - it('multiple directive arguments', () => { - expectValid(` - { - field @directive(arg1: "value", arg2: "value", arg3: "value") - } - `); - }); - - it('duplicate field arguments', () => { - expectErrors(` - { - field(arg1: "value", arg1: "value") - } - `).to.deep.equal([ - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 30 }, - ], - }, - ]); - }); - - it('many duplicate field arguments', () => { - expectErrors(` - { - field(arg1: "value", arg1: "value", arg1: "value") - } - `).to.deep.equal([ - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 30 }, - ], - }, - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 45 }, - ], - }, - ]); - }); - - it('duplicate directive arguments', () => { - expectErrors(` - { - field @directive(arg1: "value", arg1: "value") - } - `).to.deep.equal([ - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 26 }, - { line: 3, column: 41 }, - ], - }, - ]); - }); - - it('many duplicate directive arguments', () => { - expectErrors(` - { - field @directive(arg1: "value", arg1: "value", arg1: "value") - } - `).to.deep.equal([ - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 26 }, - { line: 3, column: 41 }, - ], - }, - { - message: 'There can be only one argument named "arg1".', - locations: [ - { line: 3, column: 26 }, - { line: 3, column: 56 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueDirectiveNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueDirectiveNamesRule-test.js deleted file mode 100644 index 5e898998e..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueDirectiveNamesRule-test.js +++ /dev/null @@ -1,101 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { UniqueDirectiveNamesRule } from '../rules/UniqueDirectiveNamesRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, UniqueDirectiveNamesRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Unique directive names', () => { - it('no directive', () => { - expectValidSDL(` - type Foo - `); - }); - - it('one directive', () => { - expectValidSDL(` - directive @foo on SCHEMA - `); - }); - - it('many directives', () => { - expectValidSDL(` - directive @foo on SCHEMA - directive @bar on SCHEMA - directive @baz on SCHEMA - `); - }); - - it('directive and non-directive definitions named the same', () => { - expectValidSDL(` - query foo { __typename } - fragment foo on foo { __typename } - type foo - - directive @foo on SCHEMA - `); - }); - - it('directives named the same', () => { - expectSDLErrors(` - directive @foo on SCHEMA - - directive @foo on SCHEMA - `).to.deep.equal([ - { - message: 'There can be only one directive named "@foo".', - locations: [ - { line: 2, column: 18 }, - { line: 4, column: 18 }, - ], - }, - ]); - }); - - it('adding new directive to existing schema', () => { - const schema = buildSchema('directive @foo on SCHEMA'); - - expectValidSDL('directive @bar on SCHEMA', schema); - }); - - it('adding new directive with standard name to existing schema', () => { - const schema = buildSchema('type foo'); - - expectSDLErrors('directive @skip on SCHEMA', schema).to.deep.equal([ - { - message: - 'Directive "@skip" already exists in the schema. It cannot be redefined.', - locations: [{ line: 1, column: 12 }], - }, - ]); - }); - - it('adding new directive to existing schema with same-named type', () => { - const schema = buildSchema('type foo'); - - expectValidSDL('directive @foo on SCHEMA', schema); - }); - - it('adding conflicting directives to existing schema', () => { - const schema = buildSchema('directive @foo on SCHEMA'); - - expectSDLErrors('directive @foo on SCHEMA', schema).to.deep.equal([ - { - message: - 'Directive "@foo" already exists in the schema. It cannot be redefined.', - locations: [{ line: 1, column: 12 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueDirectivesPerLocationRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueDirectivesPerLocationRule-test.js deleted file mode 100644 index 79a752241..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueDirectivesPerLocationRule-test.js +++ /dev/null @@ -1,394 +0,0 @@ -import { describe, it } from 'mocha'; - -import { parse } from '../../language/parser'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { extendSchema } from '../../utilities/extendSchema'; - -import { UniqueDirectivesPerLocationRule } from '../rules/UniqueDirectivesPerLocationRule'; - -import { - testSchema, - expectValidationErrorsWithSchema, - expectSDLValidationErrors, -} from './harness'; - -const extensionSDL = ` - directive @directive on FIELD | FRAGMENT_DEFINITION - directive @directiveA on FIELD | FRAGMENT_DEFINITION - directive @directiveB on FIELD | FRAGMENT_DEFINITION - directive @repeatable repeatable on FIELD | FRAGMENT_DEFINITION -`; -const schemaWithDirectives = extendSchema(testSchema, parse(extensionSDL)); - -function expectErrors(queryStr: string) { - return expectValidationErrorsWithSchema( - schemaWithDirectives, - UniqueDirectivesPerLocationRule, - queryStr, - ); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors( - schema, - UniqueDirectivesPerLocationRule, - sdlStr, - ); -} - -describe('Validate: Directives Are Unique Per Location', () => { - it('no directives', () => { - expectValid(` - fragment Test on Type { - field - } - `); - }); - - it('unique directives in different locations', () => { - expectValid(` - fragment Test on Type @directiveA { - field @directiveB - } - `); - }); - - it('unique directives in same locations', () => { - expectValid(` - fragment Test on Type @directiveA @directiveB { - field @directiveA @directiveB - } - `); - }); - - it('same directives in different locations', () => { - expectValid(` - fragment Test on Type @directiveA { - field @directiveA - } - `); - }); - - it('same directives in similar locations', () => { - expectValid(` - fragment Test on Type { - field @directive - field @directive - } - `); - }); - - it('repeatable directives in same location', () => { - expectValid(` - fragment Test on Type @repeatable @repeatable { - field @repeatable @repeatable - } - `); - }); - - it('unknown directives must be ignored', () => { - expectValid(` - type Test @unknown @unknown { - field: String! @unknown @unknown - } - - extend type Test @unknown { - anotherField: String! - } - `); - }); - - it('duplicate directives in one location', () => { - expectErrors(` - fragment Test on Type { - field @directive @directive - } - `).to.deep.equal([ - { - message: - 'The directive "@directive" can only be used once at this location.', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 26 }, - ], - }, - ]); - }); - - it('many duplicate directives in one location', () => { - expectErrors(` - fragment Test on Type { - field @directive @directive @directive - } - `).to.deep.equal([ - { - message: - 'The directive "@directive" can only be used once at this location.', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 26 }, - ], - }, - { - message: - 'The directive "@directive" can only be used once at this location.', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 37 }, - ], - }, - ]); - }); - - it('different duplicate directives in one location', () => { - expectErrors(` - fragment Test on Type { - field @directiveA @directiveB @directiveA @directiveB - } - `).to.deep.equal([ - { - message: - 'The directive "@directiveA" can only be used once at this location.', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 39 }, - ], - }, - { - message: - 'The directive "@directiveB" can only be used once at this location.', - locations: [ - { line: 3, column: 27 }, - { line: 3, column: 51 }, - ], - }, - ]); - }); - - it('duplicate directives in many locations', () => { - expectErrors(` - fragment Test on Type @directive @directive { - field @directive @directive - } - `).to.deep.equal([ - { - message: - 'The directive "@directive" can only be used once at this location.', - locations: [ - { line: 2, column: 29 }, - { line: 2, column: 40 }, - ], - }, - { - message: - 'The directive "@directive" can only be used once at this location.', - locations: [ - { line: 3, column: 15 }, - { line: 3, column: 26 }, - ], - }, - ]); - }); - - it('duplicate directives on SDL definitions', () => { - expectSDLErrors(` - directive @nonRepeatable on - SCHEMA | SCALAR | OBJECT | INTERFACE | UNION | INPUT_OBJECT - - schema @nonRepeatable @nonRepeatable { query: Dummy } - - scalar TestScalar @nonRepeatable @nonRepeatable - type TestObject @nonRepeatable @nonRepeatable - interface TestInterface @nonRepeatable @nonRepeatable - union TestUnion @nonRepeatable @nonRepeatable - input TestInput @nonRepeatable @nonRepeatable - `).to.deep.equal([ - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 5, column: 14 }, - { line: 5, column: 29 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 7, column: 25 }, - { line: 7, column: 40 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 8, column: 23 }, - { line: 8, column: 38 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 9, column: 31 }, - { line: 9, column: 46 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 10, column: 23 }, - { line: 10, column: 38 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 11, column: 23 }, - { line: 11, column: 38 }, - ], - }, - ]); - }); - - it('duplicate directives on SDL extensions', () => { - expectSDLErrors(` - directive @nonRepeatable on - SCHEMA | SCALAR | OBJECT | INTERFACE | UNION | INPUT_OBJECT - - extend schema @nonRepeatable @nonRepeatable - - extend scalar TestScalar @nonRepeatable @nonRepeatable - extend type TestObject @nonRepeatable @nonRepeatable - extend interface TestInterface @nonRepeatable @nonRepeatable - extend union TestUnion @nonRepeatable @nonRepeatable - extend input TestInput @nonRepeatable @nonRepeatable - `).to.deep.equal([ - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 5, column: 21 }, - { line: 5, column: 36 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 7, column: 32 }, - { line: 7, column: 47 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 8, column: 30 }, - { line: 8, column: 45 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 9, column: 38 }, - { line: 9, column: 53 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 10, column: 30 }, - { line: 10, column: 45 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 11, column: 30 }, - { line: 11, column: 45 }, - ], - }, - ]); - }); - - it('duplicate directives between SDL definitions and extensions', () => { - expectSDLErrors(` - directive @nonRepeatable on SCHEMA - - schema @nonRepeatable { query: Dummy } - extend schema @nonRepeatable - `).to.deep.equal([ - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 4, column: 14 }, - { line: 5, column: 21 }, - ], - }, - ]); - - expectSDLErrors(` - directive @nonRepeatable on SCALAR - - scalar TestScalar @nonRepeatable - extend scalar TestScalar @nonRepeatable - scalar TestScalar @nonRepeatable - `).to.deep.equal([ - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 4, column: 25 }, - { line: 5, column: 32 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 4, column: 25 }, - { line: 6, column: 25 }, - ], - }, - ]); - - expectSDLErrors(` - directive @nonRepeatable on OBJECT - - extend type TestObject @nonRepeatable - type TestObject @nonRepeatable - extend type TestObject @nonRepeatable - `).to.deep.equal([ - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 4, column: 30 }, - { line: 5, column: 23 }, - ], - }, - { - message: - 'The directive "@nonRepeatable" can only be used once at this location.', - locations: [ - { line: 4, column: 30 }, - { line: 6, column: 30 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueEnumValueNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueEnumValueNamesRule-test.js deleted file mode 100644 index a97ac3b68..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueEnumValueNamesRule-test.js +++ /dev/null @@ -1,194 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { UniqueEnumValueNamesRule } from '../rules/UniqueEnumValueNamesRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, UniqueEnumValueNamesRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Unique enum value names', () => { - it('no values', () => { - expectValidSDL(` - enum SomeEnum - `); - }); - - it('one value', () => { - expectValidSDL(` - enum SomeEnum { - FOO - } - `); - }); - - it('multiple values', () => { - expectValidSDL(` - enum SomeEnum { - FOO - BAR - } - `); - }); - - it('duplicate values inside the same enum definition', () => { - expectSDLErrors(` - enum SomeEnum { - FOO - BAR - FOO - } - `).to.deep.equal([ - { - message: 'Enum value "SomeEnum.FOO" can only be defined once.', - locations: [ - { line: 3, column: 9 }, - { line: 5, column: 9 }, - ], - }, - ]); - }); - - it('extend enum with new value', () => { - expectValidSDL(` - enum SomeEnum { - FOO - } - extend enum SomeEnum { - BAR - } - extend enum SomeEnum { - BAZ - } - `); - }); - - it('extend enum with duplicate value', () => { - expectSDLErrors(` - extend enum SomeEnum { - FOO - } - enum SomeEnum { - FOO - } - `).to.deep.equal([ - { - message: 'Enum value "SomeEnum.FOO" can only be defined once.', - locations: [ - { line: 3, column: 9 }, - { line: 6, column: 9 }, - ], - }, - ]); - }); - - it('duplicate value inside extension', () => { - expectSDLErrors(` - enum SomeEnum - extend enum SomeEnum { - FOO - BAR - FOO - } - `).to.deep.equal([ - { - message: 'Enum value "SomeEnum.FOO" can only be defined once.', - locations: [ - { line: 4, column: 9 }, - { line: 6, column: 9 }, - ], - }, - ]); - }); - - it('duplicate value inside different extensions', () => { - expectSDLErrors(` - enum SomeEnum - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - `).to.deep.equal([ - { - message: 'Enum value "SomeEnum.FOO" can only be defined once.', - locations: [ - { line: 4, column: 9 }, - { line: 7, column: 9 }, - ], - }, - ]); - }); - - it('adding new value to the type inside existing schema', () => { - const schema = buildSchema('enum SomeEnum'); - const sdl = ` - extend enum SomeEnum { - FOO - } - `; - - expectValidSDL(sdl, schema); - }); - - it('adding conflicting value to existing schema twice', () => { - const schema = buildSchema(` - enum SomeEnum { - FOO - } - `); - const sdl = ` - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: - 'Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 3, column: 9 }], - }, - { - message: - 'Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 6, column: 9 }], - }, - ]); - }); - - it('adding enum values to existing schema twice', () => { - const schema = buildSchema('enum SomeEnum'); - const sdl = ` - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: 'Enum value "SomeEnum.FOO" can only be defined once.', - locations: [ - { line: 3, column: 9 }, - { line: 6, column: 9 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueFieldDefinitionNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueFieldDefinitionNamesRule-test.js deleted file mode 100644 index c27182d1a..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueFieldDefinitionNamesRule-test.js +++ /dev/null @@ -1,435 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { UniqueFieldDefinitionNamesRule } from '../rules/UniqueFieldDefinitionNamesRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors( - schema, - UniqueFieldDefinitionNamesRule, - sdlStr, - ); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Unique field definition names', () => { - it('no fields', () => { - expectValidSDL(` - type SomeObject - interface SomeInterface - input SomeInputObject - `); - }); - - it('one field', () => { - expectValidSDL(` - type SomeObject { - foo: String - } - - interface SomeInterface { - foo: String - } - - input SomeInputObject { - foo: String - } - `); - }); - - it('multiple fields', () => { - expectValidSDL(` - type SomeObject { - foo: String - bar: String - } - - interface SomeInterface { - foo: String - bar: String - } - - input SomeInputObject { - foo: String - bar: String - } - `); - }); - - it('duplicate fields inside the same type definition', () => { - expectSDLErrors(` - type SomeObject { - foo: String - bar: String - foo: String - } - - interface SomeInterface { - foo: String - bar: String - foo: String - } - - input SomeInputObject { - foo: String - bar: String - foo: String - } - `).to.deep.equal([ - { - message: 'Field "SomeObject.foo" can only be defined once.', - locations: [ - { line: 3, column: 9 }, - { line: 5, column: 9 }, - ], - }, - { - message: 'Field "SomeInterface.foo" can only be defined once.', - locations: [ - { line: 9, column: 9 }, - { line: 11, column: 9 }, - ], - }, - { - message: 'Field "SomeInputObject.foo" can only be defined once.', - locations: [ - { line: 15, column: 9 }, - { line: 17, column: 9 }, - ], - }, - ]); - }); - - it('extend type with new field', () => { - expectValidSDL(` - type SomeObject { - foo: String - } - extend type SomeObject { - bar: String - } - extend type SomeObject { - baz: String - } - - interface SomeInterface { - foo: String - } - extend interface SomeInterface { - bar: String - } - extend interface SomeInterface { - baz: String - } - - input SomeInputObject { - foo: String - } - extend input SomeInputObject { - bar: String - } - extend input SomeInputObject { - baz: String - } - `); - }); - - it('extend type with duplicate field', () => { - expectSDLErrors(` - extend type SomeObject { - foo: String - } - type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - input SomeInputObject { - foo: String - } - `).to.deep.equal([ - { - message: 'Field "SomeObject.foo" can only be defined once.', - locations: [ - { line: 3, column: 9 }, - { line: 6, column: 9 }, - ], - }, - { - message: 'Field "SomeInterface.foo" can only be defined once.', - locations: [ - { line: 10, column: 9 }, - { line: 13, column: 9 }, - ], - }, - { - message: 'Field "SomeInputObject.foo" can only be defined once.', - locations: [ - { line: 17, column: 9 }, - { line: 20, column: 9 }, - ], - }, - ]); - }); - - it('duplicate field inside extension', () => { - expectSDLErrors(` - type SomeObject - extend type SomeObject { - foo: String - bar: String - foo: String - } - - interface SomeInterface - extend interface SomeInterface { - foo: String - bar: String - foo: String - } - - input SomeInputObject - extend input SomeInputObject { - foo: String - bar: String - foo: String - } - `).to.deep.equal([ - { - message: 'Field "SomeObject.foo" can only be defined once.', - locations: [ - { line: 4, column: 9 }, - { line: 6, column: 9 }, - ], - }, - { - message: 'Field "SomeInterface.foo" can only be defined once.', - locations: [ - { line: 11, column: 9 }, - { line: 13, column: 9 }, - ], - }, - { - message: 'Field "SomeInputObject.foo" can only be defined once.', - locations: [ - { line: 18, column: 9 }, - { line: 20, column: 9 }, - ], - }, - ]); - }); - - it('duplicate field inside different extensions', () => { - expectSDLErrors(` - type SomeObject - extend type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - } - - interface SomeInterface - extend interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - } - - input SomeInputObject - extend input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - } - `).to.deep.equal([ - { - message: 'Field "SomeObject.foo" can only be defined once.', - locations: [ - { line: 4, column: 9 }, - { line: 7, column: 9 }, - ], - }, - { - message: 'Field "SomeInterface.foo" can only be defined once.', - locations: [ - { line: 12, column: 9 }, - { line: 15, column: 9 }, - ], - }, - { - message: 'Field "SomeInputObject.foo" can only be defined once.', - locations: [ - { line: 20, column: 9 }, - { line: 23, column: 9 }, - ], - }, - ]); - }); - - it('adding new field to the type inside existing schema', () => { - const schema = buildSchema(` - type SomeObject - interface SomeInterface - input SomeInputObject - `); - const sdl = ` - extend type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - `; - - expectValidSDL(sdl, schema); - }); - - it('adding conflicting fields to existing schema twice', () => { - const schema = buildSchema(` - type SomeObject { - foo: String - } - - interface SomeInterface { - foo: String - } - - input SomeInputObject { - foo: String - } - `); - const sdl = ` - extend type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - - extend type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: - 'Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 3, column: 9 }], - }, - { - message: - 'Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 6, column: 9 }], - }, - { - message: - 'Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 9, column: 9 }], - }, - { - message: - 'Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 13, column: 9 }], - }, - { - message: - 'Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 16, column: 9 }], - }, - { - message: - 'Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension.', - locations: [{ line: 19, column: 9 }], - }, - ]); - }); - - it('adding fields to existing schema twice', () => { - const schema = buildSchema(` - type SomeObject - interface SomeInterface - input SomeInputObject - `); - const sdl = ` - extend type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: 'Field "SomeObject.foo" can only be defined once.', - locations: [ - { line: 3, column: 9 }, - { line: 6, column: 9 }, - ], - }, - { - message: 'Field "SomeInterface.foo" can only be defined once.', - locations: [ - { line: 10, column: 9 }, - { line: 13, column: 9 }, - ], - }, - { - message: 'Field "SomeInputObject.foo" can only be defined once.', - locations: [ - { line: 17, column: 9 }, - { line: 20, column: 9 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueFragmentNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueFragmentNamesRule-test.js deleted file mode 100644 index f67b462e8..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueFragmentNamesRule-test.js +++ /dev/null @@ -1,119 +0,0 @@ -import { describe, it } from 'mocha'; - -import { UniqueFragmentNamesRule } from '../rules/UniqueFragmentNamesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(UniqueFragmentNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Unique fragment names', () => { - it('no fragments', () => { - expectValid(` - { - field - } - `); - }); - - it('one fragment', () => { - expectValid(` - { - ...fragA - } - - fragment fragA on Type { - field - } - `); - }); - - it('many fragments', () => { - expectValid(` - { - ...fragA - ...fragB - ...fragC - } - fragment fragA on Type { - fieldA - } - fragment fragB on Type { - fieldB - } - fragment fragC on Type { - fieldC - } - `); - }); - - it('inline fragments are always unique', () => { - expectValid(` - { - ...on Type { - fieldA - } - ...on Type { - fieldB - } - } - `); - }); - - it('fragment and operation named the same', () => { - expectValid(` - query Foo { - ...Foo - } - fragment Foo on Type { - field - } - `); - }); - - it('fragments named the same', () => { - expectErrors(` - { - ...fragA - } - fragment fragA on Type { - fieldA - } - fragment fragA on Type { - fieldB - } - `).to.deep.equal([ - { - message: 'There can be only one fragment named "fragA".', - locations: [ - { line: 5, column: 16 }, - { line: 8, column: 16 }, - ], - }, - ]); - }); - - it('fragments named the same without being referenced', () => { - expectErrors(` - fragment fragA on Type { - fieldA - } - fragment fragA on Type { - fieldB - } - `).to.deep.equal([ - { - message: 'There can be only one fragment named "fragA".', - locations: [ - { line: 2, column: 16 }, - { line: 5, column: 16 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueInputFieldNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueInputFieldNamesRule-test.js deleted file mode 100644 index 8f2426db4..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueInputFieldNamesRule-test.js +++ /dev/null @@ -1,110 +0,0 @@ -import { describe, it } from 'mocha'; - -import { UniqueInputFieldNamesRule } from '../rules/UniqueInputFieldNamesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(UniqueInputFieldNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Unique input field names', () => { - it('input object with fields', () => { - expectValid(` - { - field(arg: { f: true }) - } - `); - }); - - it('same input object within two args', () => { - expectValid(` - { - field(arg1: { f: true }, arg2: { f: true }) - } - `); - }); - - it('multiple input object fields', () => { - expectValid(` - { - field(arg: { f1: "value", f2: "value", f3: "value" }) - } - `); - }); - - it('allows for nested input objects with similar fields', () => { - expectValid(` - { - field(arg: { - deep: { - deep: { - id: 1 - } - id: 1 - } - id: 1 - }) - } - `); - }); - - it('duplicate input object fields', () => { - expectErrors(` - { - field(arg: { f1: "value", f1: "value" }) - } - `).to.deep.equal([ - { - message: 'There can be only one input field named "f1".', - locations: [ - { line: 3, column: 22 }, - { line: 3, column: 35 }, - ], - }, - ]); - }); - - it('many duplicate input object fields', () => { - expectErrors(` - { - field(arg: { f1: "value", f1: "value", f1: "value" }) - } - `).to.deep.equal([ - { - message: 'There can be only one input field named "f1".', - locations: [ - { line: 3, column: 22 }, - { line: 3, column: 35 }, - ], - }, - { - message: 'There can be only one input field named "f1".', - locations: [ - { line: 3, column: 22 }, - { line: 3, column: 48 }, - ], - }, - ]); - }); - - it('nested duplicate input object fields', () => { - expectErrors(` - { - field(arg: { f1: {f2: "value", f2: "value" }}) - } - `).to.deep.equal([ - { - message: 'There can be only one input field named "f2".', - locations: [ - { line: 3, column: 27 }, - { line: 3, column: 40 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueOperationNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueOperationNamesRule-test.js deleted file mode 100644 index 720a285d2..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueOperationNamesRule-test.js +++ /dev/null @@ -1,135 +0,0 @@ -import { describe, it } from 'mocha'; - -import { UniqueOperationNamesRule } from '../rules/UniqueOperationNamesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(UniqueOperationNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Unique operation names', () => { - it('no operations', () => { - expectValid(` - fragment fragA on Type { - field - } - `); - }); - - it('one anon operation', () => { - expectValid(` - { - field - } - `); - }); - - it('one named operation', () => { - expectValid(` - query Foo { - field - } - `); - }); - - it('multiple operations', () => { - expectValid(` - query Foo { - field - } - - query Bar { - field - } - `); - }); - - it('multiple operations of different types', () => { - expectValid(` - query Foo { - field - } - - mutation Bar { - field - } - - subscription Baz { - field - } - `); - }); - - it('fragment and operation named the same', () => { - expectValid(` - query Foo { - ...Foo - } - fragment Foo on Type { - field - } - `); - }); - - it('multiple operations of same name', () => { - expectErrors(` - query Foo { - fieldA - } - query Foo { - fieldB - } - `).to.deep.equal([ - { - message: 'There can be only one operation named "Foo".', - locations: [ - { line: 2, column: 13 }, - { line: 5, column: 13 }, - ], - }, - ]); - }); - - it('multiple ops of same name of different types (mutation)', () => { - expectErrors(` - query Foo { - fieldA - } - mutation Foo { - fieldB - } - `).to.deep.equal([ - { - message: 'There can be only one operation named "Foo".', - locations: [ - { line: 2, column: 13 }, - { line: 5, column: 16 }, - ], - }, - ]); - }); - - it('multiple ops of same name of different types (subscription)', () => { - expectErrors(` - query Foo { - fieldA - } - subscription Foo { - fieldB - } - `).to.deep.equal([ - { - message: 'There can be only one operation named "Foo".', - locations: [ - { line: 2, column: 13 }, - { line: 5, column: 20 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueOperationTypesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueOperationTypesRule-test.js deleted file mode 100644 index fd73040c4..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueOperationTypesRule-test.js +++ /dev/null @@ -1,384 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { UniqueOperationTypesRule } from '../rules/UniqueOperationTypesRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, UniqueOperationTypesRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Unique operation types', () => { - it('no schema definition', () => { - expectValidSDL(` - type Foo - `); - }); - - it('schema definition with all types', () => { - expectValidSDL(` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - } - `); - }); - - it('schema definition with single extension', () => { - expectValidSDL(` - type Foo - - schema { query: Foo } - - extend schema { - mutation: Foo - subscription: Foo - } - `); - }); - - it('schema definition with separate extensions', () => { - expectValidSDL(` - type Foo - - schema { query: Foo } - extend schema { mutation: Foo } - extend schema { subscription: Foo } - `); - }); - - it('extend schema before definition', () => { - expectValidSDL(` - type Foo - - extend schema { mutation: Foo } - extend schema { subscription: Foo } - - schema { query: Foo } - `); - }); - - it('duplicate operation types inside single schema definition', () => { - expectSDLErrors(` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - - query: Foo - mutation: Foo - subscription: Foo - } - `).to.deep.equal([ - { - message: 'There can be only one query type in schema.', - locations: [ - { line: 5, column: 9 }, - { line: 9, column: 9 }, - ], - }, - { - message: 'There can be only one mutation type in schema.', - locations: [ - { line: 6, column: 9 }, - { line: 10, column: 9 }, - ], - }, - { - message: 'There can be only one subscription type in schema.', - locations: [ - { line: 7, column: 9 }, - { line: 11, column: 9 }, - ], - }, - ]); - }); - - it('duplicate operation types inside schema extension', () => { - expectSDLErrors(` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `).to.deep.equal([ - { - message: 'There can be only one query type in schema.', - locations: [ - { line: 5, column: 9 }, - { line: 11, column: 9 }, - ], - }, - { - message: 'There can be only one mutation type in schema.', - locations: [ - { line: 6, column: 9 }, - { line: 12, column: 9 }, - ], - }, - { - message: 'There can be only one subscription type in schema.', - locations: [ - { line: 7, column: 9 }, - { line: 13, column: 9 }, - ], - }, - ]); - }); - - it('duplicate operation types inside schema extension twice', () => { - expectSDLErrors(` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `).to.deep.equal([ - { - message: 'There can be only one query type in schema.', - locations: [ - { line: 5, column: 9 }, - { line: 11, column: 9 }, - ], - }, - { - message: 'There can be only one mutation type in schema.', - locations: [ - { line: 6, column: 9 }, - { line: 12, column: 9 }, - ], - }, - { - message: 'There can be only one subscription type in schema.', - locations: [ - { line: 7, column: 9 }, - { line: 13, column: 9 }, - ], - }, - { - message: 'There can be only one query type in schema.', - locations: [ - { line: 5, column: 9 }, - { line: 17, column: 9 }, - ], - }, - { - message: 'There can be only one mutation type in schema.', - locations: [ - { line: 6, column: 9 }, - { line: 18, column: 9 }, - ], - }, - { - message: 'There can be only one subscription type in schema.', - locations: [ - { line: 7, column: 9 }, - { line: 19, column: 9 }, - ], - }, - ]); - }); - - it('duplicate operation types inside second schema extension', () => { - expectSDLErrors(` - type Foo - - schema { - query: Foo - } - - extend schema { - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `).to.deep.equal([ - { - message: 'There can be only one query type in schema.', - locations: [ - { line: 5, column: 9 }, - { line: 14, column: 9 }, - ], - }, - { - message: 'There can be only one mutation type in schema.', - locations: [ - { line: 9, column: 9 }, - { line: 15, column: 9 }, - ], - }, - { - message: 'There can be only one subscription type in schema.', - locations: [ - { line: 10, column: 9 }, - { line: 16, column: 9 }, - ], - }, - ]); - }); - - it('define schema inside extension SDL', () => { - const schema = buildSchema('type Foo'); - const sdl = ` - schema { - query: Foo - mutation: Foo - subscription: Foo - } - `; - - expectValidSDL(sdl, schema); - }); - - it('define and extend schema inside extension SDL', () => { - const schema = buildSchema('type Foo'); - const sdl = ` - schema { query: Foo } - extend schema { mutation: Foo } - extend schema { subscription: Foo } - `; - - expectValidSDL(sdl, schema); - }); - - it('adding new operation types to existing schema', () => { - const schema = buildSchema('type Query'); - const sdl = ` - extend schema { mutation: Foo } - extend schema { subscription: Foo } - `; - - expectValidSDL(sdl, schema); - }); - - it('adding conflicting operation types to existing schema', () => { - const schema = buildSchema(` - type Query - type Mutation - type Subscription - - type Foo - `); - - const sdl = ` - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: - 'Type for query already defined in the schema. It cannot be redefined.', - locations: [{ line: 3, column: 9 }], - }, - { - message: - 'Type for mutation already defined in the schema. It cannot be redefined.', - locations: [{ line: 4, column: 9 }], - }, - { - message: - 'Type for subscription already defined in the schema. It cannot be redefined.', - locations: [{ line: 5, column: 9 }], - }, - ]); - }); - - it('adding conflicting operation types to existing schema twice', () => { - const schema = buildSchema(` - type Query - type Mutation - type Subscription - `); - - const sdl = ` - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: - 'Type for query already defined in the schema. It cannot be redefined.', - locations: [{ line: 3, column: 9 }], - }, - { - message: - 'Type for mutation already defined in the schema. It cannot be redefined.', - locations: [{ line: 4, column: 9 }], - }, - { - message: - 'Type for subscription already defined in the schema. It cannot be redefined.', - locations: [{ line: 5, column: 9 }], - }, - { - message: - 'Type for query already defined in the schema. It cannot be redefined.', - locations: [{ line: 9, column: 9 }], - }, - { - message: - 'Type for mutation already defined in the schema. It cannot be redefined.', - locations: [{ line: 10, column: 9 }], - }, - { - message: - 'Type for subscription already defined in the schema. It cannot be redefined.', - locations: [{ line: 11, column: 9 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueTypeNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueTypeNamesRule-test.js deleted file mode 100644 index 6525275e9..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueTypeNamesRule-test.js +++ /dev/null @@ -1,162 +0,0 @@ -import { describe, it } from 'mocha'; - -import type { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { UniqueTypeNamesRule } from '../rules/UniqueTypeNamesRule'; - -import { expectSDLValidationErrors } from './harness'; - -function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - return expectSDLValidationErrors(schema, UniqueTypeNamesRule, sdlStr); -} - -function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); -} - -describe('Validate: Unique type names', () => { - it('no types', () => { - expectValidSDL(` - directive @test on SCHEMA - `); - }); - - it('one type', () => { - expectValidSDL(` - type Foo - `); - }); - - it('many types', () => { - expectValidSDL(` - type Foo - type Bar - type Baz - `); - }); - - it('type and non-type definitions named the same', () => { - expectValidSDL(` - query Foo { __typename } - fragment Foo on Query { __typename } - directive @Foo on SCHEMA - - type Foo - `); - }); - - it('types named the same', () => { - expectSDLErrors(` - type Foo - - scalar Foo - type Foo - interface Foo - union Foo - enum Foo - input Foo - `).to.deep.equal([ - { - message: 'There can be only one type named "Foo".', - locations: [ - { line: 2, column: 12 }, - { line: 4, column: 14 }, - ], - }, - { - message: 'There can be only one type named "Foo".', - locations: [ - { line: 2, column: 12 }, - { line: 5, column: 12 }, - ], - }, - { - message: 'There can be only one type named "Foo".', - locations: [ - { line: 2, column: 12 }, - { line: 6, column: 17 }, - ], - }, - { - message: 'There can be only one type named "Foo".', - locations: [ - { line: 2, column: 12 }, - { line: 7, column: 13 }, - ], - }, - { - message: 'There can be only one type named "Foo".', - locations: [ - { line: 2, column: 12 }, - { line: 8, column: 12 }, - ], - }, - { - message: 'There can be only one type named "Foo".', - locations: [ - { line: 2, column: 12 }, - { line: 9, column: 13 }, - ], - }, - ]); - }); - - it('adding new type to existing schema', () => { - const schema = buildSchema('type Foo'); - - expectValidSDL('type Bar', schema); - }); - - it('adding new type to existing schema with same-named directive', () => { - const schema = buildSchema('directive @Foo on SCHEMA'); - - expectValidSDL('type Foo', schema); - }); - - it('adding conflicting types to existing schema', () => { - const schema = buildSchema('type Foo'); - const sdl = ` - scalar Foo - type Foo - interface Foo - union Foo - enum Foo - input Foo - `; - - expectSDLErrors(sdl, schema).to.deep.equal([ - { - message: - 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', - locations: [{ line: 2, column: 14 }], - }, - { - message: - 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', - locations: [{ line: 3, column: 12 }], - }, - { - message: - 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', - locations: [{ line: 4, column: 17 }], - }, - { - message: - 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', - locations: [{ line: 5, column: 13 }], - }, - { - message: - 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', - locations: [{ line: 6, column: 12 }], - }, - { - message: - 'Type "Foo" already exists in the schema. It cannot also be defined in this type definition.', - locations: [{ line: 7, column: 13 }], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/UniqueVariableNamesRule-test.js b/pkg/astvalidation/reference/__tests__/UniqueVariableNamesRule-test.js deleted file mode 100644 index 4b950fb4c..000000000 --- a/pkg/astvalidation/reference/__tests__/UniqueVariableNamesRule-test.js +++ /dev/null @@ -1,59 +0,0 @@ -import { describe, it } from 'mocha'; - -import { UniqueVariableNamesRule } from '../rules/UniqueVariableNamesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(UniqueVariableNamesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Unique variable names', () => { - it('unique variable names', () => { - expectValid(` - query A($x: Int, $y: String) { __typename } - query B($x: String, $y: Int) { __typename } - `); - }); - - it('duplicate variable names', () => { - expectErrors(` - query A($x: Int, $x: Int, $x: String) { __typename } - query B($x: String, $x: Int) { __typename } - query C($x: Int, $x: Int) { __typename } - `).to.deep.equal([ - { - message: 'There can be only one variable named "$x".', - locations: [ - { line: 2, column: 16 }, - { line: 2, column: 25 }, - ], - }, - { - message: 'There can be only one variable named "$x".', - locations: [ - { line: 2, column: 16 }, - { line: 2, column: 34 }, - ], - }, - { - message: 'There can be only one variable named "$x".', - locations: [ - { line: 3, column: 16 }, - { line: 3, column: 28 }, - ], - }, - { - message: 'There can be only one variable named "$x".', - locations: [ - { line: 4, column: 16 }, - { line: 4, column: 25 }, - ], - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/ValuesOfCorrectTypeRule-test.js b/pkg/astvalidation/reference/__tests__/ValuesOfCorrectTypeRule-test.js deleted file mode 100644 index 1f3cbab8e..000000000 --- a/pkg/astvalidation/reference/__tests__/ValuesOfCorrectTypeRule-test.js +++ /dev/null @@ -1,1197 +0,0 @@ -import { describe, it } from 'mocha'; - -import { inspect } from '../../jsutils/inspect'; - -import { GraphQLSchema } from '../../type/schema'; -import { GraphQLString } from '../../type/scalars'; -import { GraphQLScalarType, GraphQLObjectType } from '../../type/definition'; - -import { ValuesOfCorrectTypeRule } from '../rules/ValuesOfCorrectTypeRule'; - -import { - expectValidationErrors, - expectValidationErrorsWithSchema, -} from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(ValuesOfCorrectTypeRule, queryStr); -} - -function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { - return expectValidationErrorsWithSchema( - schema, - ValuesOfCorrectTypeRule, - queryStr, - ); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { - expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); -} - -describe('Validate: Values of correct type', () => { - describe('Valid values', () => { - it('Good int value', () => { - expectValid(` - { - complicatedArgs { - intArgField(intArg: 2) - } - } - `); - }); - - it('Good negative int value', () => { - expectValid(` - { - complicatedArgs { - intArgField(intArg: -2) - } - } - `); - }); - - it('Good boolean value', () => { - expectValid(` - { - complicatedArgs { - booleanArgField(booleanArg: true) - } - } - `); - }); - - it('Good string value', () => { - expectValid(` - { - complicatedArgs { - stringArgField(stringArg: "foo") - } - } - `); - }); - - it('Good float value', () => { - expectValid(` - { - complicatedArgs { - floatArgField(floatArg: 1.1) - } - } - `); - }); - - it('Good negative float value', () => { - expectValid(` - { - complicatedArgs { - floatArgField(floatArg: -1.1) - } - } - `); - }); - - it('Int into Float', () => { - expectValid(` - { - complicatedArgs { - floatArgField(floatArg: 1) - } - } - `); - }); - - it('Int into ID', () => { - expectValid(` - { - complicatedArgs { - idArgField(idArg: 1) - } - } - `); - }); - - it('String into ID', () => { - expectValid(` - { - complicatedArgs { - idArgField(idArg: "someIdString") - } - } - `); - }); - - it('Good enum value', () => { - expectValid(` - { - dog { - doesKnowCommand(dogCommand: SIT) - } - } - `); - }); - - it('Enum with undefined value', () => { - expectValid(` - { - complicatedArgs { - enumArgField(enumArg: UNKNOWN) - } - } - `); - }); - - it('Enum with null value', () => { - expectValid(` - { - complicatedArgs { - enumArgField(enumArg: NO_FUR) - } - } - `); - }); - - it('null into nullable type', () => { - expectValid(` - { - complicatedArgs { - intArgField(intArg: null) - } - } - `); - - expectValid(` - { - dog(a: null, b: null, c:{ requiredField: true, intField: null }) { - name - } - } - `); - }); - }); - - describe('Invalid String values', () => { - it('Int into String', () => { - expectErrors(` - { - complicatedArgs { - stringArgField(stringArg: 1) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: 1', - locations: [{ line: 4, column: 39 }], - }, - ]); - }); - - it('Float into String', () => { - expectErrors(` - { - complicatedArgs { - stringArgField(stringArg: 1.0) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: 1.0', - locations: [{ line: 4, column: 39 }], - }, - ]); - }); - - it('Boolean into String', () => { - expectErrors(` - { - complicatedArgs { - stringArgField(stringArg: true) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: true', - locations: [{ line: 4, column: 39 }], - }, - ]); - }); - - it('Unquoted String into String', () => { - expectErrors(` - { - complicatedArgs { - stringArgField(stringArg: BAR) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: BAR', - locations: [{ line: 4, column: 39 }], - }, - ]); - }); - }); - - describe('Invalid Int values', () => { - it('String into Int', () => { - expectErrors(` - { - complicatedArgs { - intArgField(intArg: "3") - } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: "3"', - locations: [{ line: 4, column: 33 }], - }, - ]); - }); - - it('Big Int into Int', () => { - expectErrors(` - { - complicatedArgs { - intArgField(intArg: 829384293849283498239482938) - } - } - `).to.deep.equal([ - { - message: - 'Int cannot represent non 32-bit signed integer value: 829384293849283498239482938', - locations: [{ line: 4, column: 33 }], - }, - ]); - }); - - it('Unquoted String into Int', () => { - expectErrors(` - { - complicatedArgs { - intArgField(intArg: FOO) - } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: FOO', - locations: [{ line: 4, column: 33 }], - }, - ]); - }); - - it('Simple Float into Int', () => { - expectErrors(` - { - complicatedArgs { - intArgField(intArg: 3.0) - } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: 3.0', - locations: [{ line: 4, column: 33 }], - }, - ]); - }); - - it('Float into Int', () => { - expectErrors(` - { - complicatedArgs { - intArgField(intArg: 3.333) - } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: 3.333', - locations: [{ line: 4, column: 33 }], - }, - ]); - }); - }); - - describe('Invalid Float values', () => { - it('String into Float', () => { - expectErrors(` - { - complicatedArgs { - floatArgField(floatArg: "3.333") - } - } - `).to.deep.equal([ - { - message: 'Float cannot represent non numeric value: "3.333"', - locations: [{ line: 4, column: 37 }], - }, - ]); - }); - - it('Boolean into Float', () => { - expectErrors(` - { - complicatedArgs { - floatArgField(floatArg: true) - } - } - `).to.deep.equal([ - { - message: 'Float cannot represent non numeric value: true', - locations: [{ line: 4, column: 37 }], - }, - ]); - }); - - it('Unquoted into Float', () => { - expectErrors(` - { - complicatedArgs { - floatArgField(floatArg: FOO) - } - } - `).to.deep.equal([ - { - message: 'Float cannot represent non numeric value: FOO', - locations: [{ line: 4, column: 37 }], - }, - ]); - }); - }); - - describe('Invalid Boolean value', () => { - it('Int into Boolean', () => { - expectErrors(` - { - complicatedArgs { - booleanArgField(booleanArg: 2) - } - } - `).to.deep.equal([ - { - message: 'Boolean cannot represent a non boolean value: 2', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Float into Boolean', () => { - expectErrors(` - { - complicatedArgs { - booleanArgField(booleanArg: 1.0) - } - } - `).to.deep.equal([ - { - message: 'Boolean cannot represent a non boolean value: 1.0', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('String into Boolean', () => { - expectErrors(` - { - complicatedArgs { - booleanArgField(booleanArg: "true") - } - } - `).to.deep.equal([ - { - message: 'Boolean cannot represent a non boolean value: "true"', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Unquoted into Boolean', () => { - expectErrors(` - { - complicatedArgs { - booleanArgField(booleanArg: TRUE) - } - } - `).to.deep.equal([ - { - message: 'Boolean cannot represent a non boolean value: TRUE', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - }); - - describe('Invalid ID value', () => { - it('Float into ID', () => { - expectErrors(` - { - complicatedArgs { - idArgField(idArg: 1.0) - } - } - `).to.deep.equal([ - { - message: - 'ID cannot represent a non-string and non-integer value: 1.0', - locations: [{ line: 4, column: 31 }], - }, - ]); - }); - - it('Boolean into ID', () => { - expectErrors(` - { - complicatedArgs { - idArgField(idArg: true) - } - } - `).to.deep.equal([ - { - message: - 'ID cannot represent a non-string and non-integer value: true', - locations: [{ line: 4, column: 31 }], - }, - ]); - }); - - it('Unquoted into ID', () => { - expectErrors(` - { - complicatedArgs { - idArgField(idArg: SOMETHING) - } - } - `).to.deep.equal([ - { - message: - 'ID cannot represent a non-string and non-integer value: SOMETHING', - locations: [{ line: 4, column: 31 }], - }, - ]); - }); - }); - - describe('Invalid Enum value', () => { - it('Int into Enum', () => { - expectErrors(` - { - dog { - doesKnowCommand(dogCommand: 2) - } - } - `).to.deep.equal([ - { - message: 'Enum "DogCommand" cannot represent non-enum value: 2.', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Float into Enum', () => { - expectErrors(` - { - dog { - doesKnowCommand(dogCommand: 1.0) - } - } - `).to.deep.equal([ - { - message: 'Enum "DogCommand" cannot represent non-enum value: 1.0.', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('String into Enum', () => { - expectErrors(` - { - dog { - doesKnowCommand(dogCommand: "SIT") - } - } - `).to.deep.equal([ - { - message: - 'Enum "DogCommand" cannot represent non-enum value: "SIT". Did you mean the enum value "SIT"?', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Boolean into Enum', () => { - expectErrors(` - { - dog { - doesKnowCommand(dogCommand: true) - } - } - `).to.deep.equal([ - { - message: 'Enum "DogCommand" cannot represent non-enum value: true.', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Unknown Enum Value into Enum', () => { - expectErrors(` - { - dog { - doesKnowCommand(dogCommand: JUGGLE) - } - } - `).to.deep.equal([ - { - message: 'Value "JUGGLE" does not exist in "DogCommand" enum.', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Different case Enum Value into Enum', () => { - expectErrors(` - { - dog { - doesKnowCommand(dogCommand: sit) - } - } - `).to.deep.equal([ - { - message: - 'Value "sit" does not exist in "DogCommand" enum. Did you mean the enum value "SIT"?', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - }); - - describe('Valid List value', () => { - it('Good list value', () => { - expectValid(` - { - complicatedArgs { - stringListArgField(stringListArg: ["one", null, "two"]) - } - } - `); - }); - - it('Empty list value', () => { - expectValid(` - { - complicatedArgs { - stringListArgField(stringListArg: []) - } - } - `); - }); - - it('Null value', () => { - expectValid(` - { - complicatedArgs { - stringListArgField(stringListArg: null) - } - } - `); - }); - - it('Single value into List', () => { - expectValid(` - { - complicatedArgs { - stringListArgField(stringListArg: "one") - } - } - `); - }); - }); - - describe('Invalid List value', () => { - it('Incorrect item type', () => { - expectErrors(` - { - complicatedArgs { - stringListArgField(stringListArg: ["one", 2]) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: 2', - locations: [{ line: 4, column: 55 }], - }, - ]); - }); - - it('Single value of incorrect type', () => { - expectErrors(` - { - complicatedArgs { - stringListArgField(stringListArg: 1) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: 1', - locations: [{ line: 4, column: 47 }], - }, - ]); - }); - }); - - describe('Valid non-nullable value', () => { - it('Arg on optional arg', () => { - expectValid(` - { - dog { - isHouseTrained(atOtherHomes: true) - } - } - `); - }); - - it('No Arg on optional arg', () => { - expectValid(` - { - dog { - isHouseTrained - } - } - `); - }); - - it('Multiple args', () => { - expectValid(` - { - complicatedArgs { - multipleReqs(req1: 1, req2: 2) - } - } - `); - }); - - it('Multiple args reverse order', () => { - expectValid(` - { - complicatedArgs { - multipleReqs(req2: 2, req1: 1) - } - } - `); - }); - - it('No args on multiple optional', () => { - expectValid(` - { - complicatedArgs { - multipleOpts - } - } - `); - }); - - it('One arg on multiple optional', () => { - expectValid(` - { - complicatedArgs { - multipleOpts(opt1: 1) - } - } - `); - }); - - it('Second arg on multiple optional', () => { - expectValid(` - { - complicatedArgs { - multipleOpts(opt2: 1) - } - } - `); - }); - - it('Multiple required args on mixedList', () => { - expectValid(` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4) - } - } - `); - }); - - it('Multiple required and one optional arg on mixedList', () => { - expectValid(` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5) - } - } - `); - }); - - it('All required and optional args on mixedList', () => { - expectValid(` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) - } - } - `); - }); - }); - - describe('Invalid non-nullable value', () => { - it('Incorrect value type', () => { - expectErrors(` - { - complicatedArgs { - multipleReqs(req2: "two", req1: "one") - } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: "two"', - locations: [{ line: 4, column: 32 }], - }, - { - message: 'Int cannot represent non-integer value: "one"', - locations: [{ line: 4, column: 45 }], - }, - ]); - }); - - it('Incorrect value and missing argument (ProvidedRequiredArgumentsRule)', () => { - expectErrors(` - { - complicatedArgs { - multipleReqs(req1: "one") - } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: "one"', - locations: [{ line: 4, column: 32 }], - }, - ]); - }); - - it('Null value', () => { - expectErrors(` - { - complicatedArgs { - multipleReqs(req1: null) - } - } - `).to.deep.equal([ - { - message: 'Expected value of type "Int!", found null.', - locations: [{ line: 4, column: 32 }], - }, - ]); - }); - }); - - describe('Valid input object value', () => { - it('Optional arg, despite required field in type', () => { - expectValid(` - { - complicatedArgs { - complexArgField - } - } - `); - }); - - it('Partial object, only required', () => { - expectValid(` - { - complicatedArgs { - complexArgField(complexArg: { requiredField: true }) - } - } - `); - }); - - it('Partial object, required field can be falsy', () => { - expectValid(` - { - complicatedArgs { - complexArgField(complexArg: { requiredField: false }) - } - } - `); - }); - - it('Partial object, including required', () => { - expectValid(` - { - complicatedArgs { - complexArgField(complexArg: { requiredField: true, intField: 4 }) - } - } - `); - }); - - it('Full object', () => { - expectValid(` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - intField: 4, - stringField: "foo", - booleanField: false, - stringListField: ["one", "two"] - }) - } - } - `); - }); - - it('Full object with fields in different order', () => { - expectValid(` - { - complicatedArgs { - complexArgField(complexArg: { - stringListField: ["one", "two"], - booleanField: false, - requiredField: true, - stringField: "foo", - intField: 4, - }) - } - } - `); - }); - }); - - describe('Invalid input object value', () => { - it('Partial object, missing required', () => { - expectErrors(` - { - complicatedArgs { - complexArgField(complexArg: { intField: 4 }) - } - } - `).to.deep.equal([ - { - message: - 'Field "ComplexInput.requiredField" of required type "Boolean!" was not provided.', - locations: [{ line: 4, column: 41 }], - }, - ]); - }); - - it('Partial object, invalid field type', () => { - expectErrors(` - { - complicatedArgs { - complexArgField(complexArg: { - stringListField: ["one", 2], - requiredField: true, - }) - } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: 2', - locations: [{ line: 5, column: 40 }], - }, - ]); - }); - - it('Partial object, null to non-null field', () => { - expectErrors(` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - nonNullField: null, - }) - } - } - `).to.deep.equal([ - { - message: 'Expected value of type "Boolean!", found null.', - locations: [{ line: 6, column: 29 }], - }, - ]); - }); - - it('Partial object, unknown field arg', () => { - expectErrors(` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - invalidField: "value" - }) - } - } - `).to.deep.equal([ - { - message: - 'Field "invalidField" is not defined by type "ComplexInput". Did you mean "intField"?', - locations: [{ line: 6, column: 15 }], - }, - ]); - }); - - it('reports original error for custom scalar which throws', () => { - const customScalar = new GraphQLScalarType({ - name: 'Invalid', - parseValue(value) { - throw new Error( - `Invalid scalar is always invalid: ${inspect(value)}`, - ); - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - invalidArg: { - type: GraphQLString, - args: { arg: { type: customScalar } }, - }, - }, - }), - }); - - const expectedErrors = expectErrorsWithSchema( - schema, - '{ invalidArg(arg: 123) }', - ); - - expectedErrors.to.deep.equal([ - { - message: - 'Expected value of type "Invalid", found 123; Invalid scalar is always invalid: 123', - locations: [{ line: 1, column: 19 }], - }, - ]); - - expectedErrors.to.have.nested.property( - '[0].originalError.message', - 'Invalid scalar is always invalid: 123', - ); - }); - - it('reports error for custom scalar that returns undefined', () => { - const customScalar = new GraphQLScalarType({ - name: 'CustomScalar', - parseValue() { - return undefined; - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - invalidArg: { - type: GraphQLString, - args: { arg: { type: customScalar } }, - }, - }, - }), - }); - - expectErrorsWithSchema(schema, '{ invalidArg(arg: 123) }').to.deep.equal([ - { - message: 'Expected value of type "CustomScalar", found 123.', - locations: [{ line: 1, column: 19 }], - }, - ]); - }); - - it('allows custom scalar to accept complex literals', () => { - const customScalar = new GraphQLScalarType({ name: 'Any' }); - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - anyArg: { - type: GraphQLString, - args: { arg: { type: customScalar } }, - }, - }, - }), - }); - - expectValidWithSchema( - schema, - ` - { - test1: anyArg(arg: 123) - test2: anyArg(arg: "abc") - test3: anyArg(arg: [123, "abc"]) - test4: anyArg(arg: {deep: [123, "abc"]}) - } - `, - ); - }); - }); - - describe('Directive arguments', () => { - it('with directives of valid types', () => { - expectValid(` - { - dog @include(if: true) { - name - } - human @skip(if: false) { - name - } - } - `); - }); - - it('with directive with incorrect types', () => { - expectErrors(` - { - dog @include(if: "yes") { - name @skip(if: ENUM) - } - } - `).to.deep.equal([ - { - message: 'Boolean cannot represent a non boolean value: "yes"', - locations: [{ line: 3, column: 28 }], - }, - { - message: 'Boolean cannot represent a non boolean value: ENUM', - locations: [{ line: 4, column: 28 }], - }, - ]); - }); - }); - - describe('Variable default values', () => { - it('variables with valid default values', () => { - expectValid(` - query WithDefaultValues( - $a: Int = 1, - $b: String = "ok", - $c: ComplexInput = { requiredField: true, intField: 3 } - $d: Int! = 123 - ) { - dog { name } - } - `); - }); - - it('variables with valid default null values', () => { - expectValid(` - query WithDefaultValues( - $a: Int = null, - $b: String = null, - $c: ComplexInput = { requiredField: true, intField: null } - ) { - dog { name } - } - `); - }); - - it('variables with invalid default null values', () => { - expectErrors(` - query WithDefaultValues( - $a: Int! = null, - $b: String! = null, - $c: ComplexInput = { requiredField: null, intField: null } - ) { - dog { name } - } - `).to.deep.equal([ - { - message: 'Expected value of type "Int!", found null.', - locations: [{ line: 3, column: 22 }], - }, - { - message: 'Expected value of type "String!", found null.', - locations: [{ line: 4, column: 25 }], - }, - { - message: 'Expected value of type "Boolean!", found null.', - locations: [{ line: 5, column: 47 }], - }, - ]); - }); - - it('variables with invalid default values', () => { - expectErrors(` - query InvalidDefaultValues( - $a: Int = "one", - $b: String = 4, - $c: ComplexInput = "NotVeryComplex" - ) { - dog { name } - } - `).to.deep.equal([ - { - message: 'Int cannot represent non-integer value: "one"', - locations: [{ line: 3, column: 21 }], - }, - { - message: 'String cannot represent a non string value: 4', - locations: [{ line: 4, column: 24 }], - }, - { - message: - 'Expected value of type "ComplexInput", found "NotVeryComplex".', - locations: [{ line: 5, column: 30 }], - }, - ]); - }); - - it('variables with complex invalid default values', () => { - expectErrors(` - query WithDefaultValues( - $a: ComplexInput = { requiredField: 123, intField: "abc" } - ) { - dog { name } - } - `).to.deep.equal([ - { - message: 'Boolean cannot represent a non boolean value: 123', - locations: [{ line: 3, column: 47 }], - }, - { - message: 'Int cannot represent non-integer value: "abc"', - locations: [{ line: 3, column: 62 }], - }, - ]); - }); - - it('complex variables missing required field', () => { - expectErrors(` - query MissingRequiredField($a: ComplexInput = {intField: 3}) { - dog { name } - } - `).to.deep.equal([ - { - message: - 'Field "ComplexInput.requiredField" of required type "Boolean!" was not provided.', - locations: [{ line: 2, column: 55 }], - }, - ]); - }); - - it('list variables with invalid item', () => { - expectErrors(` - query InvalidItem($a: [String] = ["one", 2]) { - dog { name } - } - `).to.deep.equal([ - { - message: 'String cannot represent a non string value: 2', - locations: [{ line: 2, column: 50 }], - }, - ]); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/VariablesAreInputTypesRule-test.js b/pkg/astvalidation/reference/__tests__/VariablesAreInputTypesRule-test.js deleted file mode 100644 index 5a19fca65..000000000 --- a/pkg/astvalidation/reference/__tests__/VariablesAreInputTypesRule-test.js +++ /dev/null @@ -1,44 +0,0 @@ -import { describe, it } from 'mocha'; - -import { VariablesAreInputTypesRule } from '../rules/VariablesAreInputTypesRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(VariablesAreInputTypesRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Variables are input types', () => { - it('input types are valid', () => { - expectValid(` - query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { - field(a: $a, b: $b, c: $c) - } - `); - }); - - it('output types are invalid', () => { - expectErrors(` - query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { - field(a: $a, b: $b, c: $c) - } - `).to.deep.equal([ - { - locations: [{ line: 2, column: 21 }], - message: 'Variable "$a" cannot be non-input type "Dog".', - }, - { - locations: [{ line: 2, column: 30 }], - message: 'Variable "$b" cannot be non-input type "[[CatOrDog!]]!".', - }, - { - locations: [{ line: 2, column: 50 }], - message: 'Variable "$c" cannot be non-input type "Pet".', - }, - ]); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/VariablesInAllowedPositionRule-test.js b/pkg/astvalidation/reference/__tests__/VariablesInAllowedPositionRule-test.js deleted file mode 100644 index 2b9ebc5c2..000000000 --- a/pkg/astvalidation/reference/__tests__/VariablesInAllowedPositionRule-test.js +++ /dev/null @@ -1,360 +0,0 @@ -import { describe, it } from 'mocha'; - -import { VariablesInAllowedPositionRule } from '../rules/VariablesInAllowedPositionRule'; - -import { expectValidationErrors } from './harness'; - -function expectErrors(queryStr: string) { - return expectValidationErrors(VariablesInAllowedPositionRule, queryStr); -} - -function expectValid(queryStr: string) { - expectErrors(queryStr).to.deep.equal([]); -} - -describe('Validate: Variables are in allowed positions', () => { - it('Boolean => Boolean', () => { - expectValid(` - query Query($booleanArg: Boolean) - { - complicatedArgs { - booleanArgField(booleanArg: $booleanArg) - } - } - `); - }); - - it('Boolean => Boolean within fragment', () => { - expectValid(` - fragment booleanArgFrag on ComplicatedArgs { - booleanArgField(booleanArg: $booleanArg) - } - query Query($booleanArg: Boolean) - { - complicatedArgs { - ...booleanArgFrag - } - } - `); - - expectValid(` - query Query($booleanArg: Boolean) - { - complicatedArgs { - ...booleanArgFrag - } - } - fragment booleanArgFrag on ComplicatedArgs { - booleanArgField(booleanArg: $booleanArg) - } - `); - }); - - it('Boolean! => Boolean', () => { - expectValid(` - query Query($nonNullBooleanArg: Boolean!) - { - complicatedArgs { - booleanArgField(booleanArg: $nonNullBooleanArg) - } - } - `); - }); - - it('Boolean! => Boolean within fragment', () => { - expectValid(` - fragment booleanArgFrag on ComplicatedArgs { - booleanArgField(booleanArg: $nonNullBooleanArg) - } - - query Query($nonNullBooleanArg: Boolean!) - { - complicatedArgs { - ...booleanArgFrag - } - } - `); - }); - - it('[String] => [String]', () => { - expectValid(` - query Query($stringListVar: [String]) - { - complicatedArgs { - stringListArgField(stringListArg: $stringListVar) - } - } - `); - }); - - it('[String!] => [String]', () => { - expectValid(` - query Query($stringListVar: [String!]) - { - complicatedArgs { - stringListArgField(stringListArg: $stringListVar) - } - } - `); - }); - - it('String => [String] in item position', () => { - expectValid(` - query Query($stringVar: String) - { - complicatedArgs { - stringListArgField(stringListArg: [$stringVar]) - } - } - `); - }); - - it('String! => [String] in item position', () => { - expectValid(` - query Query($stringVar: String!) - { - complicatedArgs { - stringListArgField(stringListArg: [$stringVar]) - } - } - `); - }); - - it('ComplexInput => ComplexInput', () => { - expectValid(` - query Query($complexVar: ComplexInput) - { - complicatedArgs { - complexArgField(complexArg: $complexVar) - } - } - `); - }); - - it('ComplexInput => ComplexInput in field position', () => { - expectValid(` - query Query($boolVar: Boolean = false) - { - complicatedArgs { - complexArgField(complexArg: {requiredArg: $boolVar}) - } - } - `); - }); - - it('Boolean! => Boolean! in directive', () => { - expectValid(` - query Query($boolVar: Boolean!) - { - dog @include(if: $boolVar) - } - `); - }); - - it('Int => Int!', () => { - expectErrors(` - query Query($intArg: Int) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - } - `).to.deep.equal([ - { - message: - 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', - locations: [ - { line: 2, column: 19 }, - { line: 4, column: 45 }, - ], - }, - ]); - }); - - it('Int => Int! within fragment', () => { - expectErrors(` - fragment nonNullIntArgFieldFrag on ComplicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - - query Query($intArg: Int) { - complicatedArgs { - ...nonNullIntArgFieldFrag - } - } - `).to.deep.equal([ - { - message: - 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', - locations: [ - { line: 6, column: 19 }, - { line: 3, column: 43 }, - ], - }, - ]); - }); - - it('Int => Int! within nested fragment', () => { - expectErrors(` - fragment outerFrag on ComplicatedArgs { - ...nonNullIntArgFieldFrag - } - - fragment nonNullIntArgFieldFrag on ComplicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - - query Query($intArg: Int) { - complicatedArgs { - ...outerFrag - } - } - `).to.deep.equal([ - { - message: - 'Variable "$intArg" of type "Int" used in position expecting type "Int!".', - locations: [ - { line: 10, column: 19 }, - { line: 7, column: 43 }, - ], - }, - ]); - }); - - it('String over Boolean', () => { - expectErrors(` - query Query($stringVar: String) { - complicatedArgs { - booleanArgField(booleanArg: $stringVar) - } - } - `).to.deep.equal([ - { - message: - 'Variable "$stringVar" of type "String" used in position expecting type "Boolean".', - locations: [ - { line: 2, column: 19 }, - { line: 4, column: 39 }, - ], - }, - ]); - }); - - it('String => [String]', () => { - expectErrors(` - query Query($stringVar: String) { - complicatedArgs { - stringListArgField(stringListArg: $stringVar) - } - } - `).to.deep.equal([ - { - message: - 'Variable "$stringVar" of type "String" used in position expecting type "[String]".', - locations: [ - { line: 2, column: 19 }, - { line: 4, column: 45 }, - ], - }, - ]); - }); - - it('Boolean => Boolean! in directive', () => { - expectErrors(` - query Query($boolVar: Boolean) { - dog @include(if: $boolVar) - } - `).to.deep.equal([ - { - message: - 'Variable "$boolVar" of type "Boolean" used in position expecting type "Boolean!".', - locations: [ - { line: 2, column: 19 }, - { line: 3, column: 26 }, - ], - }, - ]); - }); - - it('String => Boolean! in directive', () => { - expectErrors(` - query Query($stringVar: String) { - dog @include(if: $stringVar) - } - `).to.deep.equal([ - { - message: - 'Variable "$stringVar" of type "String" used in position expecting type "Boolean!".', - locations: [ - { line: 2, column: 19 }, - { line: 3, column: 26 }, - ], - }, - ]); - }); - - it('[String] => [String!]', () => { - expectErrors(` - query Query($stringListVar: [String]) - { - complicatedArgs { - stringListNonNullArgField(stringListNonNullArg: $stringListVar) - } - } - `).to.deep.equal([ - { - message: - 'Variable "$stringListVar" of type "[String]" used in position expecting type "[String!]".', - locations: [ - { line: 2, column: 19 }, - { line: 5, column: 59 }, - ], - }, - ]); - }); - - describe('Allows optional (nullable) variables with default values', () => { - it('Int => Int! fails when variable provides null default value', () => { - expectErrors(` - query Query($intVar: Int = null) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intVar) - } - } - `).to.deep.equal([ - { - message: - 'Variable "$intVar" of type "Int" used in position expecting type "Int!".', - locations: [ - { line: 2, column: 21 }, - { line: 4, column: 47 }, - ], - }, - ]); - }); - - it('Int => Int! when variable provides non-null default value', () => { - expectValid(` - query Query($intVar: Int = 1) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intVar) - } - }`); - }); - - it('Int => Int! when optional argument provides default value', () => { - expectValid(` - query Query($intVar: Int) { - complicatedArgs { - nonNullFieldWithDefault(nonNullIntArg: $intVar) - } - }`); - }); - - it('Boolean => Boolean! in directive with default value with option', () => { - expectValid(` - query Query($boolVar: Boolean = false) { - dog @include(if: $boolVar) - }`); - }); - }); -}); diff --git a/pkg/astvalidation/reference/__tests__/harness.js b/pkg/astvalidation/reference/__tests__/harness.js deleted file mode 100644 index 7d619b40b..000000000 --- a/pkg/astvalidation/reference/__tests__/harness.js +++ /dev/null @@ -1,170 +0,0 @@ -import { expect } from 'chai'; - -import { parse } from '../../language/parser'; - -import { GraphQLSchema } from '../../type/schema'; - -import { buildSchema } from '../../utilities/buildASTSchema'; - -import { validate, validateSDL } from '../validate'; -import type { ValidationRule, SDLValidationRule } from '../ValidationContext'; - -export const testSchema: GraphQLSchema = buildSchema(` - interface Being { - name(surname: Boolean): String - } - - interface Mammal { - mother: Mammal - father: Mammal - } - - interface Pet implements Being { - name(surname: Boolean): String - } - - interface Canine implements Mammal & Being { - name(surname: Boolean): String - mother: Canine - father: Canine - } - - enum DogCommand { - SIT - HEEL - DOWN - } - - type Dog implements Being & Pet & Mammal & Canine { - name(surname: Boolean): String - nickname: String - barkVolume: Int - barks: Boolean - doesKnowCommand(dogCommand: DogCommand): Boolean - isHouseTrained(atOtherHomes: Boolean = true): Boolean - isAtLocation(x: Int, y: Int): Boolean - mother: Dog - father: Dog - } - - type Cat implements Being & Pet { - name(surname: Boolean): String - nickname: String - meows: Boolean - meowsVolume: Int - furColor: FurColor - } - - union CatOrDog = Cat | Dog - - interface Intelligent { - iq: Int - } - - type Human implements Being & Intelligent { - name(surname: Boolean): String - pets: [Pet] - relatives: [Human] - iq: Int - } - - type Alien implements Being & Intelligent { - name(surname: Boolean): String - numEyes: Int - iq: Int - } - - union DogOrHuman = Dog | Human - - union HumanOrAlien = Human | Alien - - enum FurColor { - BROWN - BLACK - TAN - SPOTTED - NO_FUR - UNKNOWN - } - - input ComplexInput { - requiredField: Boolean! - nonNullField: Boolean! = false - intField: Int - stringField: String - booleanField: Boolean - stringListField: [String] - } - - type ComplicatedArgs { - # TODO List - # TODO Coercion - # TODO NotNulls - intArgField(intArg: Int): String - nonNullIntArgField(nonNullIntArg: Int!): String - stringArgField(stringArg: String): String - booleanArgField(booleanArg: Boolean): String - enumArgField(enumArg: FurColor): String - floatArgField(floatArg: Float): String - idArgField(idArg: ID): String - stringListArgField(stringListArg: [String]): String - stringListNonNullArgField(stringListNonNullArg: [String!]): String - complexArgField(complexArg: ComplexInput): String - multipleReqs(req1: Int!, req2: Int!): String - nonNullFieldWithDefault(arg: Int! = 0): String - multipleOpts(opt1: Int = 0, opt2: Int = 0): String - multipleOptAndReq(req1: Int!, req2: Int!, opt1: Int = 0, opt2: Int = 0): String - } - - type QueryRoot { - human(id: ID): Human - alien: Alien - dog: Dog - cat: Cat - pet: Pet - catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien - complicatedArgs: ComplicatedArgs - } - - schema { - query: QueryRoot - } - - directive @onQuery on QUERY - directive @onMutation on MUTATION - directive @onSubscription on SUBSCRIPTION - directive @onField on FIELD - directive @onFragmentDefinition on FRAGMENT_DEFINITION - directive @onFragmentSpread on FRAGMENT_SPREAD - directive @onInlineFragment on INLINE_FRAGMENT - directive @onVariableDefinition on VARIABLE_DEFINITION -`); - -export function expectValidationErrorsWithSchema( - schema: GraphQLSchema, - rule: ValidationRule, - queryStr: string, -): any { - const doc = parse(queryStr); - const errors = validate(schema, doc, [rule]); - return expect(errors); -} - -export function expectValidationErrors( - rule: ValidationRule, - queryStr: string, -): any { - return expectValidationErrorsWithSchema(testSchema, rule, queryStr); -} - -export function expectSDLValidationErrors( - schema: ?GraphQLSchema, - rule: SDLValidationRule, - sdlStr: string, -): any { - const doc = parse(sdlStr); - const errors = validateSDL(doc, schema, [rule]); - return expect(errors); -} \ No newline at end of file diff --git a/pkg/astvalidation/reference/__tests__/validation-test.js b/pkg/astvalidation/reference/__tests__/validation-test.js deleted file mode 100644 index 1b2d7f8bc..000000000 --- a/pkg/astvalidation/reference/__tests__/validation-test.js +++ /dev/null @@ -1,175 +0,0 @@ -import { expect } from 'chai'; -import { describe, it } from 'mocha'; - -import { GraphQLError } from '../../error/GraphQLError'; - -import { parse } from '../../language/parser'; - -import { TypeInfo } from '../../utilities/TypeInfo'; -import { buildSchema } from '../../utilities/buildASTSchema'; - -import type { ValidationContext } from '../ValidationContext'; -import { validate } from '../validate'; - -import { testSchema } from './harness'; - -describe('Validate: Supports full validation', () => { - it('rejects invalid documents', () => { - // $FlowExpectedError[incompatible-call] - expect(() => validate(testSchema, null)).to.throw('Must provide document.'); - }); - - it('validates queries', () => { - const doc = parse(` - query { - catOrDog { - ... on Cat { - furColor - } - ... on Dog { - isHouseTrained - } - } - } - `); - - const errors = validate(testSchema, doc); - expect(errors).to.deep.equal([]); - }); - - it('detects unknown fields', () => { - const doc = parse(` - { - unknown - } - `); - - const errors = validate(testSchema, doc); - expect(errors).to.deep.equal([ - { - locations: [{ line: 3, column: 9 }], - message: 'Cannot query field "unknown" on type "QueryRoot".', - }, - ]); - }); - - it('Deprecated: validates using a custom TypeInfo', () => { - // This TypeInfo will never return a valid field. - const typeInfo = new TypeInfo(testSchema, null, () => null); - - const doc = parse(` - query { - catOrDog { - ... on Cat { - furColor - } - ... on Dog { - isHouseTrained - } - } - } - `); - - const errors = validate(testSchema, doc, undefined, undefined, typeInfo); - const errorMessages = errors.map((err) => err.message); - - expect(errorMessages).to.deep.equal([ - 'Cannot query field "catOrDog" on type "QueryRoot". Did you mean "catOrDog"?', - 'Cannot query field "furColor" on type "Cat". Did you mean "furColor"?', - 'Cannot query field "isHouseTrained" on type "Dog". Did you mean "isHouseTrained"?', - ]); - }); - - it('validates using a custom rule', () => { - const schema = buildSchema(` - directive @custom(arg: String) on FIELD - - type Query { - foo: String - } - `); - - const doc = parse(` - query { - name @custom - } - `); - - function customRule(context: ValidationContext) { - return { - Directive(node) { - const directiveDef = context.getDirective(); - const error = new GraphQLError( - 'Reporting directive: ' + String(directiveDef), - node, - ); - context.reportError(error); - }, - }; - } - - const errors = validate(schema, doc, [customRule]); - expect(errors).to.deep.equal([ - { - message: 'Reporting directive: @custom', - locations: [{ line: 3, column: 14 }], - }, - ]); - }); -}); - -describe('Validate: Limit maximum number of validation errors', () => { - const query = ` - { - firstUnknownField - secondUnknownField - thirdUnknownField - } - `; - const doc = parse(query, { noLocation: true }); - - function validateDocument(options: {| maxErrors?: number |}) { - return validate(testSchema, doc, undefined, options); - } - - function invalidFieldError(fieldName: string) { - return { - message: `Cannot query field "${fieldName}" on type "QueryRoot".`, - locations: [], - }; - } - - it('when maxErrors is equal to number of errors', () => { - const errors = validateDocument({ maxErrors: 3 }); - expect(errors).to.be.deep.equal([ - invalidFieldError('firstUnknownField'), - invalidFieldError('secondUnknownField'), - invalidFieldError('thirdUnknownField'), - ]); - }); - - it('when maxErrors is less than number of errors', () => { - const errors = validateDocument({ maxErrors: 2 }); - expect(errors).to.be.deep.equal([ - invalidFieldError('firstUnknownField'), - invalidFieldError('secondUnknownField'), - { - message: - 'Too many validation errors, error limit reached. Validation aborted.', - }, - ]); - }); - - it('passthrough exceptions from rules', () => { - function customRule() { - return { - Field() { - throw new Error('Error from custom rule!'); - }, - }; - } - expect(() => - validate(testSchema, doc, [customRule], { maxErrors: 1 }), - ).to.throw(/^Error from custom rule!$/); - }); -}); diff --git a/pkg/astvalidation/reference/gen.sh b/pkg/astvalidation/reference/gen.sh deleted file mode 100755 index ee2193c93..000000000 --- a/pkg/astvalidation/reference/gen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -cd testsgo -rm -f *Rule_test.go -cd .. - -go run main.go -gofmt -w testsgo diff --git a/pkg/astvalidation/reference/main.go b/pkg/astvalidation/reference/main.go deleted file mode 100644 index e561c0fda..000000000 --- a/pkg/astvalidation/reference/main.go +++ /dev/null @@ -1,462 +0,0 @@ -package main - -import ( - "fmt" - "log" - "os" - "path/filepath" - "regexp" - "strings" - - "gopkg.in/yaml.v2" -) - -//go:generate ./gen.sh - -func main() { - currDir, _ := os.Getwd() - println(currDir) - - workingDir := inputDir - if !strings.Contains(currDir, "reference") { - workingDir = filepath.Join(currDir, "pkg/astvalidation/reference/__tests__") - } - - dir, err := os.ReadDir(workingDir) - if err != nil { - log.Fatal(err) - } - - replacementsPath := workingDir + "/../replacements.yml" - replacementContent, _ := os.ReadFile(replacementsPath) - - var replacements []Replacement - if err := yaml.Unmarshal(replacementContent, &replacements); err != nil { - log.Fatal(err) - } - - for _, fileInfo := range dir { - processFile(workingDir, fileInfo.Name(), replacements) - } -} - -const ( - inputDir = "./__tests__" - outDir = "./testsgo" - - header = ` -package testsgo - -import ( - "testing" -) -` -) - -var ( - // jsArrowFunction - represents a function passed to mocha describe and it - jsArrowFunction = ", () => {" - - // convertRules - list of reference rules which should be converted - convertRules = []string{ - "ExecutableDefinitionsRule", - "FieldsOnCorrectTypeRule", - "FragmentsOnCompositeTypesRule", - "KnownArgumentNamesRule", - "KnownDirectivesRule", - "KnownFragmentNamesRule", - "KnownTypeNamesRule", - "LoneAnonymousOperationRule", - "LoneSchemaDefinitionRule", - "NoFragmentCyclesRule", - "NoUndefinedVariablesRule", - "NoUnusedFragmentsRule", - "NoUnusedVariablesRule", - "OverlappingFieldsCanBeMergedRule", - "PossibleFragmentSpreadsRule", - "PossibleTypeExtensionsRule", - "ProvidedRequiredArgumentsRule", - "ScalarLeafsRule", - "SingleFieldSubscriptionsRule", - "UniqueArgumentNamesRule", - "UniqueDirectiveNamesRule", - "UniqueDirectivesPerLocationRule", - "UniqueEnumValueNamesRule", - "UniqueFieldDefinitionNamesRule", - "UniqueFragmentNamesRule", - "UniqueInputFieldNamesRule", - "UniqueOperationNamesRule", - "UniqueOperationTypesRule", - "UniqueTypeNamesRule", - "UniqueVariableNamesRule", - "ValuesOfCorrectTypeRule", - "VariablesAreInputTypesRule", - "VariablesInAllowedPositionRule", - // "validation", // should be rewritten manually - // "NoDeprecatedCustomRule", // should be ignored we have no custom rules - // "NoSchemaIntrospectionCustomRule", // should be ignored we have no custom rules - } -) - -// skipRule - determine do we have to convert particular rule e.g. test file from reference tests -func skipRule(name string) bool { - for _, rule := range convertRules { - if rule == name { - return false - } - } - return true -} - -// processFile - convert and save reference test file -func processFile(workingDir string, filename string, replacements Replacements) { - fPath := filepath.Join(workingDir, filename) - fileContent, _ := os.ReadFile(fPath) - - testName := strings.TrimSuffix(strings.Split(filepath.Base(filename), ".")[0], "-test") - - if skipRule(testName) { - return - } - - content := string(fileContent) - for _, replacement := range replacements.ReplaceForRule(testName) { - content = replacement.Do(content) - } - - converter := &Converter{} - result := converter.iterateLines(testName, content) - - outFileName := testName + "_test.go" - err := os.WriteFile(filepath.Join(outDir, outFileName), []byte(result), os.ModePerm) - if err != nil { - log.Fatal(err) - } -} - -// Converter - is a line by line js-to-go converter of a reference test file -// global replacements should be done before running Converter -type Converter struct { - insideImport bool - insideMultilineString bool - insideResultAssertion bool - lineNumber int -} - -// iterateLines - iterates over js file content line by line and wraps a content into go test function -func (c *Converter) iterateLines(testName string, content string) string { - var outLines []string - - // remove semicolons from content - content = strings.ReplaceAll(content, ";", "") - // splits content into separate lines - lines := strings.Split(content, "\n") - - // appends package header - outLines = append(outLines, header) - // appends go test function wrapper - outLines = append(outLines, fmt.Sprintf("func Test%s(t *testing.T) {", testName)) - - for i, line := range lines { - c.lineNumber = i + 1 - transformedLine, skip := c.transformLine(line) - if !skip { - outLines = append(outLines, transformedLine) - } - } - - // appends go test function closing bracket - outLines = append(outLines, "}") - - // joins processed lines into resulting string - return strings.Join(outLines, "\n") -} - -// transformLine - doing required replacement for the particular js code line -// could be called recursively in some cases -// returns: -// out - a processed line -// skip - a flag to skip appending line to results -func (c *Converter) transformLine(line string) (out string, skip bool) { - // fmt.Println("#transformLine lineNumber: ", c.lineNumber, " line: ", line) - // defer func() { - // fmt.Println("#transformLine RESULT ", c.lineNumber, " skip: ", skip, " out: ", out) - // }() - - // selects a required line transformation - // NOTE: Order of transformation is matters!!! - switch { - - // handles js string wrapped into "'" which in go should be presented with "`" or `"` - case strings.Contains(line, `'`): - // when js string contains double quote - if strings.Contains(line, `"`) { - // wrap result into "`" - transformedLine := strings.ReplaceAll(line, `'`, "`") - out, skip = c.transformLine(transformedLine) - } else { - // wrap result into `"` - transformedLine := strings.ReplaceAll(line, `'`, `"`) - out, skip = c.transformLine(transformedLine) - } - - // skip js single line import - case strings.Contains(line, "import { "): - return "", true - - // skip js multi line import - case strings.Contains(line, "import {"): - c.insideImport = true - return "", true - - // skip js multi line end of import - case strings.Contains(line, "} from"): - c.insideImport = false - return "", true - - // replace js const with a go variable - case strings.Contains(line, "const "): - parts := strings.Split(line, "=") - variableName := strings.TrimPrefix(strings.TrimSpace(parts[0]), "const") - transformedLine := fmt.Sprintf("%s := %s", variableName, parts[1]) - out, skip = c.transformLine(transformedLine) - - // replace mocha "describe" with go t.Run - case strings.Contains(line, "describe("): - name := strings.TrimSuffix(strings.ReplaceAll(line, "describe(", ""), jsArrowFunction) - out = fmt.Sprintf(`t.Run(%s, func(t *testing.T) {`, name) - - // replace mocha "it" with go t.Run - case strings.Contains(line, "it("): - name := strings.TrimSuffix(strings.ReplaceAll(line, "it(", ""), jsArrowFunction) - out = fmt.Sprintf(`t.Run(%s, func(t *testing.T) {`, name) - - /* - # Start of section for processing reference test helper functions - in reference implementation each test has a wrapper of harness helpers with rule name - we do not need a rule name as it could be derived from *testing.T but we preserving rule name to not heavily modify a file - Here we replacing test helper function definitions with go function variables - */ - - // rewrite test helpers - case strings.Contains(line, "function"): - out = c.transformHelperFunctions(line) - - // rewrite calls to test helpers - case !strings.Contains(line, ":=") && regexp.MustCompile(`expect.*\(`).MatchString(line): - transformedLine := c.transformUsageOfHelperFunctions(line) - out, skip = c.transformLine(transformedLine) - - case strings.Contains(line, "buildSchema("): - transformedLine := strings.ReplaceAll(line, "buildSchema", "BuildSchema") - out, skip = c.transformLine(transformedLine) - - /* - # End of section for processing reference test helper functions - */ - - // replace chai deep equal compare for an empty errors array - case strings.Contains(line, "to.deep.equal([])"): - out = strings.ReplaceAll(line, ".to.deep.equal([])", "([]Err{})") - - // detects end of schema sdl multiline string and steps into replacing errors matcher - case strings.Contains(line, "`).to.deep.equal(["): - // set insideMultilineString to false as schema sdl multiline string finished - c.insideMultilineString = false - fallthrough - - // replace chai deep equal compare of errors with a call to ResultCompare - case strings.Contains(line, ").to.deep.equal(["): - // set insideResultAssertion as we are entering errors assertion - c.insideResultAssertion = true - out = strings.ReplaceAll(line, ".to.deep.equal([", "([]Err{") - - // replace js object field inlining with message property of Err object - case strings.Contains(line, "{ message,"): - if c.insideResultAssertion { - out = strings.ReplaceAll(line, "{ message,", `{ message: message,`) - out, skip = c.transformLine(out) - } - - // replace locations with Loc slice property - // when locations in a single line we should replace ending brackets to close slice - case strings.Contains(line, "locations: ["): - transformedLine := strings.ReplaceAll(line, "locations: [", `locations: []Loc{`) - if strings.Contains(transformedLine, "}]") { - transformedLine = strings.ReplaceAll(transformedLine, "}]", `}}`) - } - out = transformedLine - - // closes result assertion with a slice close - case strings.Contains(line, "])"): - // if we are inside a multiline string leave a line as is - if c.insideMultilineString { - out = line - } else { - // set insideResultAssertion to false as we are leaving result assertion - c.insideResultAssertion = false - out = "})" - } - - // handles closing slice when we are inside a multiline assertion - case strings.Contains(line, "],"): - switch { - case c.insideMultilineString: - out = line - case c.insideResultAssertion: - out = strings.ReplaceAll(line, "],", `},`) - } - - // handles js multiline strings - case strings.Contains(line, "`"): - if strings.Contains(line, "to.deep.equal") { - // in case string contains chai comparison proceed with a different conversion - out, skip = c.transformLine(line) - } else { - // change insideMultilineString in case we are at start or end of js multiline string - if strings.Count(line, "`") == 1 { - c.insideMultilineString = !c.insideMultilineString - } - // add line as is - out = line - } - - // replacing a rule js function name with a simple string rule name - case strings.Contains(line, "Rule,"): - // if we are inside importing of rule function just skip a line - if c.insideImport { - return "", true - } - var ruleName string - for _, s := range strings.Split(line, ",") { - if strings.Contains(s, "Rule") { - ruleName = strings.TrimSpace(s) - break - } - } - if strings.Contains(ruleName, "(") { - ruleName = strings.Split(ruleName, "(")[1] - } - out = strings.ReplaceAll(line, ruleName, ruleName) - - // do not transform a line when no conditions met - // in case we are inside an import just skip a line - default: - if c.insideImport { - return "", true - } - out = line - } - - return -} - -// transformHelperFunctions - creates helper function variables -func (c *Converter) transformHelperFunctions(line string) (out string) { - // fmt.Println("#transformHelperFunctions lineNumber: ", c.lineNumber, " line: ", line) - // defer func() { - // fmt.Println("#transformHelperFunctions lineNumber: ", c.lineNumber, " out: ", out) - // }() - - switch { - case strings.Contains(line, "function expectErrorsWithSchema"): - out = "ExpectErrorsWithSchema := func(t *testing.T, schema string, queryStr string) ResultCompare {" - - case strings.Contains(line, "function expectErrors"): - out = "ExpectErrors := func(t *testing.T, queryStr string) ResultCompare {" - - case strings.Contains(line, "function expectValidSDL"): - out = "ExpectValidSDL := func(t *testing.T, sdlStr string, schema ...string) {" - - case strings.Contains(line, "function expectValidWithSchema"): - out = "ExpectValidWithSchema := func(t *testing.T, schema string, queryStr string) {" - - case strings.Contains(line, "function expectValid"): - out = "ExpectValid := func(t *testing.T, queryStr string) {" - - } - - return -} - -// transformUsageOfHelperFunctions - adds a *testing.T as a first argument to helpers call -func (c *Converter) transformUsageOfHelperFunctions(line string) (out string) { - // fmt.Println("#transformUsageOfHelperFunctions lineNumber: ", c.lineNumber, " line: ", line) - // defer func() { - // fmt.Println("#transformUsageOfHelperFunctions lineNumber: ", c.lineNumber, " out: ", out) - // }() - - switch { - case strings.Contains(line, "expectSDLErrors("): - out = strings.ReplaceAll(line, - "expectSDLErrors(sdlStr, schema)", "ExpectSDLErrors(t, sdlStr, schema...)") - out = strings.ReplaceAll(out, - "expectSDLErrors(", "ExpectSDLErrors(t,") - - // add *testing.T arg to expectErrorMessage call - case strings.Contains(line, "expectErrorMessage("): - out = strings.ReplaceAll(line, "expectErrorMessage(", "ExpectErrorMessage(t,") - - case strings.Contains(line, "expectValidationErrorsWithSchema("): - out = strings.ReplaceAll(line, - "expectValidationErrorsWithSchema(", "ExpectValidationErrorsWithSchema(t,") - - case strings.Contains(line, "expectErrorsWithSchema("): - out = strings.ReplaceAll(line, - "expectErrorsWithSchema(", "ExpectErrorsWithSchema(t,") - - case strings.Contains(line, "expectSDLValidationErrors("): - out = strings.ReplaceAll(line, - "expectSDLValidationErrors(", "ExpectSDLValidationErrors(t,") - - case strings.Contains(line, "expectValidationErrors("): - out = strings.ReplaceAll(line, - "expectValidationErrors(", "ExpectValidationErrors(t,") - - case strings.Contains(line, "expectErrors("): - out = strings.ReplaceAll(line, - "expectErrors(", "ExpectErrors(t,") - - case strings.Contains(line, "expectValid("): - out = strings.ReplaceAll(line, - "expectValid(", "ExpectValid(t,") - - case strings.Contains(line, "expectValidSDL("): - out = strings.ReplaceAll(line, - "expectValidSDL(", "ExpectValidSDL(t,") - - case strings.Contains(line, "expectValidWithSchema("): - out = strings.ReplaceAll(line, - "expectValidWithSchema(", "ExpectValidWithSchema(t,") - } - - return -} - -// Replacement - is a type holding global replacements for a particular rule e.g. test file in references tests -type Replacement struct { - Rule string - Source string - Replacement string -} - -func (r Replacement) Do(content string) string { - if !strings.Contains(content, r.Source) { - return content - } - out := strings.ReplaceAll(content, r.Source, r.Replacement) - return out -} - -// Replacements - list of global replacements for rules -type Replacements []Replacement - -// ReplaceForRule - returns array of Replacement for particular rule -func (r Replacements) ReplaceForRule(rule string) (out []Replacement) { - for _, replacement := range r { - if replacement.Rule == "__ALL__" || replacement.Rule == rule { - out = append(out, replacement) - } - } - return -} diff --git a/pkg/astvalidation/reference/replacements.yml b/pkg/astvalidation/reference/replacements.yml deleted file mode 100644 index 1cc40ba16..000000000 --- a/pkg/astvalidation/reference/replacements.yml +++ /dev/null @@ -1,169 +0,0 @@ -- - rule: ValuesOfCorrectTypeRule - reason: we have no scalars - source: >2 - it('reports original error for custom scalar which throws', () => { - const customScalar = new GraphQLScalarType({ - name: 'Invalid', - parseValue(value) { - throw new Error( - `Invalid scalar is always invalid: ${inspect(value)}`, - ); - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - invalidArg: { - type: GraphQLString, - args: { arg: { type: customScalar } }, - }, - }, - }), - }); - - const expectedErrors = expectErrorsWithSchema( - schema, - '{ invalidArg(arg: 123) }', - ); - - expectedErrors.to.deep.equal([ - { - message: - 'Expected value of type "Invalid", found 123; Invalid scalar is always invalid: 123', - locations: [{ line: 1, column: 19 }], - }, - ]); - - expectedErrors.to.have.nested.property( - '[0].originalError.message', - 'Invalid scalar is always invalid: 123', - ); - }); - - it('reports error for custom scalar that returns undefined', () => { - const customScalar = new GraphQLScalarType({ - name: 'CustomScalar', - parseValue() { - return undefined; - }, - }); - - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - invalidArg: { - type: GraphQLString, - args: { arg: { type: customScalar } }, - }, - }, - }), - }); - - expectErrorsWithSchema(schema, '{ invalidArg(arg: 123) }').to.deep.equal([ - { - message: 'Expected value of type "CustomScalar", found 123.', - locations: [{ line: 1, column: 19 }], - }, - ]); - }); - - it('allows custom scalar to accept complex literals', () => { - const customScalar = new GraphQLScalarType({ name: 'Any' }); - const schema = new GraphQLSchema({ - query: new GraphQLObjectType({ - name: 'Query', - fields: { - anyArg: { - type: GraphQLString, - args: { arg: { type: customScalar } }, - }, - }, - }), - }); - - expectValidWithSchema( - schema, - ` - { - test1: anyArg(arg: 123) - test2: anyArg(arg: "abc") - test3: anyArg(arg: [123, "abc"]) - test4: anyArg(arg: {deep: [123, "abc"]}) - } - `, - ); - }); - replacement: -- - rule: ValuesOfCorrectTypeRule - reason: was used in custom scalars test above - source: >- - function expectValidWithSchema(schema: GraphQLSchema, queryStr: string) { - expectErrorsWithSchema(schema, queryStr).to.deep.equal([]); - } - replacement: -- - rule: ValuesOfCorrectTypeRule - reason: was used in custom scalars test above - source: >- - function expectErrorsWithSchema(schema: GraphQLSchema, queryStr: string) { - return expectValidationErrorsWithSchema( - schema, - ValuesOfCorrectTypeRule, - queryStr, - ); - } - replacement: -- - rule: FieldsOnCorrectTypeRule - reason: moved to harness helpers to be able to extract message from errors - source: >2 - function expectErrorMessage(schema: GraphQLSchema, queryStr: string) { - const errors = validate(schema, parse(queryStr), [ - FieldsOnCorrectTypeRule, - ]); - expect(errors.length).to.equal(1); - return expect(errors[0].message); - } - replacement: >- - ExpectErrorMessage := func(t *testing.T, schema string, queryStr string) MessageCompare { - return ExpectValidationErrorMessage(t, schema, queryStr) - } -- - rule: FieldsOnCorrectTypeRule - reason: related to expectErrorMessage - msg.to.equal replaced by a function call - source: .to.equal - replacement: -- - rule: UniqueDirectivesPerLocationRule - reason: replaced with harness helper - source: >- - const schemaWithDirectives = extendSchema(testSchema, parse(extensionSDL)); - replacement: - schemaWithDirectives := ExtendSchema(testSchema, extensionSDL) -- - rule: __ALL__ - reason: reference expectSDLErrors function has an optional param we need to handle a variadic schemas param - source: >- - function expectSDLErrors(sdlStr: string, schema?: GraphQLSchema) { - replacement: >- - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } -- - rule: __ALL__ - reason: - source: >- - function expectValidSDL(sdlStr: string, schema?: GraphQLSchema) { - expectSDLErrors(sdlStr, schema).to.deep.equal([]); - } - replacement: >- - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } \ No newline at end of file diff --git a/pkg/astvalidation/reference/testsgo/ExecutableDefinitionsRule_test.go b/pkg/astvalidation/reference/testsgo/ExecutableDefinitionsRule_test.go deleted file mode 100755 index a8ce98a63..000000000 --- a/pkg/astvalidation/reference/testsgo/ExecutableDefinitionsRule_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestExecutableDefinitionsRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, ExecutableDefinitionsRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Executable definitions", func(t *testing.T) { - t.Run("with only operation", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - dog { - name - } - } - `) - }) - - t.Run("with operation and fragment", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - dog { - name - ...Frag - } - } - - fragment Frag on Dog { - name - } - `) - }) - - t.Run("with type definition", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - dog { - name - } - } - - type Cow { - name: String - } - - extend type Dog { - color: String - } - `)([]Err{ - { - message: `The "Cow" definition is not executable.`, - locations: []Loc{{line: 8, column: 7}}, - }, - { - message: `The "Dog" definition is not executable.`, - locations: []Loc{{line: 12, column: 7}}, - }, - }) - }) - - t.Run("with schema definition", func(t *testing.T) { - ExpectErrors(t, ` - schema { - query: Query - } - - type Query { - test: String - } - - extend schema @directive - `)([]Err{ - { - message: "The schema definition is not executable.", - locations: []Loc{{line: 2, column: 7}}, - }, - { - message: `The "Query" definition is not executable.`, - locations: []Loc{{line: 6, column: 7}}, - }, - { - message: "The schema definition is not executable.", - locations: []Loc{{line: 10, column: 7}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/FieldsOnCorrectTypeRule_test.go b/pkg/astvalidation/reference/testsgo/FieldsOnCorrectTypeRule_test.go deleted file mode 100755 index ec562c31d..000000000 --- a/pkg/astvalidation/reference/testsgo/FieldsOnCorrectTypeRule_test.go +++ /dev/null @@ -1,382 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestFieldsOnCorrectTypeRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, FieldsOnCorrectTypeRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Fields on correct type", func(t *testing.T) { - t.Run("Object field selection", func(t *testing.T) { - ExpectValid(t, ` - fragment objectFieldSelection on Dog { - __typename - name - } - `) - }) - - t.Run("Aliased object field selection", func(t *testing.T) { - ExpectValid(t, ` - fragment aliasedObjectFieldSelection on Dog { - tn : __typename - otherName : name - } - `) - }) - - t.Run("Interface field selection", func(t *testing.T) { - ExpectValid(t, ` - fragment interfaceFieldSelection on Pet { - __typename - name - } - `) - }) - - t.Run("Aliased interface field selection", func(t *testing.T) { - ExpectValid(t, ` - fragment interfaceFieldSelection on Pet { - otherName : name - } - `) - }) - - t.Run("Lying alias selection", func(t *testing.T) { - ExpectValid(t, ` - fragment lyingAliasSelection on Dog { - name : nickname - } - `) - }) - - t.Run("Ignores fields on unknown type", func(t *testing.T) { - ExpectValid(t, ` - fragment unknownSelection on UnknownType { - unknownField - } - `) - }) - - t.Run("reports errors when type is known again", func(t *testing.T) { - ExpectErrors(t, ` - fragment typeKnownAgain on Pet { - unknown_pet_field { - ... on Cat { - unknown_cat_field - } - } - } - `)([]Err{ - { - message: `Cannot query field "unknown_pet_field" on type "Pet".`, - locations: []Loc{{line: 3, column: 9}}, - }, - { - message: `Cannot query field "unknown_cat_field" on type "Cat".`, - locations: []Loc{{line: 5, column: 13}}, - }, - }) - }) - - t.Run("Field not defined on fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment fieldNotDefined on Dog { - meowVolume - } - `)([]Err{ - { - message: `Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Ignores deeply unknown field", func(t *testing.T) { - ExpectErrors(t, ` - fragment deepFieldNotDefined on Dog { - unknown_field { - deeper_unknown_field - } - } - `)([]Err{ - { - message: `Cannot query field "unknown_field" on type "Dog".`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Sub-field not defined", func(t *testing.T) { - ExpectErrors(t, ` - fragment subFieldNotDefined on Human { - pets { - unknown_field - } - } - `)([]Err{ - { - message: `Cannot query field "unknown_field" on type "Pet".`, - locations: []Loc{{line: 4, column: 11}}, - }, - }) - }) - - t.Run("Field not defined on inline fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment fieldNotDefined on Pet { - ... on Dog { - meowVolume - } - } - `)([]Err{ - { - message: `Cannot query field "meowVolume" on type "Dog". Did you mean "barkVolume"?`, - locations: []Loc{{line: 4, column: 11}}, - }, - }) - }) - - t.Run("Aliased field target not defined", func(t *testing.T) { - ExpectErrors(t, ` - fragment aliasedFieldTargetNotDefined on Dog { - volume : mooVolume - } - `)([]Err{ - { - message: `Cannot query field "mooVolume" on type "Dog". Did you mean "barkVolume"?`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Aliased lying field target not defined", func(t *testing.T) { - ExpectErrors(t, ` - fragment aliasedLyingFieldTargetNotDefined on Dog { - barkVolume : kawVolume - } - `)([]Err{ - { - message: `Cannot query field "kawVolume" on type "Dog". Did you mean "barkVolume"?`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Not defined on interface", func(t *testing.T) { - ExpectErrors(t, ` - fragment notDefinedOnInterface on Pet { - tailLength - } - `)([]Err{ - { - message: `Cannot query field "tailLength" on type "Pet".`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Defined on implementors but not on interface", func(t *testing.T) { - ExpectErrors(t, ` - fragment definedOnImplementorsButNotInterface on Pet { - nickname - } - `)([]Err{ - { - message: `Cannot query field "nickname" on type "Pet". Did you mean to use an inline fragment on "Cat" or "Dog"?`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Meta field selection on union", func(t *testing.T) { - ExpectValid(t, ` - fragment directFieldSelectionOnUnion on CatOrDog { - __typename - } - `) - }) - - t.Run("Direct field selection on union", func(t *testing.T) { - ExpectErrors(t, ` - fragment directFieldSelectionOnUnion on CatOrDog { - directField - } - `)([]Err{ - { - message: `Cannot query field "directField" on type "CatOrDog".`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("Defined on implementors queried on union", func(t *testing.T) { - ExpectErrors(t, ` - fragment definedOnImplementorsQueriedOnUnion on CatOrDog { - name - } - `)([]Err{ - { - message: `Cannot query field "name" on type "CatOrDog". Did you mean to use an inline fragment on "Being", "Pet", "Canine", "Cat", or "Dog"?`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("valid field in inline fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment objectFieldSelection on Pet { - ... on Dog { - name - } - ... { - name - } - } - `) - }) - - t.Run("Fields on correct type error message", func(t *testing.T) { - ExpectErrorMessage := func(t *testing.T, schema string, queryStr string) MessageCompare { - return ExpectValidationErrorMessage(t, schema, queryStr) - } - t.Run("Works with no suggestions", func(t *testing.T) { - schema := BuildSchema(` - type T { - fieldWithVeryLongNameThatWillNeverBeSuggested: String - } - type Query { t: T } - `) - - ExpectErrorMessage(t, schema, "{ t { f } }")( - `Cannot query field "f" on type "T".`, - ) - }) - - t.Run("Works with no small numbers of type suggestions", func(t *testing.T) { - schema := BuildSchema(` - union T = A | B - type Query { t: T } - - type A { f: String } - type B { f: String } - `) - - ExpectErrorMessage(t, schema, "{ t { f } }")( - `Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A" or "B"?`, - ) - }) - - t.Run("Works with no small numbers of field suggestions", func(t *testing.T) { - schema := BuildSchema(` - type T { - y: String - z: String - } - type Query { t: T } - `) - - ExpectErrorMessage(t, schema, "{ t { f } }")( - `Cannot query field "f" on type "T". Did you mean "y" or "z"?`, - ) - }) - - t.Run("Only shows one set of suggestions at a time, preferring types", func(t *testing.T) { - schema := BuildSchema(` - interface T { - y: String - z: String - } - type Query { t: T } - - type A implements T { - f: String - y: String - z: String - } - type B implements T { - f: String - y: String - z: String - } - `) - - ExpectErrorMessage(t, schema, "{ t { f } }")( - `Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A" or "B"?`, - ) - }) - - t.Run("Sort type suggestions based on inheritance order", func(t *testing.T) { - schema := BuildSchema(` - interface T { bar: String } - type Query { t: T } - - interface Z implements T { - foo: String - bar: String - } - - interface Y implements Z & T { - foo: String - bar: String - } - - type X implements Y & Z & T { - foo: String - bar: String - } - `) - - ExpectErrorMessage(t, schema, "{ t { foo } }")( - `Cannot query field "foo" on type "T". Did you mean to use an inline fragment on "Z", "Y", or "X"?`, - ) - }) - - t.Run("Limits lots of type suggestions", func(t *testing.T) { - schema := BuildSchema(` - union T = A | B | C | D | E | F - type Query { t: T } - - type A { f: String } - type B { f: String } - type C { f: String } - type D { f: String } - type E { f: String } - type F { f: String } - `) - - ExpectErrorMessage(t, schema, "{ t { f } }")( - `Cannot query field "f" on type "T". Did you mean to use an inline fragment on "A", "B", "C", "D", or "E"?`, - ) - }) - - t.Run("Limits lots of field suggestions", func(t *testing.T) { - schema := BuildSchema(` - type T { - u: String - v: String - w: String - x: String - y: String - z: String - } - type Query { t: T } - `) - - ExpectErrorMessage(t, schema, "{ t { f } }")( - `Cannot query field "f" on type "T". Did you mean "u", "v", "w", "x", or "y"?`, - ) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/FragmentsOnCompositeTypesRule_test.go b/pkg/astvalidation/reference/testsgo/FragmentsOnCompositeTypesRule_test.go deleted file mode 100755 index c525ba56d..000000000 --- a/pkg/astvalidation/reference/testsgo/FragmentsOnCompositeTypesRule_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestFragmentsOnCompositeTypesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, FragmentsOnCompositeTypesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Fragments on composite types", func(t *testing.T) { - t.Run("object is valid fragment type", func(t *testing.T) { - ExpectValid(t, ` - fragment validFragment on Dog { - barks - } - `) - }) - - t.Run("interface is valid fragment type", func(t *testing.T) { - ExpectValid(t, ` - fragment validFragment on Pet { - name - } - `) - }) - - t.Run("object is valid inline fragment type", func(t *testing.T) { - ExpectValid(t, ` - fragment validFragment on Pet { - ... on Dog { - barks - } - } - `) - }) - - t.Run("interface is valid inline fragment type", func(t *testing.T) { - ExpectValid(t, ` - fragment validFragment on Mammal { - ... on Canine { - name - } - } - `) - }) - - t.Run("inline fragment without type is valid", func(t *testing.T) { - ExpectValid(t, ` - fragment validFragment on Pet { - ... { - name - } - } - `) - }) - - t.Run("union is valid fragment type", func(t *testing.T) { - ExpectValid(t, ` - fragment validFragment on CatOrDog { - __typename - } - `) - }) - - t.Run("scalar is invalid fragment type", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarFragment on Boolean { - bad - } - `)([]Err{ - { - message: `Fragment "scalarFragment" cannot condition on non composite type "Boolean".`, - locations: []Loc{{line: 2, column: 34}}, - }, - }) - }) - - t.Run("enum is invalid fragment type", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarFragment on FurColor { - bad - } - `)([]Err{ - { - message: `Fragment "scalarFragment" cannot condition on non composite type "FurColor".`, - locations: []Loc{{line: 2, column: 34}}, - }, - }) - }) - - t.Run("input object is invalid fragment type", func(t *testing.T) { - ExpectErrors(t, ` - fragment inputFragment on ComplexInput { - stringField - } - `)([]Err{ - { - message: `Fragment "inputFragment" cannot condition on non composite type "ComplexInput".`, - locations: []Loc{{line: 2, column: 33}}, - }, - }) - }) - - t.Run("scalar is invalid inline fragment type", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidFragment on Pet { - ... on String { - barks - } - } - `)([]Err{ - { - message: `Fragment cannot condition on non composite type "String".`, - locations: []Loc{{line: 3, column: 16}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/KnownArgumentNamesRule_test.go b/pkg/astvalidation/reference/testsgo/KnownArgumentNamesRule_test.go deleted file mode 100755 index d3421c873..000000000 --- a/pkg/astvalidation/reference/testsgo/KnownArgumentNamesRule_test.go +++ /dev/null @@ -1,358 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestKnownArgumentNamesRule(t *testing.T) { - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, KnownArgumentNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, - schema, - KnownArgumentNamesOnDirectivesRule, - sdlStr, - ) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schema ...string) { - ExpectSDLErrors(t, sdlStr)([]Err{}) - } - - t.Run("Validate: Known argument names", func(t *testing.T) { - t.Run("single arg is known", func(t *testing.T) { - ExpectValid(t, ` - fragment argOnRequiredArg on Dog { - doesKnowCommand(dogCommand: SIT) - } - `) - }) - - t.Run("multiple args are known", func(t *testing.T) { - ExpectValid(t, ` - fragment multipleArgs on ComplicatedArgs { - multipleReqs(req1: 1, req2: 2) - } - `) - }) - - t.Run("ignores args of unknown fields", func(t *testing.T) { - ExpectValid(t, ` - fragment argOnUnknownField on Dog { - unknownField(unknownArg: SIT) - } - `) - }) - - t.Run("multiple args in reverse order are known", func(t *testing.T) { - ExpectValid(t, ` - fragment multipleArgsReverseOrder on ComplicatedArgs { - multipleReqs(req2: 2, req1: 1) - } - `) - }) - - t.Run("no args on optional arg", func(t *testing.T) { - ExpectValid(t, ` - fragment noArgOnOptionalArg on Dog { - isHouseTrained - } - `) - }) - - t.Run("args are known deeply", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - doesKnowCommand(dogCommand: SIT) - } - human { - pets { # we are using pets instead of pet: to not fail in visitor with unknown field name on a type - ... on Dog { - doesKnowCommand(dogCommand: SIT) - } - } - } - } - `) - }) - - t.Run("directive args are known", func(t *testing.T) { - ExpectValid(t, ` - { - dog @skip(if: true) - } - `) - }) - - t.Run("field args are invalid", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @skip(unless: true) - } - `)([]Err{ - { - message: `Unknown argument "unless" on directive "@skip".`, - locations: []Loc{{line: 3, column: 19}}, - }, - }) - }) - - t.Run("directive without args is valid", func(t *testing.T) { - ExpectValid(t, ` - { - dog @onField - } - `) - }) - - t.Run("arg passed to directive without arg is reported", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @onField(if: true) - } - `)([]Err{ - { - message: `Unknown argument "if" on directive "@onField".`, - locations: []Loc{{line: 3, column: 22}}, - }, - }) - }) - - t.Run("misspelled directive args are reported", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @skip(iff: true) - } - `)([]Err{ - { - message: `Unknown argument "iff" on directive "@skip".`, - locations: []Loc{{line: 3, column: 19}}, - }, - }) - }) - - t.Run("misspelled directive args are reported with suggestions", func(t *testing.T) { - t.Skip(NotSupportedSuggestionsSkipMsg) - - ExpectErrors(t, ` - { - dog @skip(iff: true) - } - `)([]Err{ - { - message: `Unknown argument "iff" on directive "@skip". Did you mean "if"?`, - locations: []Loc{{line: 3, column: 19}}, - }, - }) - }) - - t.Run("invalid arg name", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidArgName on Dog { - doesKnowCommand(unknown: true) - } - `)([]Err{ - { - message: `Unknown argument "unknown" on field "Dog.doesKnowCommand".`, - locations: []Loc{{line: 3, column: 25}}, - }, - }) - }) - - t.Run("misspelled arg name is reported", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidArgName on Dog { - doesKnowCommand(DogCommand: true) - } - `)([]Err{ - { - message: `Unknown argument "DogCommand" on field "Dog.doesKnowCommand".`, - locations: []Loc{{line: 3, column: 25}}, - }, - }) - }) - - t.Run("misspelled arg name is reported with suggestions", func(t *testing.T) { - t.Skip(NotSupportedSuggestionsSkipMsg) - - ExpectErrors(t, ` - fragment invalidArgName on Dog { - doesKnowCommand(DogCommand: true) - } - `)([]Err{ - { - message: `Unknown argument "DogCommand" on field "Dog.doesKnowCommand". Did you mean "dogCommand"?`, - locations: []Loc{{line: 3, column: 25}}, - }, - }) - }) - - t.Run("unknown args amongst known args", func(t *testing.T) { - ExpectErrors(t, ` - fragment oneGoodArgOneInvalidArg on Dog { - doesKnowCommand(whoKnows: 1, dogCommand: SIT, unknown: true) - } - `)([]Err{ - { - message: `Unknown argument "whoKnows" on field "Dog.doesKnowCommand".`, - locations: []Loc{{line: 3, column: 25}}, - }, - { - message: `Unknown argument "unknown" on field "Dog.doesKnowCommand".`, - locations: []Loc{{line: 3, column: 55}}, - }, - }) - }) - - t.Run("unknown args deeply", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(unknown: true) - } - human { - pets { # we are using pets instead of pet: to not fail in visitor with unknown field name on a type - ... on Dog { - doesKnowCommand(unknown: true) - } - } - } - } - `)([]Err{ - { - message: `Unknown argument "unknown" on field "Dog.doesKnowCommand".`, - locations: []Loc{{line: 4, column: 27}}, - }, - { - message: `Unknown argument "unknown" on field "Dog.doesKnowCommand".`, - locations: []Loc{{line: 9, column: 31}}, - }, - }) - }) - - t.Run("within SDL", func(t *testing.T) { - t.Skip("Definition directive args validation is not supported yet") - - t.Run("known arg on directive defined inside SDL", func(t *testing.T) { - ExpectValidSDL(t, ` - type Query { - foo: String @test(arg: "") - } - - directive @test(arg: String) on FIELD_DEFINITION - `) - }) - - t.Run("unknown arg on directive defined inside SDL", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @test(unknown: "") - } - - directive @test(arg: String) on FIELD_DEFINITION - `)([]Err{ - { - message: `Unknown argument "unknown" on directive "@test".`, - locations: []Loc{{line: 3, column: 29}}, - }, - }) - }) - - t.Run("misspelled arg name is reported on directive defined inside SDL", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @test(agr: "") - } - - directive @test(arg: String) on FIELD_DEFINITION - `)([]Err{ - { - message: `Unknown argument "agr" on directive "@test". Did you mean "arg"?`, - locations: []Loc{{line: 3, column: 29}}, - }, - }) - }) - - t.Run("unknown arg on standard directive", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @deprecated(unknown: "") - } - `)([]Err{ - { - message: `Unknown argument "unknown" on directive "@deprecated".`, - locations: []Loc{{line: 3, column: 35}}, - }, - }) - }) - - t.Run("unknown arg on overridden standard directive", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @deprecated(reason: "") - } - directive @deprecated(arg: String) on FIELD - `)([]Err{ - { - message: `Unknown argument "reason" on directive "@deprecated".`, - locations: []Loc{{line: 3, column: 35}}, - }, - }) - }) - - t.Run("unknown arg on directive defined in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Query { - foo: String - } - `) - ExpectSDLErrors(t, - ` - directive @test(arg: String) on OBJECT - - extend type Query @test(unknown: "") - `, - schema, - )([]Err{ - { - message: `Unknown argument "unknown" on directive "@test".`, - locations: []Loc{{line: 4, column: 36}}, - }, - }) - }) - - t.Run("unknown arg on directive used in schema extension", func(t *testing.T) { - schema := BuildSchema(` - directive @test(arg: String) on OBJECT - - type Query { - foo: String - } - `) - ExpectSDLErrors(t, - ` - extend type Query @test(unknown: "") - `, - schema, - )([]Err{ - { - message: `Unknown argument "unknown" on directive "@test".`, - locations: []Loc{{line: 2, column: 35}}, - }, - }) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/KnownDirectivesRule_test.go b/pkg/astvalidation/reference/testsgo/KnownDirectivesRule_test.go deleted file mode 100755 index 51bb3f669..000000000 --- a/pkg/astvalidation/reference/testsgo/KnownDirectivesRule_test.go +++ /dev/null @@ -1,413 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestKnownDirectivesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, KnownDirectivesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, KnownDirectivesRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - schemaWithSDLDirectives := BuildSchema(` - directive @onSchema on SCHEMA - directive @onScalar on SCALAR - directive @onObject on OBJECT - directive @onFieldDefinition on FIELD_DEFINITION - directive @onArgumentDefinition on ARGUMENT_DEFINITION - directive @onInterface on INTERFACE - directive @onUnion on UNION - directive @onEnum on ENUM - directive @onEnumValue on ENUM_VALUE - directive @onInputObject on INPUT_OBJECT - directive @onInputFieldDefinition on INPUT_FIELD_DEFINITION -`) - - t.Run("Validate: Known directives", func(t *testing.T) { - t.Run("with no directives", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - name - ...Frag - } - - fragment Frag on Dog { - name - } - `) - }) - - t.Run("with known directives", func(t *testing.T) { - ExpectValid(t, ` - { - dog @include(if: true) { - name - } - human @skip(if: false) { - name - } - } - `) - }) - - t.Run("with unknown directive", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @unknown(directive: "value") { - name - } - } - `)([]Err{ - { - message: `Unknown directive "@unknown".`, - locations: []Loc{{line: 3, column: 13}}, - }, - }) - }) - - t.Run("with many unknown directives", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @unknown(directive: "value") { - name - } - human @unknown(directive: "value") { - name - pets @unknown(directive: "value") { - name - } - } - } - `)([]Err{ - { - message: `Unknown directive "@unknown".`, - locations: []Loc{{line: 3, column: 13}}, - }, - { - message: `Unknown directive "@unknown".`, - locations: []Loc{{line: 6, column: 15}}, - }, - { - message: `Unknown directive "@unknown".`, - locations: []Loc{{line: 8, column: 16}}, - }, - }) - }) - - t.Run("with well placed directives", func(t *testing.T) { - ExpectValid(t, ` - query ($var: Boolean) @onQuery { - name @include(if: $var) - ...Frag @include(if: true) - skippedField @skip(if: true) - ...SkippedFrag @skip(if: true) - - ... @skip(if: true) { - skippedField - } - } - - mutation @onMutation { - someField - } - - subscription @onSubscription { - someField - } - - fragment Frag on SomeType @onFragmentDefinition { - someField - } - `) - }) - - t.Run("with well placed variable definition directive", func(t *testing.T) { - ExpectValid(t, ` - query Foo($var: Boolean @onVariableDefinition) { - name - } - `) - }) - - t.Run("with misplaced directives", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($var: Boolean) @include(if: true) { - name @onQuery @include(if: $var) - ...Frag @onQuery - } - - mutation Bar @onQuery { - someField - } - `)([]Err{ - { - message: `Directive "@include" may not be used on QUERY.`, - locations: []Loc{{line: 2, column: 32}}, - }, - { - message: `Directive "@onQuery" may not be used on FIELD.`, - locations: []Loc{{line: 3, column: 14}}, - }, - { - message: `Directive "@onQuery" may not be used on FRAGMENT_SPREAD.`, - locations: []Loc{{line: 4, column: 17}}, - }, - { - message: `Directive "@onQuery" may not be used on MUTATION.`, - locations: []Loc{{line: 7, column: 20}}, - }, - }) - }) - - t.Run("with misplaced variable definition directive", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($var: Boolean @onField) { - name - } - `)([]Err{ - { - message: `Directive "@onField" may not be used on VARIABLE_DEFINITION.`, - locations: []Loc{{line: 2, column: 31}}, - }, - }) - }) - - t.Run("within SDL", func(t *testing.T) { - t.Skip("NOT_IMPLEMENTED: Definition directive defined rule") - - t.Run("with directive defined inside SDL", func(t *testing.T) { - t.Skip("NOT_IMPLEMENTED: Definition directive defined rule") - - ExpectValidSDL(t, ` - type Query { - foo: String @test - } - - directive @test on FIELD_DEFINITION - `) - }) - - t.Run("with standard directive", func(t *testing.T) { - ExpectValidSDL(t, ` - type Query { - foo: String @deprecated - } - `) - }) - - t.Run("with overridden standard directive", func(t *testing.T) { - ExpectValidSDL(t, ` - schema @deprecated { - query: Query - } - directive @deprecated on SCHEMA - `) - }) - - t.Run("with directive defined in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Query { - foo: String - } - `) - ExpectValidSDL(t, - ` - directive @test on OBJECT - - extend type Query @test - `, - schema, - ) - }) - - t.Run("with directive used in schema extension", func(t *testing.T) { - schema := BuildSchema(` - directive @test on OBJECT - - type Query { - foo: String - } - `) - ExpectValidSDL(t, - ` - extend type Query @test - `, - schema, - ) - }) - - t.Run("with unknown directive in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Query { - foo: String - } - `) - ExpectSDLErrors(t, - ` - extend type Query @unknown - `, - schema, - )([]Err{ - { - message: `Unknown directive "@unknown".`, - locations: []Loc{{line: 2, column: 29}}, - }, - }) - }) - - t.Run("with well placed directives", func(t *testing.T) { - ExpectValidSDL(t, - ` - type MyObj implements MyInterface @onObject { - myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition - } - - extend type MyObj @onObject - - scalar MyScalar @onScalar - - extend scalar MyScalar @onScalar - - interface MyInterface @onInterface { - myField(myArg: Int @onArgumentDefinition): String @onFieldDefinition - } - - extend interface MyInterface @onInterface - - union MyUnion @onUnion = MyObj | Other - - extend union MyUnion @onUnion - - enum MyEnum @onEnum { - MY_VALUE @onEnumValue - } - - extend enum MyEnum @onEnum - - input MyInput @onInputObject { - myField: Int @onInputFieldDefinition - } - - extend input MyInput @onInputObject - - schema @onSchema { - query: MyQuery - } - - extend schema @onSchema - `, - schemaWithSDLDirectives, - ) - }) - - t.Run("with misplaced directives", func(t *testing.T) { - ExpectSDLErrors(t, - ` - type MyObj implements MyInterface @onInterface { - myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition - } - - scalar MyScalar @onEnum - - interface MyInterface @onObject { - myField(myArg: Int @onInputFieldDefinition): String @onInputFieldDefinition - } - - union MyUnion @onEnumValue = MyObj | Other - - enum MyEnum @onScalar { - MY_VALUE @onUnion - } - - input MyInput @onEnum { - myField: Int @onArgumentDefinition - } - - schema @onObject { - query: MyQuery - } - - extend schema @onObject - `, - schemaWithSDLDirectives, - )([]Err{ - { - message: `Directive "@onInterface" may not be used on OBJECT.`, - locations: []Loc{{line: 2, column: 45}}, - }, - { - message: `Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.`, - locations: []Loc{{line: 3, column: 32}}, - }, - { - message: `Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION.`, - locations: []Loc{{line: 3, column: 65}}, - }, - { - message: `Directive "@onEnum" may not be used on SCALAR.`, - locations: []Loc{{line: 6, column: 27}}, - }, - { - message: `Directive "@onObject" may not be used on INTERFACE.`, - locations: []Loc{{line: 8, column: 33}}, - }, - { - message: `Directive "@onInputFieldDefinition" may not be used on ARGUMENT_DEFINITION.`, - locations: []Loc{{line: 9, column: 32}}, - }, - { - message: `Directive "@onInputFieldDefinition" may not be used on FIELD_DEFINITION.`, - locations: []Loc{{line: 9, column: 65}}, - }, - { - message: `Directive "@onEnumValue" may not be used on UNION.`, - locations: []Loc{{line: 12, column: 25}}, - }, - { - message: `Directive "@onScalar" may not be used on ENUM.`, - locations: []Loc{{line: 14, column: 23}}, - }, - { - message: `Directive "@onUnion" may not be used on ENUM_VALUE.`, - locations: []Loc{{line: 15, column: 22}}, - }, - { - message: `Directive "@onEnum" may not be used on INPUT_OBJECT.`, - locations: []Loc{{line: 18, column: 25}}, - }, - { - message: `Directive "@onArgumentDefinition" may not be used on INPUT_FIELD_DEFINITION.`, - locations: []Loc{{line: 19, column: 26}}, - }, - { - message: `Directive "@onObject" may not be used on SCHEMA.`, - locations: []Loc{{line: 22, column: 18}}, - }, - { - message: `Directive "@onObject" may not be used on SCHEMA.`, - locations: []Loc{{line: 26, column: 25}}, - }, - }) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/KnownFragmentNamesRule_test.go b/pkg/astvalidation/reference/testsgo/KnownFragmentNamesRule_test.go deleted file mode 100755 index fcdd72204..000000000 --- a/pkg/astvalidation/reference/testsgo/KnownFragmentNamesRule_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestKnownFragmentNamesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, KnownFragmentNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Known fragment names", func(t *testing.T) { - t.Run("known fragment names are valid", func(t *testing.T) { - ExpectValid(t, ` - { - human(id: 4) { - ...HumanFields1 - ... on Human { - ...HumanFields2 - } - ... { - name - } - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - `) - }) - - t.Run("unknown fragment names are invalid", func(t *testing.T) { - ExpectErrors(t, ` - { - human(id: 4) { - ...UnknownFragment1 - ... on Human { - ...UnknownFragment2 - } - } - } - fragment HumanFields on Human { - name - ...UnknownFragment3 - } - `)([]Err{ - { - message: `Unknown fragment "UnknownFragment1".`, - locations: []Loc{{line: 4, column: 14}}, - }, - { - message: `Unknown fragment "UnknownFragment2".`, - locations: []Loc{{line: 6, column: 16}}, - }, - { - message: `Unknown fragment "UnknownFragment3".`, - locations: []Loc{{line: 12, column: 12}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/KnownTypeNamesRule_test.go b/pkg/astvalidation/reference/testsgo/KnownTypeNamesRule_test.go deleted file mode 100755 index d891d525b..000000000 --- a/pkg/astvalidation/reference/testsgo/KnownTypeNamesRule_test.go +++ /dev/null @@ -1,390 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestKnownTypeNamesRule(t *testing.T) { - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, KnownTypeNamesOperationRule, queryStr) - } - - ExpectErrorsWithSchema := func(t *testing.T, schema string, queryStr string) ResultCompare { - return ExpectValidationErrorsWithSchema(t, schema, KnownTypeNamesOperationRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, KnownTypeNamesRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Known type names", func(t *testing.T) { - t.Run("known type names are valid", func(t *testing.T) { - ExpectValid(t, ` - query Foo( - $var: String - $required: [Int!]! - # $introspectionType: __EnumValue - disabled cause it is not valid input type - ) { - human(id: 4) { - pets { ... on Pet { name }, ... { name } } - } - } - `) - }) - - t.Run("unknown type names are invalid", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($var: JumbledUpLetters) { - human(id: 4) { - name - pets { ... on Badger { name } } - } - } - fragment PetFields on Peat { - name - } - `)([]Err{ - { - message: `Unknown type "JumbledUpLetters".`, - locations: []Loc{{line: 2, column: 23}}, - }, - { - message: `Unknown type "Badger".`, - locations: []Loc{{line: 5, column: 25}}, - }, - { - message: `Unknown type "Peat".`, - locations: []Loc{{line: 8, column: 29}}, - }, - }) - }) - - t.Run("unknown type names are invalid", func(t *testing.T) { - t.Skip("1. Suggestions is not supported. 2. Fragment cycle is reported incorrectly for PetFields fragment") - - ExpectErrors(t, ` - query Foo($var: JumbledUpLetters) { - human(id: 4) { - name - pets { ... on Badger { name } ...PetFields } - } - } - fragment PetFields on Peat { - name - } - `)([]Err{ - { - message: `Unknown type "JumbledUpLetters".`, - locations: []Loc{{line: 2, column: 23}}, - }, - { - message: `Unknown type "Badger".`, - locations: []Loc{{line: 5, column: 25}}, - }, - { - message: `Unknown type "Peat". Did you mean "Pet" or "Cat"?`, - locations: []Loc{{line: 8, column: 29}}, - }, - }) - }) - - t.Run("references to standard scalars that are missing in schema", func(t *testing.T) { - t.Skip("think fix or remove - currently harness helpers are always merging base schema with schema") - - schema := BuildSchema("type Query { foo: String }") - query := ` - query ($id: ID, $float: Float, $int: Int) { - __typename - } - ` - ExpectErrorsWithSchema(t, schema, query)([]Err{ - { - message: `Unknown type "ID".`, - locations: []Loc{{line: 2, column: 19}}, - }, - { - message: `Unknown type "Float".`, - locations: []Loc{{line: 2, column: 31}}, - }, - { - message: `Unknown type "Int".`, - locations: []Loc{{line: 2, column: 44}}, - }, - }) - }) - - t.Run("within SDL", func(t *testing.T) { - t.Skip() - - t.Run("use standard types", func(t *testing.T) { - ExpectValidSDL(t, ` - type Query { - string: String - int: Int - float: Float - boolean: Boolean - id: ID - introspectionType: __EnumValue - } - `) - }) - - t.Run("reference types defined inside the same document", func(t *testing.T) { - ExpectValidSDL(t, ` - union SomeUnion = SomeObject | AnotherObject - - type SomeObject implements SomeInterface { - someScalar(arg: SomeInputObject): SomeScalar - } - - type AnotherObject { - foo(arg: SomeInputObject): String - } - - type SomeInterface { - someScalar(arg: SomeInputObject): SomeScalar - } - - input SomeInputObject { - someScalar: SomeScalar - } - - scalar SomeScalar - - type RootQuery { - someInterface: SomeInterface - someUnion: SomeUnion - someScalar: SomeScalar - someObject: SomeObject - } - - schema { - query: RootQuery - } - `) - }) - - t.Run("unknown type references", func(t *testing.T) { - ExpectSDLErrors(t, ` - type A - type B - - type SomeObject implements C { - e(d: D): E - } - - union SomeUnion = F | G - - interface SomeInterface { - i(h: H): I - } - - input SomeInput { - j: J - } - - directive @SomeDirective(k: K) on QUERY - - schema { - query: L - mutation: M - subscription: N - } - `)([]Err{ - { - message: `Unknown type "C". Did you mean "A" or "B"?`, - locations: []Loc{{line: 5, column: 36}}, - }, - { - message: `Unknown type "D". Did you mean "A", "B", or "ID"?`, - locations: []Loc{{line: 6, column: 16}}, - }, - { - message: `Unknown type "E". Did you mean "A" or "B"?`, - locations: []Loc{{line: 6, column: 20}}, - }, - { - message: `Unknown type "F". Did you mean "A" or "B"?`, - locations: []Loc{{line: 9, column: 27}}, - }, - { - message: `Unknown type "G". Did you mean "A" or "B"?`, - locations: []Loc{{line: 9, column: 31}}, - }, - { - message: `Unknown type "H". Did you mean "A" or "B"?`, - locations: []Loc{{line: 12, column: 16}}, - }, - { - message: `Unknown type "I". Did you mean "A", "B", or "ID"?`, - locations: []Loc{{line: 12, column: 20}}, - }, - { - message: `Unknown type "J". Did you mean "A" or "B"?`, - locations: []Loc{{line: 16, column: 14}}, - }, - { - message: `Unknown type "K". Did you mean "A" or "B"?`, - locations: []Loc{{line: 19, column: 37}}, - }, - { - message: `Unknown type "L". Did you mean "A" or "B"?`, - locations: []Loc{{line: 22, column: 18}}, - }, - { - message: `Unknown type "M". Did you mean "A" or "B"?`, - locations: []Loc{{line: 23, column: 21}}, - }, - { - message: `Unknown type "N". Did you mean "A" or "B"?`, - locations: []Loc{{line: 24, column: 25}}, - }, - }) - }) - - t.Run("does not consider non-type definitions", func(t *testing.T) { - ExpectSDLErrors(t, ` - query Foo { __typename } - fragment Foo on Query { __typename } - directive @Foo on QUERY - - type Query { - foo: Foo - } - `)([]Err{ - { - message: `Unknown type "Foo".`, - locations: []Loc{{line: 7, column: 16}}, - }, - }) - }) - - t.Run("reference standard types inside extension document", func(t *testing.T) { - schema := BuildSchema("type Foo") - sdl := ` - type SomeType { - string: String - int: Int - float: Float - boolean: Boolean - id: ID - introspectionType: __EnumValue - } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("reference types inside extension document", func(t *testing.T) { - schema := BuildSchema("type Foo") - sdl := ` - type QueryRoot { - foo: Foo - bar: Bar - } - - scalar Bar - - schema { - query: QueryRoot - } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("unknown type references inside extension document", func(t *testing.T) { - schema := BuildSchema("type A") - sdl := ` - type B - - type SomeObject implements C { - e(d: D): E - } - - union SomeUnion = F | G - - interface SomeInterface { - i(h: H): I - } - - input SomeInput { - j: J - } - - directive @SomeDirective(k: K) on QUERY - - schema { - query: L - mutation: M - subscription: N - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Unknown type "C". Did you mean "A" or "B"?`, - locations: []Loc{{line: 4, column: 36}}, - }, - { - message: `Unknown type "D". Did you mean "A", "B", or "ID"?`, - locations: []Loc{{line: 5, column: 16}}, - }, - { - message: `Unknown type "E". Did you mean "A" or "B"?`, - locations: []Loc{{line: 5, column: 20}}, - }, - { - message: `Unknown type "F". Did you mean "A" or "B"?`, - locations: []Loc{{line: 8, column: 27}}, - }, - { - message: `Unknown type "G". Did you mean "A" or "B"?`, - locations: []Loc{{line: 8, column: 31}}, - }, - { - message: `Unknown type "H". Did you mean "A" or "B"?`, - locations: []Loc{{line: 11, column: 16}}, - }, - { - message: `Unknown type "I". Did you mean "A", "B", or "ID"?`, - locations: []Loc{{line: 11, column: 20}}, - }, - { - message: `Unknown type "J". Did you mean "A" or "B"?`, - locations: []Loc{{line: 15, column: 14}}, - }, - { - message: `Unknown type "K". Did you mean "A" or "B"?`, - locations: []Loc{{line: 18, column: 37}}, - }, - { - message: `Unknown type "L". Did you mean "A" or "B"?`, - locations: []Loc{{line: 21, column: 18}}, - }, - { - message: `Unknown type "M". Did you mean "A" or "B"?`, - locations: []Loc{{line: 22, column: 21}}, - }, - { - message: `Unknown type "N". Did you mean "A" or "B"?`, - locations: []Loc{{line: 23, column: 25}}, - }, - }) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/LoneAnonymousOperationRule_test.go b/pkg/astvalidation/reference/testsgo/LoneAnonymousOperationRule_test.go deleted file mode 100755 index 286da7e69..000000000 --- a/pkg/astvalidation/reference/testsgo/LoneAnonymousOperationRule_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestLoneAnonymousOperationRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, LoneAnonymousOperationRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Anonymous operation must be alone", func(t *testing.T) { - t.Run("no operations", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Type { - field - } - `) - }) - - t.Run("one anon operation", func(t *testing.T) { - ExpectValid(t, ` - { - field - } - `) - }) - - t.Run("multiple named operations", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - field - } - - query Bar { - field - } - `) - }) - - t.Run("anon operation with fragment", func(t *testing.T) { - ExpectValid(t, ` - { - ...Foo - } - fragment Foo on Type { - field - } - `) - }) - - t.Run("multiple anon operations", func(t *testing.T) { - ExpectErrors(t, ` - { - fieldA - } - { - fieldB - } - `)([]Err{ - { - message: "This anonymous operation must be the only defined operation.", - locations: []Loc{{line: 2, column: 7}}, - }, - { - message: "This anonymous operation must be the only defined operation.", - locations: []Loc{{line: 5, column: 7}}, - }, - }) - }) - - t.Run("anon operation with a mutation", func(t *testing.T) { - ExpectErrors(t, ` - { - fieldA - } - mutation Foo { - fieldB - } - `)([]Err{ - { - message: "This anonymous operation must be the only defined operation.", - locations: []Loc{{line: 2, column: 7}}, - }, - }) - }) - - t.Run("anon operation with a subscription", func(t *testing.T) { - ExpectErrors(t, ` - { - fieldA - } - subscription Foo { - fieldB - } - `)([]Err{ - { - message: "This anonymous operation must be the only defined operation.", - locations: []Loc{{line: 2, column: 7}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/LoneSchemaDefinitionRule_test.go b/pkg/astvalidation/reference/testsgo/LoneSchemaDefinitionRule_test.go deleted file mode 100755 index 8a2de3ab7..000000000 --- a/pkg/astvalidation/reference/testsgo/LoneSchemaDefinitionRule_test.go +++ /dev/null @@ -1,163 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestLoneSchemaDefinitionRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, LoneSchemaDefinitionRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Schema definition should be alone", func(t *testing.T) { - t.Run("no schema", func(t *testing.T) { - ExpectValidSDL(t, ` - type Query { - foo: String - } - `) - }) - - t.Run("one schema definition", func(t *testing.T) { - ExpectValidSDL(t, ` - schema { - query: Foo - } - - type Foo { - foo: String - } - `) - }) - - t.Run("multiple schema definitions", func(t *testing.T) { - ExpectSDLErrors(t, ` - schema { - query: Foo - } - - type Foo { - foo: String - } - - schema { - mutation: Foo - } - - schema { - subscription: Foo - } - `)([]Err{ - { - message: "Must provide only one schema definition.", - locations: []Loc{{line: 10, column: 7}}, - }, - { - message: "Must provide only one schema definition.", - locations: []Loc{{line: 14, column: 7}}, - }, - }) - }) - - t.Run("define schema in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Foo { - foo: String - } - `) - - ExpectSDLErrors(t, - ` - schema { - query: Foo - } - `, - schema, - )([]Err{}) - }) - - t.Run("redefine schema in schema extension", func(t *testing.T) { - schema := BuildSchema(` - schema { - query: Foo - } - - type Foo { - foo: String - } - `) - - ExpectSDLErrors(t, - ` - schema { - mutation: Foo - } - `, - schema, - )([]Err{ - { - message: "Cannot define a new schema within a schema extension.", - locations: []Loc{{line: 2, column: 9}}, - }, - }) - }) - - t.Run("redefine implicit schema in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Query { - fooField: Foo - } - - type Foo { - foo: String - } - `) - - ExpectSDLErrors(t, - ` - schema { - mutation: Foo - } - `, - schema, - )([]Err{ - { - message: "Cannot define a new schema within a schema extension.", - locations: []Loc{{line: 2, column: 9}}, - }, - }) - }) - - t.Run("extend schema in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Query { - fooField: Foo - } - - type Foo { - foo: String - } - `) - - ExpectValidSDL(t, - ` - extend schema { - mutation: Foo - } - `, - schema, - ) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/NoFragmentCyclesRule_test.go b/pkg/astvalidation/reference/testsgo/NoFragmentCyclesRule_test.go deleted file mode 100755 index 7f229b5a2..000000000 --- a/pkg/astvalidation/reference/testsgo/NoFragmentCyclesRule_test.go +++ /dev/null @@ -1,263 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestNoFragmentCyclesRule(t *testing.T) { - t.Skip("fails with fragment is unused - seems our rule should be splitted") - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, NoFragmentCyclesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: No circular fragment spreads", func(t *testing.T) { - - t.Run("single reference is valid", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { name } - `) - }) - - t.Run("spreading twice is not circular", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Dog { ...fragB, ...fragB } - fragment fragB on Dog { name } - `) - }) - - t.Run("spreading twice indirectly is not circular", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Dog { ...fragB, ...fragC } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { name } - `) - }) - - t.Run("double spread within abstract types", func(t *testing.T) { - ExpectValid(t, ` - fragment nameFragment on Pet { - ... on Dog { name } - ... on Cat { name } - } - - fragment spreadsInAnon on Pet { - ... on Dog { ...nameFragment } - ... on Cat { ...nameFragment } - } - `) - }) - - t.Run("does not false positive on unknown fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment nameFragment on Pet { - ...UnknownFragment - } - `) - }) - - t.Run("spreading recursively within field fails", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Human { relatives { ...fragA } }, - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself.`, - locations: []Loc{{line: 2, column: 45}}, - }, - }) - }) - - t.Run("no spreading itself directly", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Dog { ...fragA } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself.`, - locations: []Loc{{line: 2, column: 31}}, - }, - }) - }) - - t.Run("no spreading itself directly within inline fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Pet { - ... on Dog { - ...fragA - } - } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself.`, - locations: []Loc{{line: 4, column: 11}}, - }, - }) - }) - - t.Run("no spreading itself indirectly", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragA } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself via "fragB".`, - locations: []Loc{ - {line: 2, column: 31}, - {line: 3, column: 31}, - }, - }, - }) - }) - - t.Run("no spreading itself indirectly reports opposite order", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragB on Dog { ...fragA } - fragment fragA on Dog { ...fragB } - `)([]Err{ - { - message: `Cannot spread fragment "fragB" within itself via "fragA".`, - locations: []Loc{ - {line: 2, column: 31}, - {line: 3, column: 31}, - }, - }, - }) - }) - - t.Run("no spreading itself indirectly within inline fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Pet { - ... on Dog { - ...fragB - } - } - fragment fragB on Pet { - ... on Dog { - ...fragA - } - } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself via "fragB".`, - locations: []Loc{ - {line: 4, column: 11}, - {line: 9, column: 11}, - }, - }, - }) - }) - - t.Run("no spreading itself deeply", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { ...fragO } - fragment fragX on Dog { ...fragY } - fragment fragY on Dog { ...fragZ } - fragment fragZ on Dog { ...fragO } - fragment fragO on Dog { ...fragP } - fragment fragP on Dog { ...fragA, ...fragX } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself via "fragB", "fragC", "fragO", "fragP".`, - locations: []Loc{ - {line: 2, column: 31}, - {line: 3, column: 31}, - {line: 4, column: 31}, - {line: 8, column: 31}, - {line: 9, column: 31}, - }, - }, - { - message: `Cannot spread fragment "fragO" within itself via "fragP", "fragX", "fragY", "fragZ".`, - locations: []Loc{ - {line: 8, column: 31}, - {line: 9, column: 41}, - {line: 5, column: 31}, - {line: 6, column: 31}, - {line: 7, column: 31}, - }, - }, - }) - }) - - t.Run("no spreading itself deeply two paths", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Dog { ...fragB, ...fragC } - fragment fragB on Dog { ...fragA } - fragment fragC on Dog { ...fragA } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself via "fragB".`, - locations: []Loc{ - {line: 2, column: 31}, - {line: 3, column: 31}, - }, - }, - { - message: `Cannot spread fragment "fragA" within itself via "fragC".`, - locations: []Loc{ - {line: 2, column: 41}, - {line: 4, column: 31}, - }, - }, - }) - }) - - t.Run("no spreading itself deeply two paths -- alt traverse order", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Dog { ...fragC } - fragment fragB on Dog { ...fragC } - fragment fragC on Dog { ...fragA, ...fragB } - `)([]Err{ - { - message: `Cannot spread fragment "fragA" within itself via "fragC".`, - locations: []Loc{ - {line: 2, column: 31}, - {line: 4, column: 31}, - }, - }, - { - message: `Cannot spread fragment "fragC" within itself via "fragB".`, - locations: []Loc{ - {line: 4, column: 41}, - {line: 3, column: 31}, - }, - }, - }) - }) - - t.Run("no spreading itself deeply and immediately", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Dog { ...fragB } - fragment fragB on Dog { ...fragB, ...fragC } - fragment fragC on Dog { ...fragA, ...fragB } - `)([]Err{ - { - message: `Cannot spread fragment "fragB" within itself.`, - locations: []Loc{{line: 3, column: 31}}, - }, - { - message: `Cannot spread fragment "fragA" within itself via "fragB", "fragC".`, - locations: []Loc{ - {line: 2, column: 31}, - {line: 3, column: 41}, - {line: 4, column: 31}, - }, - }, - { - message: `Cannot spread fragment "fragB" within itself via "fragC".`, - locations: []Loc{ - {line: 3, column: 41}, - {line: 4, column: 41}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/NoUndefinedVariablesRule_test.go b/pkg/astvalidation/reference/testsgo/NoUndefinedVariablesRule_test.go deleted file mode 100755 index 00d0e866d..000000000 --- a/pkg/astvalidation/reference/testsgo/NoUndefinedVariablesRule_test.go +++ /dev/null @@ -1,412 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestNoUndefinedVariablesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, NoUndefinedVariablesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: No undefined variables", func(t *testing.T) { - t.Run("all variables defined", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c) - } - `) - }) - - t.Run("all variables deeply defined", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - field(a: $a) { - field(b: $b) { - field(c: $c) - } - } - } - `) - }) - - t.Run("all variables deeply in inline fragments defined", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - ... on Type { - field(a: $a) { - field(b: $b) { - ... on Type { - field(c: $c) - } - } - } - } - } - `) - }) - - t.Run("all variables in fragments deeply defined", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `) - }) - - t.Run("variable within single fragment defined in multiple operations", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String) { - ...FragA - } - query Bar($a: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - `) - }) - - t.Run("variable within fragments defined in operations", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String) { - ...FragA - } - query Bar($b: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `) - }) - - t.Run("variable within recursive fragment defined", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragA - } - } - `) - }) - - t.Run("variable not defined", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c, d: $d) - } - `)([]Err{ - { - message: `Variable "$d" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 3, column: 39}, - {line: 2, column: 7}, - }, - }, - }) - }) - - t.Run("variable not defined by un-named query", func(t *testing.T) { - ExpectErrors(t, ` - { - field(a: $a) - } - `)([]Err{ - { - message: `Variable "$a" is not defined.`, - locations: []Loc{ - {line: 3, column: 18}, - {line: 2, column: 7}, - }, - }, - }) - }) - - t.Run("multiple variables not defined", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - field(a: $a, b: $b, c: $c) - } - `)([]Err{ - { - message: `Variable "$a" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 3, column: 18}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$c" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 3, column: 32}, - {line: 2, column: 7}, - }, - }, - }) - }) - - t.Run("variable in fragment not defined by un-named query", func(t *testing.T) { - ExpectErrors(t, ` - { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - `)([]Err{ - { - message: `Variable "$a" is not defined.`, - locations: []Loc{ - {line: 6, column: 18}, - {line: 2, column: 7}, - }, - }, - }) - }) - - t.Run("variable in fragment not defined by operation", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: String, $b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `)([]Err{ - { - message: `Variable "$c" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 16, column: 18}, - {line: 2, column: 7}, - }, - }, - }) - }) - - t.Run("multiple variables in fragments not defined", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `)([]Err{ - { - message: `Variable "$a" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 6, column: 18}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$c" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 16, column: 18}, - {line: 2, column: 7}, - }, - }, - }) - }) - - t.Run("single variable in fragment not defined by multiple operations", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field(a: $a, b: $b) - } - `)([]Err{ - { - message: `Variable "$b" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 9, column: 25}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$b" is not defined by operation "Bar".`, - locations: []Loc{ - {line: 9, column: 25}, - {line: 5, column: 7}, - }, - }, - }) - }) - - t.Run("variables in fragment not defined by multiple operations", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field(a: $a, b: $b) - } - `)([]Err{ - { - message: `Variable "$a" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 9, column: 18}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$b" is not defined by operation "Bar".`, - locations: []Loc{ - {line: 9, column: 25}, - {line: 5, column: 7}, - }, - }, - }) - }) - - t.Run("variable in fragment used by other operation", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - ...FragA - } - query Bar($a: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `)([]Err{ - { - message: `Variable "$a" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 9, column: 18}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$b" is not defined by operation "Bar".`, - locations: []Loc{ - {line: 12, column: 18}, - {line: 5, column: 7}, - }, - }, - }) - }) - - t.Run("multiple undefined variables produce multiple errors", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - ...FragAB - } - query Bar($a: String) { - ...FragAB - } - fragment FragAB on Type { - field1(a: $a, b: $b) - ...FragC - field3(a: $a, b: $b) - } - fragment FragC on Type { - field2(c: $c) - } - `)([]Err{ - { - message: `Variable "$a" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 9, column: 19}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$a" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 11, column: 19}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$c" is not defined by operation "Foo".`, - locations: []Loc{ - {line: 14, column: 19}, - {line: 2, column: 7}, - }, - }, - { - message: `Variable "$b" is not defined by operation "Bar".`, - locations: []Loc{ - {line: 9, column: 26}, - {line: 5, column: 7}, - }, - }, - { - message: `Variable "$b" is not defined by operation "Bar".`, - locations: []Loc{ - {line: 11, column: 26}, - {line: 5, column: 7}, - }, - }, - { - message: `Variable "$c" is not defined by operation "Bar".`, - locations: []Loc{ - {line: 14, column: 19}, - {line: 5, column: 7}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/NoUnusedFragmentsRule_test.go b/pkg/astvalidation/reference/testsgo/NoUnusedFragmentsRule_test.go deleted file mode 100755 index 93256df0c..000000000 --- a/pkg/astvalidation/reference/testsgo/NoUnusedFragmentsRule_test.go +++ /dev/null @@ -1,168 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestNoUnusedFragmentsRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, NoUnusedFragmentsRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: No unused fragments", func(t *testing.T) { - t.Run("all fragment names are used", func(t *testing.T) { - ExpectValid(t, ` - { - human(id: 4) { - ...HumanFields1 - ... on Human { - ...HumanFields2 - } - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - `) - }) - - t.Run("all fragment names are used by multiple operations", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - `) - }) - - t.Run("contains unknown fragments", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - fragment Unused1 on Human { - name - } - fragment Unused2 on Human { - name - } - `)([]Err{ - { - message: `Fragment "Unused1" is never used.`, - locations: []Loc{{line: 22, column: 7}}, - }, - { - message: `Fragment "Unused2" is never used.`, - locations: []Loc{{line: 25, column: 7}}, - }, - }) - }) - - t.Run("contains unknown fragments with ref cycle", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - human(id: 4) { - ...HumanFields1 - } - } - query Bar { - human(id: 4) { - ...HumanFields2 - } - } - fragment HumanFields1 on Human { - name - ...HumanFields3 - } - fragment HumanFields2 on Human { - name - } - fragment HumanFields3 on Human { - name - } - fragment Unused1 on Human { - name - ...Unused2 - } - fragment Unused2 on Human { - name - ...Unused1 - } - `)([]Err{ - { - message: `Fragment "Unused1" is never used.`, - locations: []Loc{{line: 22, column: 7}}, - }, - { - message: `Fragment "Unused2" is never used.`, - locations: []Loc{{line: 26, column: 7}}, - }, - }) - }) - - t.Run("contains unknown and undef fragments", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - human(id: 4) { - ...bar - } - } - fragment foo on Human { - name - } - `)([]Err{ - { - message: `Fragment "foo" is never used.`, - locations: []Loc{{line: 7, column: 7}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/NoUnusedVariablesRule_test.go b/pkg/astvalidation/reference/testsgo/NoUnusedVariablesRule_test.go deleted file mode 100755 index 3452decdb..000000000 --- a/pkg/astvalidation/reference/testsgo/NoUnusedVariablesRule_test.go +++ /dev/null @@ -1,238 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestNoUnusedVariablesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, NoUnusedVariablesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: No unused variables", func(t *testing.T) { - t.Run("uses all variables", func(t *testing.T) { - ExpectValid(t, ` - query ($a: String, $b: String, $c: String) { - field(a: $a, b: $b, c: $c) - } - `) - }) - - t.Run("uses all variables deeply", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - field(a: $a) { - field(b: $b) { - field(c: $c) - } - } - } - `) - }) - - t.Run("uses all variables deeply in inline fragments", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - ... on Type { - field(a: $a) { - field(b: $b) { - ... on Type { - field(c: $c) - } - } - } - } - } - `) - }) - - t.Run("uses all variables in fragments", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field(c: $c) - } - `) - }) - - t.Run("variable used by fragment in multiple operations", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String) { - ...FragA - } - query Bar($b: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `) - }) - - t.Run("variable used by recursive fragment", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragA - } - } - `) - }) - - t.Run("variable not used", func(t *testing.T) { - ExpectErrors(t, ` - query ($a: String, $b: String, $c: String) { - field(a: $a, b: $b) - } - `)([]Err{ - { - message: `Variable "$c" is never used.`, - locations: []Loc{{line: 2, column: 38}}, - }, - }) - }) - - t.Run("multiple variables not used", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: String, $b: String, $c: String) { - field(b: $b) - } - `)([]Err{ - { - message: `Variable "$a" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 17}}, - }, - { - message: `Variable "$c" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 41}}, - }, - }) - }) - - t.Run("variable not used in fragments", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field - } - `)([]Err{ - { - message: `Variable "$c" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 41}}, - }, - }) - }) - - t.Run("multiple variables not used in fragments", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: String, $b: String, $c: String) { - ...FragA - } - fragment FragA on Type { - field { - ...FragB - } - } - fragment FragB on Type { - field(b: $b) { - ...FragC - } - } - fragment FragC on Type { - field - } - `)([]Err{ - { - message: `Variable "$a" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 17}}, - }, - { - message: `Variable "$c" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 41}}, - }, - }) - }) - - t.Run("variable not used by unreferenced fragment", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - ...FragA - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `)([]Err{ - { - message: `Variable "$b" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 17}}, - }, - }) - }) - - t.Run("variable not used by fragment used by other operation", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($b: String) { - ...FragA - } - query Bar($a: String) { - ...FragB - } - fragment FragA on Type { - field(a: $a) - } - fragment FragB on Type { - field(b: $b) - } - `)([]Err{ - { - message: `Variable "$b" is never used in operation "Foo".`, - locations: []Loc{{line: 2, column: 17}}, - }, - { - message: `Variable "$a" is never used in operation "Bar".`, - locations: []Loc{{line: 5, column: 17}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/OverlappingFieldsCanBeMergedRule_test.go b/pkg/astvalidation/reference/testsgo/OverlappingFieldsCanBeMergedRule_test.go deleted file mode 100755 index a9e715b14..000000000 --- a/pkg/astvalidation/reference/testsgo/OverlappingFieldsCanBeMergedRule_test.go +++ /dev/null @@ -1,1022 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestOverlappingFieldsCanBeMergedRule(t *testing.T) { - t.Skip("part of the tests works. for errors message formats differs. locations is missing") - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, OverlappingFieldsCanBeMergedRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - ExpectErrorsWithSchema := func(t *testing.T, schema string, queryStr string) ResultCompare { - return ExpectValidationErrorsWithSchema(t, - schema, - OverlappingFieldsCanBeMergedRule, - queryStr, - ) - } - - ExpectValidWithSchema := func(t *testing.T, schema string, queryStr string) { - ExpectErrorsWithSchema(t, schema, queryStr)([]Err{}) - } - - t.Run("Validate: Overlapping fields can be merged", func(t *testing.T) { - t.Run("unique fields", func(t *testing.T) { - ExpectValid(t, ` - fragment uniqueFields on Dog { - name - nickname - } - `) - }) - - t.Run("identical fields", func(t *testing.T) { - ExpectValid(t, ` - fragment mergeIdenticalFields on Dog { - name - name - } - `) - }) - - t.Run("identical fields with identical args", func(t *testing.T) { - ExpectValid(t, ` - fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: SIT) - } - `) - }) - - t.Run("identical fields with identical directives", func(t *testing.T) { - ExpectValid(t, ` - fragment mergeSameFieldsWithSameDirectives on Dog { - name @include(if: true) - name @include(if: true) - } - `) - }) - - t.Run("different args with different aliases", func(t *testing.T) { - ExpectValid(t, ` - fragment differentArgsWithDifferentAliases on Dog { - knowsSit: doesKnowCommand(dogCommand: SIT) - knowsDown: doesKnowCommand(dogCommand: DOWN) - } - `) - }) - - t.Run("different directives with different aliases", func(t *testing.T) { - ExpectValid(t, ` - fragment differentDirectivesWithDifferentAliases on Dog { - nameIfTrue: name @include(if: true) - nameIfFalse: name @include(if: false) - } - `) - }) - - t.Run("different skip/include directives accepted", func(t *testing.T) { - // Note: Differing skip/include directives don"t create an ambiguous return - // value and are acceptable in conditions where differing runtime values - // may have the same desired effect of including or skipping a field. - ExpectValid(t, ` - fragment differentDirectivesWithDifferentAliases on Dog { - name @include(if: true) - name @include(if: false) - } - `) - }) - - t.Run("Same aliases with different field targets", func(t *testing.T) { - ExpectErrors(t, ` - fragment sameAliasesWithDifferentFieldTargets on Dog { - fido: name - fido: nickname - } - `)([]Err{ - { - message: `Fields "fido" conflict because "name" and "nickname" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 9}, - }, - }, - }) - }) - - t.Run("Same aliases allowed on non-overlapping fields", func(t *testing.T) { - // This is valid since no object can be both a "Dog" and a "Cat", thus - // these fields can never overlap. - ExpectValid(t, ` - fragment sameAliasesWithDifferentFieldTargets on Pet { - ... on Dog { - name - } - ... on Cat { - name: nickname - } - } - `) - }) - - t.Run("Alias masking direct field access", func(t *testing.T) { - ExpectErrors(t, ` - fragment aliasMaskingDirectFieldAccess on Dog { - name: nickname - name - } - `)([]Err{ - { - message: `Fields "name" conflict because "nickname" and "name" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 9}, - }, - }, - }) - }) - - t.Run("different args, second adds an argument", func(t *testing.T) { - ExpectErrors(t, ` - fragment conflictingArgs on Dog { - doesKnowCommand - doesKnowCommand(dogCommand: HEEL) - } - `)([]Err{ - { - message: `Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 9}, - }, - }, - }) - }) - - t.Run("different args, second missing an argument", func(t *testing.T) { - ExpectErrors(t, ` - fragment conflictingArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand - } - `)([]Err{ - { - message: `Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 9}, - }, - }, - }) - }) - - t.Run("conflicting arg values", func(t *testing.T) { - ExpectErrors(t, ` - fragment conflictingArgs on Dog { - doesKnowCommand(dogCommand: SIT) - doesKnowCommand(dogCommand: HEEL) - } - `)([]Err{ - { - message: `Fields "doesKnowCommand" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 9}, - }, - }, - }) - }) - - t.Run("conflicting arg names", func(t *testing.T) { - ExpectErrors(t, ` - fragment conflictingArgs on Dog { - isAtLocation(x: 0) - isAtLocation(y: 0) - } - `)([]Err{ - { - message: `Fields "isAtLocation" conflict because they have differing arguments. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 9}, - }, - }, - }) - }) - - t.Run("allows different args where no conflict is possible", func(t *testing.T) { - // This is valid since no object can be both a "Dog" and a "Cat", thus - // these fields can never overlap. - ExpectValid(t, ` - fragment conflictingArgs on Pet { - ... on Dog { - name(surname: true) - } - ... on Cat { - name - } - } - `) - }) - - t.Run("encounters conflict in fragments", func(t *testing.T) { - ExpectErrors(t, ` - { - ...A - ...B - } - fragment A on Type { - x: a - } - fragment B on Type { - x: b - } - `)([]Err{ - { - message: `Fields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 7, column: 9}, - {line: 10, column: 9}, - }, - }, - }) - }) - - t.Run("reports each conflict once", func(t *testing.T) { - ExpectErrors(t, ` - { - f1 { - ...A - ...B - } - f2 { - ...B - ...A - } - f3 { - ...A - ...B - x: c - } - } - fragment A on Type { - x: a - } - fragment B on Type { - x: b - } - `)([]Err{ - { - message: `Fields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 18, column: 9}, - {line: 21, column: 9}, - }, - }, - { - message: `Fields "x" conflict because "c" and "a" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 14, column: 11}, - {line: 18, column: 9}, - }, - }, - { - message: `Fields "x" conflict because "c" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 14, column: 11}, - {line: 21, column: 9}, - }, - }, - }) - }) - - t.Run("deep conflict", func(t *testing.T) { - ExpectErrors(t, ` - { - field { - x: a - }, - field { - x: b - } - } - `)([]Err{ - { - message: `Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 11}, - {line: 6, column: 9}, - {line: 7, column: 11}, - }, - }, - }) - }) - - t.Run("deep conflict with multiple issues", func(t *testing.T) { - ExpectErrors(t, ` - { - field { - x: a - y: c - }, - field { - x: b - y: d - } - } - `)([]Err{ - { - message: `Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields and subfields "y" conflict because "c" and "d" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 11}, - {line: 5, column: 11}, - {line: 7, column: 9}, - {line: 8, column: 11}, - {line: 9, column: 11}, - }, - }, - }) - }) - - t.Run("very deep conflict", func(t *testing.T) { - ExpectErrors(t, ` - { - field { - deepField { - x: a - } - }, - field { - deepField { - x: b - } - } - } - `)([]Err{ - { - message: `Fields "field" conflict because subfields "deepField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 4, column: 11}, - {line: 5, column: 13}, - {line: 8, column: 9}, - {line: 9, column: 11}, - {line: 10, column: 13}, - }, - }, - }) - }) - - t.Run("reports deep conflict to nearest common ancestor", func(t *testing.T) { - ExpectErrors(t, ` - { - field { - deepField { - x: a - } - deepField { - x: b - } - }, - field { - deepField { - y - } - } - } - `)([]Err{ - { - message: `Fields "deepField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 4, column: 11}, - {line: 5, column: 13}, - {line: 7, column: 11}, - {line: 8, column: 13}, - }, - }, - }) - }) - - t.Run("reports deep conflict to nearest common ancestor in fragments", func(t *testing.T) { - ExpectErrors(t, ` - { - field { - ...F - } - field { - ...F - } - } - fragment F on T { - deepField { - deeperField { - x: a - } - deeperField { - x: b - } - }, - deepField { - deeperField { - y - } - } - } - `)([]Err{ - { - message: `Fields "deeperField" conflict because subfields "x" conflict because "a" and "b" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 12, column: 11}, - {line: 13, column: 13}, - {line: 15, column: 11}, - {line: 16, column: 13}, - }, - }, - }) - }) - - t.Run("reports deep conflict in nested fragments", func(t *testing.T) { - ExpectErrors(t, ` - { - field { - ...F - } - field { - ...I - } - } - fragment F on T { - x: a - ...G - } - fragment G on T { - y: c - } - fragment I on T { - y: d - ...J - } - fragment J on T { - x: b - } - `)([]Err{ - { - message: `Fields "field" conflict because subfields "x" conflict because "a" and "b" are different fields and subfields "y" conflict because "c" and "d" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 11, column: 9}, - {line: 15, column: 9}, - {line: 6, column: 9}, - {line: 22, column: 9}, - {line: 18, column: 9}, - }, - }, - }) - }) - - t.Run("ignores unknown fragments", func(t *testing.T) { - ExpectValid(t, ` - { - field - ...Unknown - ...Known - } - - fragment Known on T { - field - ...OtherUnknown - } - `) - }) - - t.Run("return types must be unambiguous", func(t *testing.T) { - schema := BuildSchema(` - interface SomeBox { - deepBox: SomeBox - unrelatedField: String - } - - type StringBox implements SomeBox { - scalar: String - deepBox: StringBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox - } - - type IntBox implements SomeBox { - scalar: Int - deepBox: IntBox - unrelatedField: String - listStringBox: [StringBox] - stringBox: StringBox - intBox: IntBox - } - - interface NonNullStringBox1 { - scalar: String! - } - - type NonNullStringBox1Impl implements SomeBox & NonNullStringBox1 { - scalar: String! - unrelatedField: String - deepBox: SomeBox - } - - interface NonNullStringBox2 { - scalar: String! - } - - type NonNullStringBox2Impl implements SomeBox & NonNullStringBox2 { - scalar: String! - unrelatedField: String - deepBox: SomeBox - } - - type Connection { - edges: [Edge] - } - - type Edge { - node: Node - } - - type Node { - id: ID - name: String - } - - type Query { - someBox: SomeBox - connection: Connection - } - `) - - t.Run("conflicting return types which potentially overlap", func(t *testing.T) { - // This is invalid since an object could potentially be both the Object - // type IntBox and the interface type NonNullStringBox1. While that - // condition does not exist in the current schema, the schema could - // expand in the future to allow this. Thus it is invalid. - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ...on IntBox { - scalar - } - ...on NonNullStringBox1 { - scalar - } - } - } - `, - )([]Err{ - { - message: `Fields "scalar" conflict because they return conflicting types "Int" and "String!". Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 17}, - {line: 8, column: 17}, - }, - }, - }) - }) - - t.Run("compatible return shapes on different return types", func(t *testing.T) { - // In this case `deepBox` returns `SomeBox` in the first usage, and - // `StringBox` in the second usage. These return types are not the same! - // however this is valid because the return *shapes* are compatible. - ExpectValidWithSchema(t, - schema, - ` - { - someBox { - ... on SomeBox { - deepBox { - unrelatedField - } - } - ... on StringBox { - deepBox { - unrelatedField - } - } - } - } - `, - ) - }) - - t.Run("disallows differing return types despite no overlap", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - scalar - } - ... on StringBox { - scalar - } - } - } - `, - )([]Err{ - { - message: `Fields "scalar" conflict because they return conflicting types "Int" and "String". Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 17}, - {line: 8, column: 17}, - }, - }, - }) - }) - - t.Run("reports correctly when a non-exclusive follows an exclusive", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - deepBox { - ...X - } - } - } - someBox { - ... on StringBox { - deepBox { - ...Y - } - } - } - memoed: someBox { - ... on IntBox { - deepBox { - ...X - } - } - } - memoed: someBox { - ... on StringBox { - deepBox { - ...Y - } - } - } - other: someBox { - ...X - } - other: someBox { - ...Y - } - } - fragment X on SomeBox { - scalar - } - fragment Y on SomeBox { - scalar: unrelatedField - } - `, - )([]Err{ - { - message: `Fields "other" conflict because subfields "scalar" conflict because "scalar" and "unrelatedField" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 31, column: 13}, - {line: 39, column: 13}, - {line: 34, column: 13}, - {line: 42, column: 13}, - }, - }, - }) - }) - - t.Run("disallows differing return type nullability despite no overlap", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on NonNullStringBox1 { - scalar - } - ... on StringBox { - scalar - } - } - } - `, - )([]Err{ - { - message: `Fields "scalar" conflict because they return conflicting types "String!" and "String". Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 17}, - {line: 8, column: 17}, - }, - }, - }) - }) - - t.Run("disallows differing return type list despite no overlap", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - box: listStringBox { - scalar - } - } - ... on StringBox { - box: stringBox { - scalar - } - } - } - } - `, - )([]Err{ - { - message: `Fields "box" conflict because they return conflicting types "[StringBox]" and "StringBox". Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 17}, - {line: 10, column: 17}, - }, - }, - }) - - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar - } - } - ... on StringBox { - box: listStringBox { - scalar - } - } - } - } - `, - )([]Err{ - { - message: `Fields "box" conflict because they return conflicting types "StringBox" and "[StringBox]". Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 17}, - {line: 10, column: 17}, - }, - }, - }) - }) - - t.Run("disallows differing subfields", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - box: stringBox { - val: scalar - val: unrelatedField - } - } - ... on StringBox { - box: stringBox { - val: scalar - } - } - } - } - `, - )([]Err{ - { - message: `Fields "val" conflict because "scalar" and "unrelatedField" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 6, column: 19}, - {line: 7, column: 19}, - }, - }, - }) - }) - - t.Run("disallows differing deep return types despite no overlap", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - box: stringBox { - scalar - } - } - ... on StringBox { - box: intBox { - scalar - } - } - } - } - `, - )([]Err{ - { - message: `Fields "box" conflict because subfields "scalar" conflict because they return conflicting types "String" and "Int". Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 17}, - {line: 6, column: 19}, - {line: 10, column: 17}, - {line: 11, column: 19}, - }, - }, - }) - }) - - t.Run("allows non-conflicting overlapping types", func(t *testing.T) { - ExpectValidWithSchema(t, - schema, - ` - { - someBox { - ... on IntBox { - scalar: unrelatedField - } - ... on StringBox { - scalar - } - } - } - `, - ) - }) - - t.Run("same wrapped scalar return types", func(t *testing.T) { - ExpectValidWithSchema(t, - schema, - ` - { - someBox { - ...on NonNullStringBox1 { - scalar - } - ...on NonNullStringBox2 { - scalar - } - } - } - `, - ) - }) - - t.Run("allows inline fragments without type condition", func(t *testing.T) { - ExpectValidWithSchema(t, - schema, - ` - { - a - ... { - a - } - } - `, - ) - }) - - t.Run("compares deep types including list", func(t *testing.T) { - ExpectErrorsWithSchema(t, - schema, - ` - { - connection { - ...edgeID - edges { - node { - id: name - } - } - } - } - - fragment edgeID on Connection { - edges { - node { - id - } - } - } - `, - )([]Err{ - { - message: `Fields "edges" conflict because subfields "node" conflict because subfields "id" conflict because "name" and "id" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 5, column: 15}, - {line: 6, column: 17}, - {line: 7, column: 19}, - {line: 14, column: 13}, - {line: 15, column: 15}, - {line: 16, column: 17}, - }, - }, - }) - }) - - t.Run("ignores unknown types", func(t *testing.T) { - ExpectValidWithSchema(t, - schema, - ` - { - someBox { - ...on UnknownType { - scalar - } - ...on NonNullStringBox2 { - scalar - } - } - } - `, - ) - }) - - t.Run("works for field names that are JS keywords", func(t *testing.T) { - schemaWithKeywords := BuildSchema(` - type Foo { - constructor: String - } - - type Query { - foo: Foo - } - `) - - ExpectValidWithSchema(t, - schemaWithKeywords, - ` - { - foo { - constructor - } - } - `, - ) - }) - }) - - t.Run("does not infinite loop on recursive fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Human { name, relatives { name, ...fragA } } - `) - }) - - t.Run("does not infinite loop on immediately recursive fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Human { name, ...fragA } - `) - }) - - t.Run("does not infinite loop on transitively recursive fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Human { name, ...fragB } - fragment fragB on Human { name, ...fragC } - fragment fragC on Human { name, ...fragA } - `) - }) - - t.Run("finds invalid case even with immediately recursive fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment sameAliasesWithDifferentFieldTargets on Dog { - ...sameAliasesWithDifferentFieldTargets - fido: name - fido: nickname - } - `)([]Err{ - { - message: `Fields "fido" conflict because "name" and "nickname" are different fields. Use different aliases on the fields to fetch both if this was intentional.`, - locations: []Loc{ - {line: 4, column: 9}, - {line: 5, column: 9}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/PossibleFragmentSpreadsRule_test.go b/pkg/astvalidation/reference/testsgo/PossibleFragmentSpreadsRule_test.go deleted file mode 100755 index 553858c21..000000000 --- a/pkg/astvalidation/reference/testsgo/PossibleFragmentSpreadsRule_test.go +++ /dev/null @@ -1,244 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestPossibleFragmentSpreadsRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, PossibleFragmentSpreadsRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Possible fragment spreads", func(t *testing.T) { - t.Run("of the same object", func(t *testing.T) { - ExpectValid(t, ` - fragment objectWithinObject on Dog { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `) - }) - - t.Run("of the same object with inline fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } - `) - }) - - t.Run("object into an implemented interface", func(t *testing.T) { - ExpectValid(t, ` - fragment objectWithinInterface on Pet { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `) - }) - - t.Run("object into containing union", func(t *testing.T) { - ExpectValid(t, ` - fragment objectWithinUnion on CatOrDog { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `) - }) - - t.Run("union into contained object", func(t *testing.T) { - ExpectValid(t, ` - fragment unionWithinObject on Dog { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `) - }) - - t.Run("union into overlapping interface", func(t *testing.T) { - ExpectValid(t, ` - fragment unionWithinInterface on Pet { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `) - }) - - t.Run("union into overlapping union", func(t *testing.T) { - ExpectValid(t, ` - fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `) - }) - - t.Run("interface into implemented object", func(t *testing.T) { - ExpectValid(t, ` - fragment interfaceWithinObject on Dog { ...petFragment } - fragment petFragment on Pet { name } - `) - }) - - t.Run("interface into overlapping interface", func(t *testing.T) { - ExpectValid(t, ` - fragment interfaceWithinInterface on Pet { ...beingFragment } - fragment beingFragment on Being { name } - `) - }) - - t.Run("interface into overlapping interface in inline fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment interfaceWithinInterface on Pet { ... on Being { name } } - `) - }) - - t.Run("interface into overlapping union", func(t *testing.T) { - ExpectValid(t, ` - fragment interfaceWithinUnion on CatOrDog { ...petFragment } - fragment petFragment on Pet { name } - `) - }) - - t.Run("ignores incorrect type (caught by FragmentsOnCompositeTypesRule)", func(t *testing.T) { - ExpectValid(t, ` - fragment petFragment on Pet { ...badInADifferentWay } - fragment badInADifferentWay on String { name } - `) - }) - - t.Run("ignores unknown fragments (caught by KnownFragmentNamesRule)", func(t *testing.T) { - ExpectValid(t, ` - fragment petFragment on Pet { ...UnknownFragment } - `) - }) - - t.Run("different object into object", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidObjectWithinObject on Cat { ...dogFragment } - fragment dogFragment on Dog { barkVolume } - `)([]Err{ - { - message: `Fragment "dogFragment" cannot be spread here as objects of type "Cat" can never be of type "Dog".`, - locations: []Loc{{line: 2, column: 51}}, - }, - }) - }) - - t.Run("different object into object in inline fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidObjectWithinObjectAnon on Cat { - ... on Dog { barkVolume } - } - `)([]Err{ - { - message: `Fragment cannot be spread here as objects of type "Cat" can never be of type "Dog".`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("object into not implementing interface", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidObjectWithinInterface on Pet { ...humanFragment } - fragment humanFragment on Human { pets { name } } - `)([]Err{ - { - message: `Fragment "humanFragment" cannot be spread here as objects of type "Pet" can never be of type "Human".`, - locations: []Loc{{line: 2, column: 54}}, - }, - }) - }) - - t.Run("object into not containing union", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } - fragment humanFragment on Human { pets { name } } - `)([]Err{ - { - message: `Fragment "humanFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "Human".`, - locations: []Loc{{line: 2, column: 55}}, - }, - }) - }) - - t.Run("union into not contained object", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidUnionWithinObject on Human { ...catOrDogFragment } - fragment catOrDogFragment on CatOrDog { __typename } - `)([]Err{ - { - message: `Fragment "catOrDogFragment" cannot be spread here as objects of type "Human" can never be of type "CatOrDog".`, - locations: []Loc{{line: 2, column: 52}}, - }, - }) - }) - - t.Run("union into non overlapping interface", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } - fragment humanOrAlienFragment on HumanOrAlien { __typename } - `)([]Err{ - { - message: `Fragment "humanOrAlienFragment" cannot be spread here as objects of type "Pet" can never be of type "HumanOrAlien".`, - locations: []Loc{{line: 2, column: 53}}, - }, - }) - }) - - t.Run("union into non overlapping union", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } - fragment humanOrAlienFragment on HumanOrAlien { __typename } - `)([]Err{ - { - message: `Fragment "humanOrAlienFragment" cannot be spread here as objects of type "CatOrDog" can never be of type "HumanOrAlien".`, - locations: []Loc{{line: 2, column: 54}}, - }, - }) - }) - - t.Run("interface into non implementing object", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } - fragment intelligentFragment on Intelligent { iq } - `)([]Err{ - { - message: `Fragment "intelligentFragment" cannot be spread here as objects of type "Cat" can never be of type "Intelligent".`, - locations: []Loc{{line: 2, column: 54}}, - }, - }) - }) - - t.Run("interface into non overlapping interface", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidInterfaceWithinInterface on Pet { - ...intelligentFragment - } - fragment intelligentFragment on Intelligent { iq } - `)([]Err{ - { - message: `Fragment "intelligentFragment" cannot be spread here as objects of type "Pet" can never be of type "Intelligent".`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("interface into non overlapping interface in inline fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidInterfaceWithinInterfaceAnon on Pet { - ...on Intelligent { iq } - } - `)([]Err{ - { - message: `Fragment cannot be spread here as objects of type "Pet" can never be of type "Intelligent".`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("interface into non overlapping union", func(t *testing.T) { - ExpectErrors(t, ` - fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } - fragment petFragment on Pet { name } - `)([]Err{ - { - message: `Fragment "petFragment" cannot be spread here as objects of type "HumanOrAlien" can never be of type "Pet".`, - locations: []Loc{{line: 2, column: 62}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/PossibleTypeExtensionsRule_test.go b/pkg/astvalidation/reference/testsgo/PossibleTypeExtensionsRule_test.go deleted file mode 100755 index ce14565bf..000000000 --- a/pkg/astvalidation/reference/testsgo/PossibleTypeExtensionsRule_test.go +++ /dev/null @@ -1,276 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestPossibleTypeExtensionsRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, PossibleTypeExtensionsRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Possible type extensions", func(t *testing.T) { - t.Run("no extensions", func(t *testing.T) { - ExpectValidSDL(t, ` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - `) - }) - - t.Run("one extension per type", func(t *testing.T) { - ExpectValidSDL(t, ` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - `) - }) - - t.Run("many extensions per type", func(t *testing.T) { - ExpectValidSDL(t, ` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - `) - }) - - t.Run("extending unknown type", func(t *testing.T) { - message := - `Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?` - - ExpectSDLErrors(t, ` - type Known - - extend scalar Unknown @dummy - extend type Unknown @dummy - extend interface Unknown @dummy - extend union Unknown @dummy - extend enum Unknown @dummy - extend input Unknown @dummy - `)([]Err{ - {message: message, locations: []Loc{{line: 4, column: 21}}}, - {message: message, locations: []Loc{{line: 5, column: 19}}}, - {message: message, locations: []Loc{{line: 6, column: 24}}}, - {message: message, locations: []Loc{{line: 7, column: 20}}}, - {message: message, locations: []Loc{{line: 8, column: 19}}}, - {message: message, locations: []Loc{{line: 9, column: 20}}}, - }) - }) - - t.Run("does not consider non-type definitions", func(t *testing.T) { - message := `Cannot extend type "Foo" because it is not defined.` - - ExpectSDLErrors(t, ` - query Foo { __typename } - fragment Foo on Query { __typename } - directive @Foo on SCHEMA - - extend scalar Foo @dummy - extend type Foo @dummy - extend interface Foo @dummy - extend union Foo @dummy - extend enum Foo @dummy - extend input Foo @dummy - `)([]Err{ - {message: message, locations: []Loc{{line: 6, column: 21}}}, - {message: message, locations: []Loc{{line: 7, column: 19}}}, - {message: message, locations: []Loc{{line: 8, column: 24}}}, - {message: message, locations: []Loc{{line: 9, column: 20}}}, - {message: message, locations: []Loc{{line: 10, column: 19}}}, - {message: message, locations: []Loc{{line: 11, column: 20}}}, - }) - }) - - t.Run("extending with different kinds", func(t *testing.T) { - ExpectSDLErrors(t, ` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - - extend type FooScalar @dummy - extend interface FooObject @dummy - extend union FooInterface @dummy - extend enum FooUnion @dummy - extend input FooEnum @dummy - extend scalar FooInputObject @dummy - `)([]Err{ - { - message: `Cannot extend non-object type "FooScalar".`, - locations: []Loc{ - {line: 2, column: 7}, - {line: 9, column: 7}, - }, - }, - { - message: `Cannot extend non-interface type "FooObject".`, - locations: []Loc{ - {line: 3, column: 7}, - {line: 10, column: 7}, - }, - }, - { - message: `Cannot extend non-union type "FooInterface".`, - locations: []Loc{ - {line: 4, column: 7}, - {line: 11, column: 7}, - }, - }, - { - message: `Cannot extend non-enum type "FooUnion".`, - locations: []Loc{ - {line: 5, column: 7}, - {line: 12, column: 7}, - }, - }, - { - message: `Cannot extend non-input object type "FooEnum".`, - locations: []Loc{ - {line: 6, column: 7}, - {line: 13, column: 7}, - }, - }, - { - message: `Cannot extend non-scalar type "FooInputObject".`, - locations: []Loc{ - {line: 7, column: 7}, - {line: 14, column: 7}, - }, - }, - }) - }) - - t.Run("extending types within existing schema", func(t *testing.T) { - schema := BuildSchema(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - `) - sdl := ` - extend scalar FooScalar @dummy - extend type FooObject @dummy - extend interface FooInterface @dummy - extend union FooUnion @dummy - extend enum FooEnum @dummy - extend input FooInputObject @dummy - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("extending unknown types within existing schema", func(t *testing.T) { - schema := BuildSchema("type Known") - sdl := ` - extend scalar Unknown @dummy - extend type Unknown @dummy - extend interface Unknown @dummy - extend union Unknown @dummy - extend enum Unknown @dummy - extend input Unknown @dummy - ` - - message := - `Cannot extend type "Unknown" because it is not defined. Did you mean "Known"?` - ExpectSDLErrors(t, sdl, schema)([]Err{ - {message: message, locations: []Loc{{line: 2, column: 21}}}, - {message: message, locations: []Loc{{line: 3, column: 19}}}, - {message: message, locations: []Loc{{line: 4, column: 24}}}, - {message: message, locations: []Loc{{line: 5, column: 20}}}, - {message: message, locations: []Loc{{line: 6, column: 19}}}, - {message: message, locations: []Loc{{line: 7, column: 20}}}, - }) - }) - - t.Run("extending types with different kinds within existing schema", func(t *testing.T) { - schema := BuildSchema(` - scalar FooScalar - type FooObject - interface FooInterface - union FooUnion - enum FooEnum - input FooInputObject - `) - sdl := ` - extend type FooScalar @dummy - extend interface FooObject @dummy - extend union FooInterface @dummy - extend enum FooUnion @dummy - extend input FooEnum @dummy - extend scalar FooInputObject @dummy - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Cannot extend non-object type "FooScalar".`, - locations: []Loc{{line: 2, column: 7}}, - }, - { - message: `Cannot extend non-interface type "FooObject".`, - locations: []Loc{{line: 3, column: 7}}, - }, - { - message: `Cannot extend non-union type "FooInterface".`, - locations: []Loc{{line: 4, column: 7}}, - }, - { - message: `Cannot extend non-enum type "FooUnion".`, - locations: []Loc{{line: 5, column: 7}}, - }, - { - message: `Cannot extend non-input object type "FooEnum".`, - locations: []Loc{{line: 6, column: 7}}, - }, - { - message: `Cannot extend non-scalar type "FooInputObject".`, - locations: []Loc{{line: 7, column: 7}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/ProvidedRequiredArgumentsRule_test.go b/pkg/astvalidation/reference/testsgo/ProvidedRequiredArgumentsRule_test.go deleted file mode 100755 index 6a1a392bf..000000000 --- a/pkg/astvalidation/reference/testsgo/ProvidedRequiredArgumentsRule_test.go +++ /dev/null @@ -1,347 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestProvidedRequiredArgumentsRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, ProvidedRequiredArgumentsRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, - schema, - ProvidedRequiredArgumentsOnDirectivesRule, - sdlStr, - ) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schema ...string) { - ExpectSDLErrors(t, sdlStr)([]Err{}) - } - - t.Run("Validate: Provided required arguments", func(t *testing.T) { - t.Run("ignores unknown arguments", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - isHouseTrained(unknownArgument: true) - } - } - `) - }) - - t.Run("Valid non-nullable value", func(t *testing.T) { - t.Run("Arg on optional arg", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - isHouseTrained(atOtherHomes: true) - } - } - `) - }) - - t.Run("No Arg on optional arg", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - isHouseTrained - } - } - `) - }) - - t.Run("No arg on non-null field with default", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - nonNullFieldWithDefault - } - } - `) - }) - - t.Run("Multiple args", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleReqs(req1: 1, req2: 2) - } - } - `) - }) - - t.Run("Multiple args reverse order", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleReqs(req2: 2, req1: 1) - } - } - `) - }) - - t.Run("No args on multiple optional", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOpts - } - } - `) - }) - - t.Run("One arg on multiple optional", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOpts(opt1: 1) - } - } - `) - }) - - t.Run("Second arg on multiple optional", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOpts(opt2: 1) - } - } - `) - }) - - t.Run("Multiple required args on mixedList", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4) - } - } - `) - }) - - t.Run("Multiple required and one optional arg on mixedList", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5) - } - } - `) - }) - - t.Run("All required and optional args on mixedList", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) - } - } - `) - }) - }) - - t.Run("Invalid non-nullable value", func(t *testing.T) { - t.Run("Missing one non-nullable argument", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - multipleReqs(req2: 2) - } - } - `)([]Err{ - { - message: `Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.`, - locations: []Loc{{line: 4, column: 13}}, - }, - }) - }) - - t.Run("Missing multiple non-nullable arguments", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - multipleReqs - } - } - `)([]Err{ - { - message: `Field "multipleReqs" argument "req1" of type "Int!" is required, but it was not provided.`, - locations: []Loc{{line: 4, column: 13}}, - }, - { - message: `Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.`, - locations: []Loc{{line: 4, column: 13}}, - }, - }) - }) - - t.Run("Incorrect value and missing argument", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - multipleReqs(req1: "one") - } - } - `)([]Err{ - { - message: `Field "multipleReqs" argument "req2" of type "Int!" is required, but it was not provided.`, - locations: []Loc{{line: 4, column: 13}}, - }, - }) - }) - }) - - t.Run("Directive arguments", func(t *testing.T) { - t.Run("ignores unknown directives", func(t *testing.T) { - ExpectValid(t, ` - { - dog @unknown - } - `) - }) - - t.Run("with directives of valid types", func(t *testing.T) { - ExpectValid(t, ` - { - dog @include(if: true) { - name - } - human @skip(if: false) { - name - } - } - `) - }) - - t.Run("with directive with missing types", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @include { - name @skip - } - } - `)([]Err{ - { - message: `Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.`, - locations: []Loc{{line: 3, column: 15}}, - }, - { - message: `Directive "@skip" argument "if" of type "Boolean!" is required, but it was not provided.`, - locations: []Loc{{line: 4, column: 18}}, - }, - }) - }) - }) - - t.Run("within SDL", func(t *testing.T) { - t.Run("Missing optional args on directive defined inside SDL", func(t *testing.T) { - ExpectValidSDL(t, ` - type Query { - foo: String @test - } - - directive @test(arg1: String, arg2: String! = "") on FIELD_DEFINITION - `) - }) - - t.Run("Missing arg on directive defined inside SDL", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @test - } - - directive @test(arg: String!) on FIELD_DEFINITION - `)([]Err{ - { - message: `Directive "@test" argument "arg" of type "String!" is required, but it was not provided.`, - locations: []Loc{{line: 3, column: 23}}, - }, - }) - }) - - t.Run("Missing arg on standard directive", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @include - } - `)([]Err{ - { - message: `Directive "@include" argument "if" of type "Boolean!" is required, but it was not provided.`, - locations: []Loc{{line: 3, column: 23}}, - }, - }) - }) - - t.Run("Missing arg on overridden standard directive", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Query { - foo: String @deprecated - } - directive @deprecated(reason: String!) on FIELD - `)([]Err{ - { - message: `Directive "@deprecated" argument "reason" of type "String!" is required, but it was not provided.`, - locations: []Loc{{line: 3, column: 23}}, - }, - }) - }) - - t.Run("Missing arg on directive defined in schema extension", func(t *testing.T) { - schema := BuildSchema(` - type Query { - foo: String - } - `) - ExpectSDLErrors(t, - ` - directive @test(arg: String!) on OBJECT - - extend type Query @test - `, - schema, - )([]Err{ - { - message: `Directive "@test" argument "arg" of type "String!" is required, but it was not provided.`, - locations: []Loc{{line: 4, column: 30}}, - }, - }) - }) - - t.Run("Missing arg on directive used in schema extension", func(t *testing.T) { - schema := BuildSchema(` - directive @test(arg: String!) on OBJECT - - type Query { - foo: String - } - `) - ExpectSDLErrors(t, - ` - extend type Query @test - `, - schema, - )([]Err{ - { - message: `Directive "@test" argument "arg" of type "String!" is required, but it was not provided.`, - locations: []Loc{{line: 2, column: 29}}, - }, - }) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/ScalarLeafsRule_test.go b/pkg/astvalidation/reference/testsgo/ScalarLeafsRule_test.go deleted file mode 100755 index d273e4f65..000000000 --- a/pkg/astvalidation/reference/testsgo/ScalarLeafsRule_test.go +++ /dev/null @@ -1,127 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestScalarLeafsRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, ScalarLeafsRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Scalar leafs", func(t *testing.T) { - t.Run("valid scalar selection", func(t *testing.T) { - ExpectValid(t, ` - fragment scalarSelection on Dog { - barks - } - `) - }) - - t.Run("object type missing selection", func(t *testing.T) { - ExpectErrors(t, ` - query directQueryOnObjectWithoutSubFields { - human - } - `)([]Err{ - { - message: `Field "human" of type "Human" must have a selection of subfields. Did you mean "human { ... }"?`, - locations: []Loc{{line: 3, column: 9}}, - }, - }) - }) - - t.Run("interface type missing selection", func(t *testing.T) { - ExpectErrors(t, ` - { - human { pets } - } - `)([]Err{ - { - message: `Field "pets" of type "[Pet]" must have a selection of subfields. Did you mean "pets { ... }"?`, - locations: []Loc{{line: 3, column: 17}}, - }, - }) - }) - - t.Run("valid scalar selection with args", func(t *testing.T) { - ExpectValid(t, ` - fragment scalarSelectionWithArgs on Dog { - doesKnowCommand(dogCommand: SIT) - } - `) - }) - - t.Run("scalar selection not allowed on Boolean", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarSelectionsNotAllowedOnBoolean on Dog { - barks { sinceWhen } - } - `)([]Err{ - { - message: `Field "barks" must not have a selection since type "Boolean" has no subfields.`, - locations: []Loc{{line: 3, column: 15}}, - }, - }) - }) - - t.Run("scalar selection not allowed on Enum", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarSelectionsNotAllowedOnEnum on Cat { - furColor { inHexDec } - } - `)([]Err{ - { - message: `Field "furColor" must not have a selection since type "FurColor" has no subfields.`, - locations: []Loc{{line: 3, column: 18}}, - }, - }) - }) - - t.Run("scalar selection not allowed with args", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarSelectionsNotAllowedWithArgs on Dog { - doesKnowCommand(dogCommand: SIT) { sinceWhen } - } - `)([]Err{ - { - message: `Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.`, - locations: []Loc{{line: 3, column: 42}}, - }, - }) - }) - - t.Run("Scalar selection not allowed with directives", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarSelectionsNotAllowedWithDirectives on Dog { - name @include(if: true) { isAlsoHumanName } - } - `)([]Err{ - { - message: `Field "name" must not have a selection since type "String" has no subfields.`, - locations: []Loc{{line: 3, column: 33}}, - }, - }) - }) - - t.Run("Scalar selection not allowed with directives and args", func(t *testing.T) { - ExpectErrors(t, ` - fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { - doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } - } - `)([]Err{ - { - message: `Field "doesKnowCommand" must not have a selection since type "Boolean" has no subfields.`, - locations: []Loc{{line: 3, column: 61}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/SingleFieldSubscriptionsRule_test.go b/pkg/astvalidation/reference/testsgo/SingleFieldSubscriptionsRule_test.go deleted file mode 100755 index 656980bf0..000000000 --- a/pkg/astvalidation/reference/testsgo/SingleFieldSubscriptionsRule_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestSingleFieldSubscriptionsRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, SingleFieldSubscriptionsRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Subscriptions with single field", func(t *testing.T) { - t.Run("valid subscription", func(t *testing.T) { - ExpectValid(t, ` - subscription ImportantEmails { - importantEmails - } - `) - }) - - t.Run("fails with more than one root field", func(t *testing.T) { - ExpectErrors(t, ` - subscription ImportantEmails { - importantEmails - notImportantEmails - } - `)([]Err{ - { - message: `Subscription "ImportantEmails" must select only one top level field.`, - locations: []Loc{{line: 4, column: 9}}, - }, - }) - }) - - t.Run("fails with more than one root field including introspection", func(t *testing.T) { - ExpectErrors(t, ` - subscription ImportantEmails { - importantEmails - __typename - } - `)([]Err{ - { - message: `Subscription "ImportantEmails" must select only one top level field.`, - locations: []Loc{{line: 4, column: 9}}, - }, - }) - }) - - t.Run("fails with many more than one root field", func(t *testing.T) { - ExpectErrors(t, ` - subscription ImportantEmails { - importantEmails - notImportantEmails - spamEmails - } - `)([]Err{ - { - message: `Subscription "ImportantEmails" must select only one top level field.`, - locations: []Loc{ - {line: 4, column: 9}, - {line: 5, column: 9}, - }, - }, - }) - }) - - t.Run("fails with more than one root field in anonymous subscriptions", func(t *testing.T) { - ExpectErrors(t, ` - subscription { - importantEmails - notImportantEmails - } - `)([]Err{ - { - message: "Anonymous Subscription must select only one top level field.", - locations: []Loc{{line: 4, column: 9}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueArgumentNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueArgumentNamesRule_test.go deleted file mode 100755 index d26fd0a83..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueArgumentNamesRule_test.go +++ /dev/null @@ -1,171 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueArgumentNamesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, UniqueArgumentNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Unique argument names", func(t *testing.T) { - t.Run("no arguments on field", func(t *testing.T) { - ExpectValid(t, ` - { - field - } - `) - }) - - t.Run("no arguments on directive", func(t *testing.T) { - ExpectValid(t, ` - { - field @directive - } - `) - }) - - t.Run("argument on field", func(t *testing.T) { - ExpectValid(t, ` - { - field(arg: "value") - } - `) - }) - - t.Run("argument on directive", func(t *testing.T) { - ExpectValid(t, ` - { - field @directive(arg: "value") - } - `) - }) - - t.Run("same argument on two fields", func(t *testing.T) { - ExpectValid(t, ` - { - one: field(arg: "value") - two: field(arg: "value") - } - `) - }) - - t.Run("same argument on field and directive", func(t *testing.T) { - ExpectValid(t, ` - { - field(arg: "value") @directive(arg: "value") - } - `) - }) - - t.Run("same argument on two directives", func(t *testing.T) { - ExpectValid(t, ` - { - field @directive1(arg: "value") @directive2(arg: "value") - } - `) - }) - - t.Run("multiple field arguments", func(t *testing.T) { - ExpectValid(t, ` - { - field(arg1: "value", arg2: "value", arg3: "value") - } - `) - }) - - t.Run("multiple directive arguments", func(t *testing.T) { - ExpectValid(t, ` - { - field @directive(arg1: "value", arg2: "value", arg3: "value") - } - `) - }) - - t.Run("duplicate field arguments", func(t *testing.T) { - ExpectErrors(t, ` - { - field(arg1: "value", arg1: "value") - } - `)([]Err{ - { - message: `There can be only one argument named "arg1".`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 30}, - }, - }, - }) - }) - - t.Run("many duplicate field arguments", func(t *testing.T) { - ExpectErrors(t, ` - { - field(arg1: "value", arg1: "value", arg1: "value") - } - `)([]Err{ - { - message: `There can be only one argument named "arg1".`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 30}, - }, - }, - { - message: `There can be only one argument named "arg1".`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 45}, - }, - }, - }) - }) - - t.Run("duplicate directive arguments", func(t *testing.T) { - ExpectErrors(t, ` - { - field @directive(arg1: "value", arg1: "value") - } - `)([]Err{ - { - message: `There can be only one argument named "arg1".`, - locations: []Loc{ - {line: 3, column: 26}, - {line: 3, column: 41}, - }, - }, - }) - }) - - t.Run("many duplicate directive arguments", func(t *testing.T) { - ExpectErrors(t, ` - { - field @directive(arg1: "value", arg1: "value", arg1: "value") - } - `)([]Err{ - { - message: `There can be only one argument named "arg1".`, - locations: []Loc{ - {line: 3, column: 26}, - {line: 3, column: 41}, - }, - }, - { - message: `There can be only one argument named "arg1".`, - locations: []Loc{ - {line: 3, column: 26}, - {line: 3, column: 56}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueDirectiveNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueDirectiveNamesRule_test.go deleted file mode 100755 index 9a4eb7174..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueDirectiveNamesRule_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueDirectiveNamesRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, UniqueDirectiveNamesRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Unique directive names", func(t *testing.T) { - t.Run("no directive", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - `) - }) - - t.Run("one directive", func(t *testing.T) { - ExpectValidSDL(t, ` - directive @foo on SCHEMA - `) - }) - - t.Run("many directives", func(t *testing.T) { - ExpectValidSDL(t, ` - directive @foo on SCHEMA - directive @bar on SCHEMA - directive @baz on SCHEMA - `) - }) - - t.Run("directive and non-directive definitions named the same", func(t *testing.T) { - ExpectValidSDL(t, ` - query foo { __typename } - fragment foo on foo { __typename } - type foo - - directive @foo on SCHEMA - `) - }) - - t.Run("directives named the same", func(t *testing.T) { - ExpectSDLErrors(t, ` - directive @foo on SCHEMA - - directive @foo on SCHEMA - `)([]Err{ - { - message: `There can be only one directive named "@foo".`, - locations: []Loc{ - {line: 2, column: 18}, - {line: 4, column: 18}, - }, - }, - }) - }) - - t.Run("adding new directive to existing schema", func(t *testing.T) { - schema := BuildSchema("directive @foo on SCHEMA") - - ExpectValidSDL(t, "directive @bar on SCHEMA", schema) - }) - - t.Run("adding new directive with standard name to existing schema", func(t *testing.T) { - schema := BuildSchema("type foo") - - ExpectSDLErrors(t, "directive @skip on SCHEMA", schema)([]Err{ - { - message: `Directive "@skip" already exists in the schema. It cannot be redefined.`, - locations: []Loc{{line: 1, column: 12}}, - }, - }) - }) - - t.Run("adding new directive to existing schema with same-named type", func(t *testing.T) { - schema := BuildSchema("type foo") - - ExpectValidSDL(t, "directive @foo on SCHEMA", schema) - }) - - t.Run("adding conflicting directives to existing schema", func(t *testing.T) { - schema := BuildSchema("directive @foo on SCHEMA") - - ExpectSDLErrors(t, "directive @foo on SCHEMA", schema)([]Err{ - { - message: `Directive "@foo" already exists in the schema. It cannot be redefined.`, - locations: []Loc{{line: 1, column: 12}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueDirectivesPerLocationRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueDirectivesPerLocationRule_test.go deleted file mode 100755 index 583e971e7..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueDirectivesPerLocationRule_test.go +++ /dev/null @@ -1,377 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueDirectivesPerLocationRule(t *testing.T) { - - extensionSDL := ` - directive @directive on FIELD | FRAGMENT_DEFINITION - directive @directiveA on FIELD | FRAGMENT_DEFINITION - directive @directiveB on FIELD | FRAGMENT_DEFINITION - directive @repeatable repeatable on FIELD | FRAGMENT_DEFINITION - - # adding type here to make test queries valid - type Type { - field: String! - } -` - schemaWithDirectives := ExtendSchema(testSchema, extensionSDL) - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrorsWithSchema(t, - schemaWithDirectives, - UniqueDirectivesPerLocationRule, - queryStr, - ) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, - schema, - UniqueDirectivesPerLocationRule, - sdlStr, - ) - } - - t.Run("Validate: Directives Are Unique Per Location", func(t *testing.T) { - t.Run("no directives", func(t *testing.T) { - ExpectValid(t, ` - fragment Test on Type { - field - } - `) - }) - - t.Run("unique directives in different locations", func(t *testing.T) { - ExpectValid(t, ` - fragment Test on Type @directiveA { - field @directiveB - } - `) - }) - - t.Run("unique directives in same locations", func(t *testing.T) { - ExpectValid(t, ` - fragment Test on Type @directiveA @directiveB { - field @directiveA @directiveB - } - `) - }) - - t.Run("same directives in different locations", func(t *testing.T) { - ExpectValid(t, ` - fragment Test on Type @directiveA { - field @directiveA - } - `) - }) - - t.Run("same directives in similar locations", func(t *testing.T) { - ExpectValid(t, ` - fragment Test on Type { - field @directive - field @directive - } - `) - }) - - t.Run("repeatable directives in same location", func(t *testing.T) { - ExpectValid(t, ` - fragment Test on Type @repeatable @repeatable { - field @repeatable @repeatable - } - `) - }) - - t.Run("unknown directives must be ignored", func(t *testing.T) { - ExpectValid(t, ` - type Test @unknown @unknown { - field: String! @unknown @unknown - } - - extend type Test @unknown { - anotherField: String! - } - `) - }) - - t.Run("duplicate directives in one location", func(t *testing.T) { - ExpectErrors(t, ` - fragment Test on Type { - field @directive @directive - } - `)([]Err{ - { - message: `The directive "@directive" can only be used once at this location.`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 26}, - }, - }, - }) - }) - - t.Run("many duplicate directives in one location", func(t *testing.T) { - ExpectErrors(t, ` - fragment Test on Type { - field @directive @directive @directive - } - `)([]Err{ - { - message: `The directive "@directive" can only be used once at this location.`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 26}, - }, - }, - { - message: `The directive "@directive" can only be used once at this location.`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 37}, - }, - }, - }) - }) - - t.Run("different duplicate directives in one location", func(t *testing.T) { - ExpectErrors(t, ` - fragment Test on Type { - field @directiveA @directiveB @directiveA @directiveB - } - `)([]Err{ - { - message: `The directive "@directiveA" can only be used once at this location.`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 39}, - }, - }, - { - message: `The directive "@directiveB" can only be used once at this location.`, - locations: []Loc{ - {line: 3, column: 27}, - {line: 3, column: 51}, - }, - }, - }) - }) - - t.Run("duplicate directives in many locations", func(t *testing.T) { - ExpectErrors(t, ` - fragment Test on Type @directive @directive { - field @directive @directive - } - `)([]Err{ - { - message: `The directive "@directive" can only be used once at this location.`, - locations: []Loc{ - {line: 2, column: 29}, - {line: 2, column: 40}, - }, - }, - { - message: `The directive "@directive" can only be used once at this location.`, - locations: []Loc{ - {line: 3, column: 15}, - {line: 3, column: 26}, - }, - }, - }) - }) - - t.Run("duplicate directives on SDL definitions", func(t *testing.T) { - ExpectSDLErrors(t, ` - directive @nonRepeatable on - SCHEMA | SCALAR | OBJECT | INTERFACE | UNION | INPUT_OBJECT - - schema @nonRepeatable @nonRepeatable { query: Dummy } - - scalar TestScalar @nonRepeatable @nonRepeatable - type TestObject @nonRepeatable @nonRepeatable - interface TestInterface @nonRepeatable @nonRepeatable - union TestUnion @nonRepeatable @nonRepeatable - input TestInput @nonRepeatable @nonRepeatable - `)([]Err{ - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 5, column: 14}, - {line: 5, column: 29}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 7, column: 25}, - {line: 7, column: 40}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 8, column: 23}, - {line: 8, column: 38}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 9, column: 31}, - {line: 9, column: 46}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 10, column: 23}, - {line: 10, column: 38}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 11, column: 23}, - {line: 11, column: 38}, - }, - }, - }) - }) - - t.Run("duplicate directives on SDL extensions", func(t *testing.T) { - t.Skip("Parser do not support directives on extensions") - - ExpectSDLErrors(t, ` - directive @nonRepeatable on - SCHEMA | SCALAR | OBJECT | INTERFACE | UNION | INPUT_OBJECT - - extend schema @nonRepeatable @nonRepeatable - - extend scalar TestScalar @nonRepeatable @nonRepeatable - extend type TestObject @nonRepeatable @nonRepeatable - extend interface TestInterface @nonRepeatable @nonRepeatable - extend union TestUnion @nonRepeatable @nonRepeatable - extend input TestInput @nonRepeatable @nonRepeatable - `)([]Err{ - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 5, column: 21}, - {line: 5, column: 36}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 7, column: 32}, - {line: 7, column: 47}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 8, column: 30}, - {line: 8, column: 45}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 9, column: 38}, - {line: 9, column: 53}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 10, column: 30}, - {line: 10, column: 45}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 11, column: 30}, - {line: 11, column: 45}, - }, - }, - }) - }) - - t.Run("duplicate directives between SDL definitions and extensions", func(t *testing.T) { - t.Skip("Parser do not support directives on extensions") - - ExpectSDLErrors(t, ` - directive @nonRepeatable on SCHEMA - - schema @nonRepeatable { query: Dummy } - extend schema @nonRepeatable - `)([]Err{ - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 4, column: 14}, - {line: 5, column: 21}, - }, - }, - }) - - ExpectSDLErrors(t, ` - directive @nonRepeatable on SCALAR - - scalar TestScalar @nonRepeatable - extend scalar TestScalar @nonRepeatable - scalar TestScalar @nonRepeatable - `)([]Err{ - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 4, column: 25}, - {line: 5, column: 32}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 4, column: 25}, - {line: 6, column: 25}, - }, - }, - }) - - ExpectSDLErrors(t, ` - directive @nonRepeatable on OBJECT - - extend type TestObject @nonRepeatable - type TestObject @nonRepeatable - extend type TestObject @nonRepeatable - `)([]Err{ - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 4, column: 30}, - {line: 5, column: 23}, - }, - }, - { - message: `The directive "@nonRepeatable" can only be used once at this location.`, - locations: []Loc{ - {line: 4, column: 30}, - {line: 6, column: 30}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueEnumValueNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueEnumValueNamesRule_test.go deleted file mode 100755 index d4027bb59..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueEnumValueNamesRule_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueEnumValueNamesRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, UniqueEnumValueNamesRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Unique enum value names", func(t *testing.T) { - t.Run("no values", func(t *testing.T) { - ExpectValidSDL(t, ` - enum SomeEnum - `) - }) - - t.Run("one value", func(t *testing.T) { - ExpectValidSDL(t, ` - enum SomeEnum { - FOO - } - `) - }) - - t.Run("multiple values", func(t *testing.T) { - ExpectValidSDL(t, ` - enum SomeEnum { - FOO - BAR - } - `) - }) - - t.Run("duplicate values inside the same enum definition", func(t *testing.T) { - ExpectSDLErrors(t, ` - enum SomeEnum { - FOO - BAR - FOO - } - `)([]Err{ - { - message: `Enum value "SomeEnum.FOO" can only be defined once.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 5, column: 9}, - }, - }, - }) - }) - - t.Run("extend enum with new value", func(t *testing.T) { - ExpectValidSDL(t, ` - enum SomeEnum { - FOO - } - extend enum SomeEnum { - BAR - } - extend enum SomeEnum { - BAZ - } - `) - }) - - t.Run("extend enum with duplicate value", func(t *testing.T) { - ExpectSDLErrors(t, ` - extend enum SomeEnum { - FOO - } - enum SomeEnum { - FOO - } - `)([]Err{ - { - message: `Enum value "SomeEnum.FOO" can only be defined once.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 6, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate value inside extension", func(t *testing.T) { - ExpectSDLErrors(t, ` - enum SomeEnum - extend enum SomeEnum { - FOO - BAR - FOO - } - `)([]Err{ - { - message: `Enum value "SomeEnum.FOO" can only be defined once.`, - locations: []Loc{ - {line: 4, column: 9}, - {line: 6, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate value inside different extensions", func(t *testing.T) { - ExpectSDLErrors(t, ` - enum SomeEnum - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - `)([]Err{ - { - message: `Enum value "SomeEnum.FOO" can only be defined once.`, - locations: []Loc{ - {line: 4, column: 9}, - {line: 7, column: 9}, - }, - }, - }) - }) - - t.Run("adding new value to the type inside existing schema", func(t *testing.T) { - schema := BuildSchema("enum SomeEnum") - sdl := ` - extend enum SomeEnum { - FOO - } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("adding conflicting value to existing schema twice", func(t *testing.T) { - schema := BuildSchema(` - enum SomeEnum { - FOO - } - `) - sdl := ` - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 3, column: 9}}, - }, - { - message: `Enum value "SomeEnum.FOO" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 6, column: 9}}, - }, - }) - }) - - t.Run("adding enum values to existing schema twice", func(t *testing.T) { - schema := BuildSchema("enum SomeEnum") - sdl := ` - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Enum value "SomeEnum.FOO" can only be defined once.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 6, column: 9}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueFieldDefinitionNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueFieldDefinitionNamesRule_test.go deleted file mode 100755 index 0e4f4a4df..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueFieldDefinitionNamesRule_test.go +++ /dev/null @@ -1,434 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueFieldDefinitionNamesRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, - schema, - UniqueFieldDefinitionNamesRule, - sdlStr, - ) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Unique field definition names", func(t *testing.T) { - t.Run("no fields", func(t *testing.T) { - ExpectValidSDL(t, ` - type SomeObject - interface SomeInterface - input SomeInputObject - `) - }) - - t.Run("one field", func(t *testing.T) { - ExpectValidSDL(t, ` - type SomeObject { - foo: String - } - - interface SomeInterface { - foo: String - } - - input SomeInputObject { - foo: String - } - `) - }) - - t.Run("multiple fields", func(t *testing.T) { - ExpectValidSDL(t, ` - type SomeObject { - foo: String - bar: String - } - - interface SomeInterface { - foo: String - bar: String - } - - input SomeInputObject { - foo: String - bar: String - } - `) - }) - - t.Run("duplicate fields inside the same type definition", func(t *testing.T) { - ExpectSDLErrors(t, ` - type SomeObject { - foo: String - bar: String - foo: String - } - - interface SomeInterface { - foo: String - bar: String - foo: String - } - - input SomeInputObject { - foo: String - bar: String - foo: String - } - `)([]Err{ - { - message: `Field "SomeObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 5, column: 9}, - }, - }, - { - message: `Field "SomeInterface.foo" can only be defined once.`, - locations: []Loc{ - {line: 9, column: 9}, - {line: 11, column: 9}, - }, - }, - { - message: `Field "SomeInputObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 15, column: 9}, - {line: 17, column: 9}, - }, - }, - }) - }) - - t.Run("extend type with new field", func(t *testing.T) { - ExpectValidSDL(t, ` - type SomeObject { - foo: String - } - extend type SomeObject { - bar: String - } - extend type SomeObject { - baz: String - } - - interface SomeInterface { - foo: String - } - extend interface SomeInterface { - bar: String - } - extend interface SomeInterface { - baz: String - } - - input SomeInputObject { - foo: String - } - extend input SomeInputObject { - bar: String - } - extend input SomeInputObject { - baz: String - } - `) - }) - - t.Run("extend type with duplicate field", func(t *testing.T) { - ExpectSDLErrors(t, ` - extend type SomeObject { - foo: String - } - type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - input SomeInputObject { - foo: String - } - `)([]Err{ - { - message: `Field "SomeObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 6, column: 9}, - }, - }, - { - message: `Field "SomeInterface.foo" can only be defined once.`, - locations: []Loc{ - {line: 10, column: 9}, - {line: 13, column: 9}, - }, - }, - { - message: `Field "SomeInputObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 17, column: 9}, - {line: 20, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate field inside extension", func(t *testing.T) { - ExpectSDLErrors(t, ` - type SomeObject - extend type SomeObject { - foo: String - bar: String - foo: String - } - - interface SomeInterface - extend interface SomeInterface { - foo: String - bar: String - foo: String - } - - input SomeInputObject - extend input SomeInputObject { - foo: String - bar: String - foo: String - } - `)([]Err{ - { - message: `Field "SomeObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 4, column: 9}, - {line: 6, column: 9}, - }, - }, - { - message: `Field "SomeInterface.foo" can only be defined once.`, - locations: []Loc{ - {line: 11, column: 9}, - {line: 13, column: 9}, - }, - }, - { - message: `Field "SomeInputObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 18, column: 9}, - {line: 20, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate field inside different extensions", func(t *testing.T) { - ExpectSDLErrors(t, ` - type SomeObject - extend type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - } - - interface SomeInterface - extend interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - } - - input SomeInputObject - extend input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - } - `)([]Err{ - { - message: `Field "SomeObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 4, column: 9}, - {line: 7, column: 9}, - }, - }, - { - message: `Field "SomeInterface.foo" can only be defined once.`, - locations: []Loc{ - {line: 12, column: 9}, - {line: 15, column: 9}, - }, - }, - { - message: `Field "SomeInputObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 20, column: 9}, - {line: 23, column: 9}, - }, - }, - }) - }) - - t.Run("adding new field to the type inside existing schema", func(t *testing.T) { - schema := BuildSchema(` - type SomeObject - interface SomeInterface - input SomeInputObject - `) - sdl := ` - extend type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("adding conflicting fields to existing schema twice", func(t *testing.T) { - schema := BuildSchema(` - type SomeObject { - foo: String - } - - interface SomeInterface { - foo: String - } - - input SomeInputObject { - foo: String - } - `) - sdl := ` - extend type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - - extend type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 3, column: 9}}, - }, - { - message: `Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 6, column: 9}}, - }, - { - message: `Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 9, column: 9}}, - }, - { - message: `Field "SomeObject.foo" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 13, column: 9}}, - }, - { - message: `Field "SomeInterface.foo" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 16, column: 9}}, - }, - { - message: `Field "SomeInputObject.foo" already exists in the schema. It cannot also be defined in this type extension.`, - locations: []Loc{{line: 19, column: 9}}, - }, - }) - }) - - t.Run("adding fields to existing schema twice", func(t *testing.T) { - schema := BuildSchema(` - type SomeObject - interface SomeInterface - input SomeInputObject - `) - sdl := ` - extend type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - } - - extend interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - } - - extend input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Field "SomeObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 3, column: 9}, - {line: 6, column: 9}, - }, - }, - { - message: `Field "SomeInterface.foo" can only be defined once.`, - locations: []Loc{ - {line: 10, column: 9}, - {line: 13, column: 9}, - }, - }, - { - message: `Field "SomeInputObject.foo" can only be defined once.`, - locations: []Loc{ - {line: 17, column: 9}, - {line: 20, column: 9}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueFragmentNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueFragmentNamesRule_test.go deleted file mode 100755 index 0105b904c..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueFragmentNamesRule_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueFragmentNamesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, UniqueFragmentNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Unique fragment names", func(t *testing.T) { - t.Run("no fragments", func(t *testing.T) { - ExpectValid(t, ` - { - field - } - `) - }) - - t.Run("one fragment", func(t *testing.T) { - ExpectValid(t, ` - { - ...fragA - } - - fragment fragA on Type { - field - } - `) - }) - - t.Run("many fragments", func(t *testing.T) { - ExpectValid(t, ` - { - ...fragA - ...fragB - ...fragC - } - fragment fragA on Type { - fieldA - } - fragment fragB on Type { - fieldB - } - fragment fragC on Type { - fieldC - } - `) - }) - - t.Run("inline fragments are always unique", func(t *testing.T) { - ExpectValid(t, ` - { - ...on Type { - fieldA - } - ...on Type { - fieldB - } - } - `) - }) - - t.Run("fragment and operation named the same", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - ...Foo - } - fragment Foo on Type { - field - } - `) - }) - - t.Run("fragments named the same", func(t *testing.T) { - ExpectErrors(t, ` - { - ...fragA - } - fragment fragA on Type { - fieldA - } - fragment fragA on Type { - fieldB - } - `)([]Err{ - { - message: `There can be only one fragment named "fragA".`, - locations: []Loc{ - {line: 5, column: 16}, - {line: 8, column: 16}, - }, - }, - }) - }) - - t.Run("fragments named the same without being referenced", func(t *testing.T) { - ExpectErrors(t, ` - fragment fragA on Type { - fieldA - } - fragment fragA on Type { - fieldB - } - `)([]Err{ - { - message: `There can be only one fragment named "fragA".`, - locations: []Loc{ - {line: 2, column: 16}, - {line: 5, column: 16}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueInputFieldNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueInputFieldNamesRule_test.go deleted file mode 100755 index b61b69154..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueInputFieldNamesRule_test.go +++ /dev/null @@ -1,178 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueInputFieldNamesRule(t *testing.T) { - ExpectErrors := func(t *testing.T, schema, queryStr string) ResultCompare { - return ExpectValidationErrorsWithSchema(t, schema, UniqueInputFieldNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, schemaStr, queryStr string) { - ExpectErrors(t, schemaStr, queryStr)([]Err{}) - } - - t.Run("Validate: Unique input field names", func(t *testing.T) { - t.Run("input object with fields", func(t *testing.T) { - ExpectValid(t, ` - input Input { - f: Boolean - } - - type Query { - field(arg: Input): String - }`, ` - { - field(arg: { f: true }) - } - `) - }) - - t.Run("same input object within two args", func(t *testing.T) { - ExpectValid(t, ` - input Input { - f: Boolean - } - - type Query { - field(arg1: Input, arg2: Input): String - }`, ` - { - field(arg1: { f: true }, arg2: { f: true }) - } - `) - }) - - t.Run("multiple input object fields", func(t *testing.T) { - ExpectValid(t, ` - input Input { - f1: String - f2: String - f3: String - } - - type Query { - field(arg: Input): String - }`, ` - { - field(arg: { f1: "value", f2: "value", f3: "value" }) - } - `) - }) - - t.Run("allows for nested input objects with similar fields", func(t *testing.T) { - ExpectValid(t, ` - input Nested1 { - id: ID - deep: Nested2 - } - - input Nested2 { - id: ID - } - - input Input { - id: ID - deep: Nested1 - } - - type Query { - field(arg: Input): String - }`, ` - { - field(arg: { - deep: { - deep: { - id: 1 - } - id: 1 - } - id: 1 - }) - } - `) - }) - - t.Run("duplicate input object fields", func(t *testing.T) { - ExpectErrors(t, ` - input Input { - f1: String - } - - type Query { - field(arg: Input): String - }`, ` - { - field(arg: { f1: "value", f1: "value" }) - } - `)([]Err{ - { - message: `There can be only one input field named "f1".`, - locations: []Loc{ - {line: 3, column: 22}, - {line: 3, column: 35}, - }, - }, - }) - }) - - t.Run("many duplicate input object fields", func(t *testing.T) { - ExpectErrors(t, ` - input Input { - f1: String - } - - type Query { - field(arg: Input): String - }`, ` - { - field(arg: { f1: "value", f1: "value", f1: "value" }) - } - `)([]Err{ - { - message: `There can be only one input field named "f1".`, - locations: []Loc{ - {line: 3, column: 22}, - {line: 3, column: 35}, - }, - }, - { - message: `There can be only one input field named "f1".`, - locations: []Loc{ - {line: 3, column: 22}, - {line: 3, column: 48}, - }, - }, - }) - }) - - t.Run("nested duplicate input object fields", func(t *testing.T) { - ExpectErrors(t, ` - input Nested { - f2: String - } - - input Input { - f1: Nested - } - - type Query { - field(arg: Input): String - }`, ` - { - field(arg: { f1: {f2: "value", f2: "value" }}) - } - `)([]Err{ - { - message: `There can be only one input field named "f2".`, - locations: []Loc{ - {line: 3, column: 27}, - {line: 3, column: 40}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueOperationNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueOperationNamesRule_test.go deleted file mode 100755 index d76bb2fbd..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueOperationNamesRule_test.go +++ /dev/null @@ -1,140 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueOperationNamesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, UniqueOperationNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Unique operation names", func(t *testing.T) { - t.Run("no operations", func(t *testing.T) { - ExpectValid(t, ` - fragment fragA on Type { - field - } - `) - }) - - t.Run("one anon operation", func(t *testing.T) { - ExpectValid(t, ` - { - field - } - `) - }) - - t.Run("one named operation", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - field - } - `) - }) - - t.Run("multiple operations", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - field - } - - query Bar { - field - } - `) - }) - - t.Run("multiple operations of different types", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - field - } - - mutation Bar { - field - } - - subscription Baz { - field - } - `) - }) - - t.Run("fragment and operation named the same", func(t *testing.T) { - ExpectValid(t, ` - query Foo { - ...Foo - } - fragment Foo on Type { - field - } - `) - }) - - t.Run("multiple operations of same name", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - fieldA - } - query Foo { - fieldB - } - `)([]Err{ - { - message: `There can be only one operation named "Foo".`, - locations: []Loc{ - {line: 2, column: 13}, - {line: 5, column: 13}, - }, - }, - }) - }) - - t.Run("multiple ops of same name of different types (mutation)", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - fieldA - } - mutation Foo { - fieldB - } - `)([]Err{ - { - message: `There can be only one operation named "Foo".`, - locations: []Loc{ - {line: 2, column: 13}, - {line: 5, column: 16}, - }, - }, - }) - }) - - t.Run("multiple ops of same name of different types (subscription)", func(t *testing.T) { - ExpectErrors(t, ` - query Foo { - fieldA - } - subscription Foo { - fieldB - } - `)([]Err{ - { - message: `There can be only one operation named "Foo".`, - locations: []Loc{ - {line: 2, column: 13}, - {line: 5, column: 20}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueOperationTypesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueOperationTypesRule_test.go deleted file mode 100755 index a17b95e71..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueOperationTypesRule_test.go +++ /dev/null @@ -1,380 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueOperationTypesRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, UniqueOperationTypesRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Unique operation types", func(t *testing.T) { - t.Run("no schema definition", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - `) - }) - - t.Run("schema definition with all types", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - } - `) - }) - - t.Run("schema definition with single extension", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - - schema { query: Foo } - - extend schema { - mutation: Foo - subscription: Foo - } - `) - }) - - t.Run("schema definition with separate extensions", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - - schema { query: Foo } - extend schema { mutation: Foo } - extend schema { subscription: Foo } - `) - }) - - t.Run("extend schema before definition", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - - extend schema { mutation: Foo } - extend schema { subscription: Foo } - - schema { query: Foo } - `) - }) - - t.Run("duplicate operation types inside single schema definition", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - - query: Foo - mutation: Foo - subscription: Foo - } - `)([]Err{ - { - message: "There can be only one query type in schema.", - locations: []Loc{ - {line: 5, column: 9}, - {line: 9, column: 9}, - }, - }, - { - message: "There can be only one mutation type in schema.", - locations: []Loc{ - {line: 6, column: 9}, - {line: 10, column: 9}, - }, - }, - { - message: "There can be only one subscription type in schema.", - locations: []Loc{ - {line: 7, column: 9}, - {line: 11, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate operation types inside schema extension", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `)([]Err{ - { - message: "There can be only one query type in schema.", - locations: []Loc{ - {line: 5, column: 9}, - {line: 11, column: 9}, - }, - }, - { - message: "There can be only one mutation type in schema.", - locations: []Loc{ - {line: 6, column: 9}, - {line: 12, column: 9}, - }, - }, - { - message: "There can be only one subscription type in schema.", - locations: []Loc{ - {line: 7, column: 9}, - {line: 13, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate operation types inside schema extension twice", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Foo - - schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `)([]Err{ - { - message: "There can be only one query type in schema.", - locations: []Loc{ - {line: 5, column: 9}, - {line: 11, column: 9}, - }, - }, - { - message: "There can be only one mutation type in schema.", - locations: []Loc{ - {line: 6, column: 9}, - {line: 12, column: 9}, - }, - }, - { - message: "There can be only one subscription type in schema.", - locations: []Loc{ - {line: 7, column: 9}, - {line: 13, column: 9}, - }, - }, - { - message: "There can be only one query type in schema.", - locations: []Loc{ - {line: 5, column: 9}, - {line: 17, column: 9}, - }, - }, - { - message: "There can be only one mutation type in schema.", - locations: []Loc{ - {line: 6, column: 9}, - {line: 18, column: 9}, - }, - }, - { - message: "There can be only one subscription type in schema.", - locations: []Loc{ - {line: 7, column: 9}, - {line: 19, column: 9}, - }, - }, - }) - }) - - t.Run("duplicate operation types inside second schema extension", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Foo - - schema { - query: Foo - } - - extend schema { - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `)([]Err{ - { - message: "There can be only one query type in schema.", - locations: []Loc{ - {line: 5, column: 9}, - {line: 14, column: 9}, - }, - }, - { - message: "There can be only one mutation type in schema.", - locations: []Loc{ - {line: 9, column: 9}, - {line: 15, column: 9}, - }, - }, - { - message: "There can be only one subscription type in schema.", - locations: []Loc{ - {line: 10, column: 9}, - {line: 16, column: 9}, - }, - }, - }) - }) - - t.Run("define schema inside extension SDL", func(t *testing.T) { - schema := BuildSchema("type Foo") - sdl := ` - schema { - query: Foo - mutation: Foo - subscription: Foo - } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("define and extend schema inside extension SDL", func(t *testing.T) { - schema := BuildSchema("type Foo") - sdl := ` - schema { query: Foo } - extend schema { mutation: Foo } - extend schema { subscription: Foo } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("adding new operation types to existing schema", func(t *testing.T) { - schema := BuildSchema("type Query") - sdl := ` - extend schema { mutation: Foo } - extend schema { subscription: Foo } - ` - - ExpectValidSDL(t, sdl, schema) - }) - - t.Run("adding conflicting operation types to existing schema", func(t *testing.T) { - schema := BuildSchema(` - type Query - type Mutation - type Subscription - - type Foo - `) - - sdl := ` - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: "Type for query already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 3, column: 9}}, - }, - { - message: "Type for mutation already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 4, column: 9}}, - }, - { - message: "Type for subscription already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 5, column: 9}}, - }, - }) - }) - - t.Run("adding conflicting operation types to existing schema twice", func(t *testing.T) { - schema := BuildSchema(` - type Query - type Mutation - type Subscription - `) - - sdl := ` - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: "Type for query already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 3, column: 9}}, - }, - { - message: "Type for mutation already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 4, column: 9}}, - }, - { - message: "Type for subscription already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 5, column: 9}}, - }, - { - message: "Type for query already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 9, column: 9}}, - }, - { - message: "Type for mutation already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 10, column: 9}}, - }, - { - message: "Type for subscription already defined in the schema. It cannot be redefined.", - locations: []Loc{{line: 11, column: 9}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueTypeNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueTypeNamesRule_test.go deleted file mode 100755 index 4c336949f..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueTypeNamesRule_test.go +++ /dev/null @@ -1,161 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueTypeNamesRule(t *testing.T) { - t.Skip() - - ExpectSDLErrors := func(t *testing.T, sdlStr string, schemas ...string) ResultCompare { - schema := "" - if len(schemas) > 0 { - schema = schemas[0] - } - return ExpectSDLValidationErrors(t, schema, UniqueTypeNamesRule, sdlStr) - } - - ExpectValidSDL := func(t *testing.T, sdlStr string, schemas ...string) { - ExpectSDLErrors(t, sdlStr, schemas...)([]Err{}) - } - - t.Run("Validate: Unique type names", func(t *testing.T) { - t.Run("no types", func(t *testing.T) { - ExpectValidSDL(t, ` - directive @test on SCHEMA - `) - }) - - t.Run("one type", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - `) - }) - - t.Run("many types", func(t *testing.T) { - ExpectValidSDL(t, ` - type Foo - type Bar - type Baz - `) - }) - - t.Run("type and non-type definitions named the same", func(t *testing.T) { - ExpectValidSDL(t, ` - query Foo { __typename } - fragment Foo on Query { __typename } - directive @Foo on SCHEMA - - type Foo - `) - }) - - t.Run("types named the same", func(t *testing.T) { - ExpectSDLErrors(t, ` - type Foo - - scalar Foo - type Foo - interface Foo - union Foo - enum Foo - input Foo - `)([]Err{ - { - message: `There can be only one type named "Foo".`, - locations: []Loc{ - {line: 2, column: 12}, - {line: 4, column: 14}, - }, - }, - { - message: `There can be only one type named "Foo".`, - locations: []Loc{ - {line: 2, column: 12}, - {line: 5, column: 12}, - }, - }, - { - message: `There can be only one type named "Foo".`, - locations: []Loc{ - {line: 2, column: 12}, - {line: 6, column: 17}, - }, - }, - { - message: `There can be only one type named "Foo".`, - locations: []Loc{ - {line: 2, column: 12}, - {line: 7, column: 13}, - }, - }, - { - message: `There can be only one type named "Foo".`, - locations: []Loc{ - {line: 2, column: 12}, - {line: 8, column: 12}, - }, - }, - { - message: `There can be only one type named "Foo".`, - locations: []Loc{ - {line: 2, column: 12}, - {line: 9, column: 13}, - }, - }, - }) - }) - - t.Run("adding new type to existing schema", func(t *testing.T) { - schema := BuildSchema("type Foo") - - ExpectValidSDL(t, "type Bar", schema) - }) - - t.Run("adding new type to existing schema with same-named directive", func(t *testing.T) { - schema := BuildSchema("directive @Foo on SCHEMA") - - ExpectValidSDL(t, "type Foo", schema) - }) - - t.Run("adding conflicting types to existing schema", func(t *testing.T) { - schema := BuildSchema("type Foo") - sdl := ` - scalar Foo - type Foo - interface Foo - union Foo - enum Foo - input Foo - ` - - ExpectSDLErrors(t, sdl, schema)([]Err{ - { - message: `Type "Foo" already exists in the schema. It cannot also be defined in this type definition.`, - locations: []Loc{{line: 2, column: 14}}, - }, - { - message: `Type "Foo" already exists in the schema. It cannot also be defined in this type definition.`, - locations: []Loc{{line: 3, column: 12}}, - }, - { - message: `Type "Foo" already exists in the schema. It cannot also be defined in this type definition.`, - locations: []Loc{{line: 4, column: 17}}, - }, - { - message: `Type "Foo" already exists in the schema. It cannot also be defined in this type definition.`, - locations: []Loc{{line: 5, column: 13}}, - }, - { - message: `Type "Foo" already exists in the schema. It cannot also be defined in this type definition.`, - locations: []Loc{{line: 6, column: 12}}, - }, - { - message: `Type "Foo" already exists in the schema. It cannot also be defined in this type definition.`, - locations: []Loc{{line: 7, column: 13}}, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/UniqueVariableNamesRule_test.go b/pkg/astvalidation/reference/testsgo/UniqueVariableNamesRule_test.go deleted file mode 100755 index 9b2d0ae80..000000000 --- a/pkg/astvalidation/reference/testsgo/UniqueVariableNamesRule_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestUniqueVariableNamesRule(t *testing.T) { - t.Skip() - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, UniqueVariableNamesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Unique variable names", func(t *testing.T) { - t.Run("unique variable names", func(t *testing.T) { - ExpectValid(t, ` - query A($x: Int, $y: String) { __typename } - query B($x: String, $y: Int) { __typename } - `) - }) - - t.Run("duplicate variable names", func(t *testing.T) { - ExpectErrors(t, ` - query A($x: Int, $x: Int, $x: String) { __typename } - query B($x: String, $x: Int) { __typename } - query C($x: Int, $x: Int) { __typename } - `)([]Err{ - { - message: `There can be only one variable named "$x".`, - locations: []Loc{ - {line: 2, column: 16}, - {line: 2, column: 25}, - }, - }, - { - message: `There can be only one variable named "$x".`, - locations: []Loc{ - {line: 2, column: 16}, - {line: 2, column: 34}, - }, - }, - { - message: `There can be only one variable named "$x".`, - locations: []Loc{ - {line: 3, column: 16}, - {line: 3, column: 28}, - }, - }, - { - message: `There can be only one variable named "$x".`, - locations: []Loc{ - {line: 4, column: 16}, - {line: 4, column: 25}, - }, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/ValuesOfCorrectTypeRule_test.go b/pkg/astvalidation/reference/testsgo/ValuesOfCorrectTypeRule_test.go deleted file mode 100755 index 350011c96..000000000 --- a/pkg/astvalidation/reference/testsgo/ValuesOfCorrectTypeRule_test.go +++ /dev/null @@ -1,1129 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestValuesOfCorrectTypeRule(t *testing.T) { - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, ValuesOfCorrectTypeRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Values of correct type", func(t *testing.T) { - t.Run("Valid values", func(t *testing.T) { - t.Run("Good int value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - intArgField(intArg: 2) - } - } - `) - }) - - t.Run("Good negative int value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - intArgField(intArg: -2) - } - } - `) - }) - - t.Run("Good boolean value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - booleanArgField(booleanArg: true) - } - } - `) - }) - - t.Run("Good string value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - stringArgField(stringArg: "foo") - } - } - `) - }) - - t.Run("Good float value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - floatArgField(floatArg: 1.1) - } - } - `) - }) - - t.Run("Good negative float value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - floatArgField(floatArg: -1.1) - } - } - `) - }) - - t.Run("Int into Float", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - floatArgField(floatArg: 1) - } - } - `) - }) - - t.Run("Int into ID", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - idArgField(idArg: 1) - } - } - `) - }) - - t.Run("String into ID", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - idArgField(idArg: "someIdString") - } - } - `) - }) - - t.Run("Good enum value", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - doesKnowCommand(dogCommand: SIT) - } - } - `) - }) - - t.Run("Enum with undefined value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - enumArgField(enumArg: UNKNOWN) - } - } - `) - }) - - t.Run("Enum with null value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - enumArgField(enumArg: NO_FUR) - } - } - `) - }) - - t.Run("null into nullable type", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - intArgField(intArg: null) - } - } - `) - - ExpectValid(t, ` - { - dog(a: null, b: null, c:{ requiredField: true, intField: null }) { - name - } - } - `) - }) - }) - - t.Run("Invalid String values", func(t *testing.T) { - t.Run("Int into String", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - stringArgField(stringArg: 1) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: 1", - locations: []Loc{{line: 4, column: 39}}, - }, - }) - }) - - t.Run("Float into String", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - stringArgField(stringArg: 1.0) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: 1.0", - locations: []Loc{{line: 4, column: 39}}, - }, - }) - }) - - t.Run("Boolean into String", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - stringArgField(stringArg: true) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: true", - locations: []Loc{{line: 4, column: 39}}, - }, - }) - }) - - t.Run("Unquoted String into String", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - stringArgField(stringArg: BAR) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: BAR", - locations: []Loc{{line: 4, column: 39}}, - }, - }) - }) - }) - - t.Run("Invalid Int values", func(t *testing.T) { - t.Run("String into Int", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - intArgField(intArg: "3") - } - } - `)([]Err{ - { - message: `Int cannot represent non-integer value: "3"`, - locations: []Loc{{line: 4, column: 33}}, - }, - }) - }) - - t.Run("Big Int into Int", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - intArgField(intArg: 829384293849283498239482938) - } - } - `)([]Err{ - { - message: "Int cannot represent non 32-bit signed integer value: 829384293849283498239482938", - locations: []Loc{{line: 4, column: 33}}, - }, - }) - }) - - t.Run("Unquoted String into Int", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - intArgField(intArg: FOO) - } - } - `)([]Err{ - { - message: "Int cannot represent non-integer value: FOO", - locations: []Loc{{line: 4, column: 33}}, - }, - }) - }) - - t.Run("Simple Float into Int", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - intArgField(intArg: 3.0) - } - } - `)([]Err{ - { - message: "Int cannot represent non-integer value: 3.0", - locations: []Loc{{line: 4, column: 33}}, - }, - }) - }) - - t.Run("Float into Int", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - intArgField(intArg: 3.333) - } - } - `)([]Err{ - { - message: "Int cannot represent non-integer value: 3.333", - locations: []Loc{{line: 4, column: 33}}, - }, - }) - }) - }) - - t.Run("Invalid Float values", func(t *testing.T) { - t.Run("String into Float", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - floatArgField(floatArg: "3.333") - } - } - `)([]Err{ - { - message: `Float cannot represent non numeric value: "3.333"`, - locations: []Loc{{line: 4, column: 37}}, - }, - }) - }) - - t.Run("Boolean into Float", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - floatArgField(floatArg: true) - } - } - `)([]Err{ - { - message: "Float cannot represent non numeric value: true", - locations: []Loc{{line: 4, column: 37}}, - }, - }) - }) - - t.Run("Unquoted into Float", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - floatArgField(floatArg: FOO) - } - } - `)([]Err{ - { - message: "Float cannot represent non numeric value: FOO", - locations: []Loc{{line: 4, column: 37}}, - }, - }) - }) - }) - - t.Run("Invalid Boolean value", func(t *testing.T) { - t.Run("Int into Boolean", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - booleanArgField(booleanArg: 2) - } - } - `)([]Err{ - { - message: "Boolean cannot represent a non boolean value: 2", - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Float into Boolean", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - booleanArgField(booleanArg: 1.0) - } - } - `)([]Err{ - { - message: "Boolean cannot represent a non boolean value: 1.0", - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("String into Boolean", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - booleanArgField(booleanArg: "true") - } - } - `)([]Err{ - { - message: `Boolean cannot represent a non boolean value: "true"`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Unquoted into Boolean", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - booleanArgField(booleanArg: TRUE) - } - } - `)([]Err{ - { - message: "Boolean cannot represent a non boolean value: TRUE", - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - }) - - t.Run("Invalid ID value", func(t *testing.T) { - t.Run("Float into ID", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - idArgField(idArg: 1.0) - } - } - `)([]Err{ - { - message: "ID cannot represent a non-string and non-integer value: 1.0", - locations: []Loc{{line: 4, column: 31}}, - }, - }) - }) - - t.Run("Boolean into ID", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - idArgField(idArg: true) - } - } - `)([]Err{ - { - message: "ID cannot represent a non-string and non-integer value: true", - locations: []Loc{{line: 4, column: 31}}, - }, - }) - }) - - t.Run("Unquoted into ID", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - idArgField(idArg: SOMETHING) - } - } - `)([]Err{ - { - message: "ID cannot represent a non-string and non-integer value: SOMETHING", - locations: []Loc{{line: 4, column: 31}}, - }, - }) - }) - }) - - t.Run("Invalid Enum value", func(t *testing.T) { - t.Run("Int into Enum", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: 2) - } - } - `)([]Err{ - { - message: `Enum "DogCommand" cannot represent non-enum value: 2.`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Float into Enum", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: 1.0) - } - } - `)([]Err{ - { - message: `Enum "DogCommand" cannot represent non-enum value: 1.0.`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("String into Enum", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: "SIT") - } - } - `)([]Err{ - { - message: `Enum "DogCommand" cannot represent non-enum value: "SIT".`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("String into Enum with suggestions", func(t *testing.T) { - t.Skip(NotSupportedSuggestionsSkipMsg) - - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: "SIT") - } - } - `)([]Err{ - { - message: `Enum "DogCommand" cannot represent non-enum value: "SIT". Did you mean the enum value "SIT"?`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Boolean into Enum", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: true) - } - } - `)([]Err{ - { - message: `Enum "DogCommand" cannot represent non-enum value: true.`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Unknown Enum Value into Enum", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: JUGGLE) - } - } - `)([]Err{ - { - message: `Value "JUGGLE" does not exist in "DogCommand" enum.`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Different case Enum Value into Enum", func(t *testing.T) { - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: sit) - } - } - `)([]Err{ - { - message: `Value "sit" does not exist in "DogCommand" enum.`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Different case Enum Value into Enum with suggestions", func(t *testing.T) { - t.Skip(NotSupportedSuggestionsSkipMsg) - - ExpectErrors(t, ` - { - dog { - doesKnowCommand(dogCommand: sit) - } - } - `)([]Err{ - { - message: `Value "sit" does not exist in "DogCommand" enum. Did you mean the enum value "SIT"?`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - }) - - t.Run("Valid List value", func(t *testing.T) { - t.Run("Good list value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - stringListArgField(stringListArg: ["one", null, "two"]) - } - } - `) - }) - - t.Run("Empty list value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - stringListArgField(stringListArg: []) - } - } - `) - }) - - t.Run("Null value", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - stringListArgField(stringListArg: null) - } - } - `) - }) - - t.Run("Single value into List", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - stringListArgField(stringListArg: "one") - } - } - `) - }) - }) - - t.Run("Invalid List value", func(t *testing.T) { - t.Run("Incorrect item type", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - stringListArgField(stringListArg: ["one", 2]) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: 2", - locations: []Loc{{line: 4, column: 55}}, - }, - }) - }) - - t.Run("Single value of incorrect type", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - stringListArgField(stringListArg: 1) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: 1", - locations: []Loc{{line: 4, column: 47}}, - }, - }) - }) - }) - - t.Run("Valid non-nullable value", func(t *testing.T) { - t.Run("Arg on optional arg", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - isHouseTrained(atOtherHomes: true) - } - } - `) - }) - - t.Run("No Arg on optional arg", func(t *testing.T) { - ExpectValid(t, ` - { - dog { - isHouseTrained - } - } - `) - }) - - t.Run("Multiple args", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleReqs(req1: 1, req2: 2) - } - } - `) - }) - - t.Run("Multiple args reverse order", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleReqs(req2: 2, req1: 1) - } - } - `) - }) - - t.Run("No args on multiple optional", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOpts - } - } - `) - }) - - t.Run("One arg on multiple optional", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOpts(opt1: 1) - } - } - `) - }) - - t.Run("Second arg on multiple optional", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOpts(opt2: 1) - } - } - `) - }) - - t.Run("Multiple required args on mixedList", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4) - } - } - `) - }) - - t.Run("Multiple required and one optional arg on mixedList", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5) - } - } - `) - }) - - t.Run("All required and optional args on mixedList", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) - } - } - `) - }) - }) - - t.Run("Invalid non-nullable value", func(t *testing.T) { - t.Run("Incorrect value type", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - multipleReqs(req2: "two", req1: "one") - } - } - `)([]Err{ - { - message: `Int cannot represent non-integer value: "two"`, - locations: []Loc{{line: 4, column: 32}}, - }, - { - message: `Int cannot represent non-integer value: "one"`, - locations: []Loc{{line: 4, column: 45}}, - }, - }) - }) - - t.Run("Incorrect value and missing argument (ProvidedRequiredArgumentsRule)", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - multipleReqs(req1: "one") - } - } - `)([]Err{ - { - message: `Int cannot represent non-integer value: "one"`, - locations: []Loc{{line: 4, column: 32}}, - }, - }) - }) - - t.Run("Null value", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - multipleReqs(req1: null) - } - } - `)([]Err{ - { - message: `Expected value of type "Int!", found null.`, - locations: []Loc{{line: 4, column: 32}}, - }, - }) - }) - }) - - t.Run("Valid input object value", func(t *testing.T) { - t.Run("Optional arg, despite required field in type", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - complexArgField - } - } - `) - }) - - t.Run("Partial object, only required", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - complexArgField(complexArg: { requiredField: true }) - } - } - `) - }) - - t.Run("Partial object, required field can be falsy", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - complexArgField(complexArg: { requiredField: false }) - } - } - `) - }) - - t.Run("Partial object, including required", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - complexArgField(complexArg: { requiredField: true, intField: 4 }) - } - } - `) - }) - - t.Run("Full object", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - intField: 4, - stringField: "foo", - booleanField: false, - stringListField: ["one", "two"] - }) - } - } - `) - }) - - t.Run("Full object with fields in different order", func(t *testing.T) { - ExpectValid(t, ` - { - complicatedArgs { - complexArgField(complexArg: { - stringListField: ["one", "two"], - booleanField: false, - requiredField: true, - stringField: "foo", - intField: 4, - }) - } - } - `) - }) - }) - - t.Run("Invalid input object value", func(t *testing.T) { - t.Run("Partial object, missing required", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - complexArgField(complexArg: { intField: 4 }) - } - } - `)([]Err{ - { - message: `Field "ComplexInput.requiredField" of required type "Boolean!" was not provided.`, - locations: []Loc{{line: 4, column: 41}}, - }, - }) - }) - - t.Run("Partial object, invalid field type", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - complexArgField(complexArg: { - stringListField: ["one", 2], - requiredField: true, - }) - } - } - `)([]Err{ - { - message: "String cannot represent a non string value: 2", - locations: []Loc{{line: 5, column: 40}}, - }, - }) - }) - - t.Run("Partial object, null to non-null field", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - nonNullField: null, - }) - } - } - `)([]Err{ - { - message: `Expected value of type "Boolean!", found null.`, - locations: []Loc{{line: 6, column: 29}}, - }, - }) - }) - - t.Run("Partial object, unknown field arg", func(t *testing.T) { - ExpectErrors(t, ` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - invalidField: "value" - }) - } - } - `)([]Err{ - { - message: `Field "invalidField" is not defined by type "ComplexInput".`, - locations: []Loc{{line: 6, column: 15}}, - }, - }) - }) - - t.Run("Partial object, unknown field arg with suggestions", func(t *testing.T) { - t.Skip(NotSupportedSuggestionsSkipMsg) - - ExpectErrors(t, ` - { - complicatedArgs { - complexArgField(complexArg: { - requiredField: true, - invalidField: "value" - }) - } - } - `)([]Err{ - { - message: `Field "invalidField" is not defined by type "ComplexInput". Did you mean "intField"?`, - locations: []Loc{{line: 6, column: 15}}, - }, - }) - }) - - }) - - t.Run("Directive arguments", func(t *testing.T) { - t.Run("with directives of valid types", func(t *testing.T) { - ExpectValid(t, ` - { - dog @include(if: true) { - name - } - human @skip(if: false) { - name - } - } - `) - }) - - t.Run("with directive with incorrect types", func(t *testing.T) { - ExpectErrors(t, ` - { - dog @include(if: "yes") { - name @skip(if: ENUM) - } - } - `)([]Err{ - { - message: `Boolean cannot represent a non boolean value: "yes"`, - locations: []Loc{{line: 3, column: 28}}, - }, - { - message: "Boolean cannot represent a non boolean value: ENUM", - locations: []Loc{{line: 4, column: 28}}, - }, - }) - }) - }) - - t.Run("Variable default values", func(t *testing.T) { - t.Run("variables with valid default values", func(t *testing.T) { - ExpectValid(t, ` - query WithDefaultValues( - $a: Int = 1, - $b: String = "ok", - $c: ComplexInput = { requiredField: true, intField: 3 } - $d: Int! = 123 - ) { - dog { name } - } - `) - }) - - t.Run("variables with valid default null values", func(t *testing.T) { - ExpectValid(t, ` - query WithDefaultValues( - $a: Int = null, - $b: String = null, - $c: ComplexInput = { requiredField: true, intField: null } - ) { - dog { name } - } - `) - }) - - t.Run("variables with invalid default null values", func(t *testing.T) { - ExpectErrors(t, ` - query WithDefaultValues( - $a: Int! = null, - $b: String! = null, - $c: ComplexInput = { requiredField: null, intField: null } - ) { - dog { name } - } - `)([]Err{ - { - message: `Expected value of type "Int!", found null.`, - locations: []Loc{{line: 3, column: 22}}, - }, - { - message: `Expected value of type "String!", found null.`, - locations: []Loc{{line: 4, column: 25}}, - }, - { - message: `Expected value of type "Boolean!", found null.`, - locations: []Loc{{line: 5, column: 47}}, - }, - }) - }) - - t.Run("variables with invalid default values", func(t *testing.T) { - ExpectErrors(t, ` - query InvalidDefaultValues( - $a: Int = "one", - $b: String = 4, - $c: ComplexInput = "NotVeryComplex" - ) { - dog { name } - } - `)([]Err{ - { - message: `Int cannot represent non-integer value: "one"`, - locations: []Loc{{line: 3, column: 21}}, - }, - { - message: "String cannot represent a non string value: 4", - locations: []Loc{{line: 4, column: 24}}, - }, - { - message: `Expected value of type "ComplexInput", found "NotVeryComplex".`, - locations: []Loc{{line: 5, column: 30}}, - }, - }) - }) - - t.Run("variables with complex invalid default values", func(t *testing.T) { - ExpectErrors(t, ` - query WithDefaultValues( - $a: ComplexInput = { requiredField: 123, intField: "abc" } - ) { - dog { name } - } - `)([]Err{ - { - message: "Boolean cannot represent a non boolean value: 123", - locations: []Loc{{line: 3, column: 47}}, - }, - { - message: `Int cannot represent non-integer value: "abc"`, - locations: []Loc{{line: 3, column: 62}}, - }, - }) - }) - - t.Run("complex variables missing required field", func(t *testing.T) { - ExpectErrors(t, ` - query MissingRequiredField($a: ComplexInput = {intField: 3}) { - dog { name } - } - `)([]Err{ - { - message: `Field "ComplexInput.requiredField" of required type "Boolean!" was not provided.`, - locations: []Loc{{line: 2, column: 55}}, - }, - }) - }) - - t.Run("list variables with invalid item", func(t *testing.T) { - ExpectErrors(t, ` - query InvalidItem($a: [String] = ["one", 2]) { - dog { name } - } - `)([]Err{ - { - message: "String cannot represent a non string value: 2", - locations: []Loc{{line: 2, column: 50}}, - }, - }) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/VariablesAreInputTypesRule_test.go b/pkg/astvalidation/reference/testsgo/VariablesAreInputTypesRule_test.go deleted file mode 100755 index b0b24b9bd..000000000 --- a/pkg/astvalidation/reference/testsgo/VariablesAreInputTypesRule_test.go +++ /dev/null @@ -1,48 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestVariablesAreInputTypesRule(t *testing.T) { - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, VariablesAreInputTypesRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Variables are input types", func(t *testing.T) { - t.Run("input types are valid", func(t *testing.T) { - ExpectValid(t, ` - query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { - field(a: $a, b: $b, c: $c) - } - `) - }) - - t.Run("output types are invalid", func(t *testing.T) { - ExpectErrors(t, ` - query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { - field(a: $a, b: $b, c: $c) - } - `)([]Err{ - { - locations: []Loc{{line: 2, column: 21}}, - message: `Variable "$a" cannot be non-input type "Dog".`, - }, - { - locations: []Loc{{line: 2, column: 30}}, - message: `Variable "$b" cannot be non-input type "[[CatOrDog!]]!".`, - }, - { - locations: []Loc{{line: 2, column: 50}}, - message: `Variable "$c" cannot be non-input type "Pet".`, - }, - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/VariablesInAllowedPositionRule_test.go b/pkg/astvalidation/reference/testsgo/VariablesInAllowedPositionRule_test.go deleted file mode 100755 index c5415c958..000000000 --- a/pkg/astvalidation/reference/testsgo/VariablesInAllowedPositionRule_test.go +++ /dev/null @@ -1,355 +0,0 @@ -package testsgo - -import ( - "testing" -) - -func TestVariablesInAllowedPositionRule(t *testing.T) { - - ExpectErrors := func(t *testing.T, queryStr string) ResultCompare { - return ExpectValidationErrors(t, VariablesInAllowedPositionRule, queryStr) - } - - ExpectValid := func(t *testing.T, queryStr string) { - ExpectErrors(t, queryStr)([]Err{}) - } - - t.Run("Validate: Variables are in allowed positions", func(t *testing.T) { - t.Run("Boolean => Boolean", func(t *testing.T) { - ExpectValid(t, ` - query Query($booleanArg: Boolean) - { - complicatedArgs { - booleanArgField(booleanArg: $booleanArg) - } - } - `) - }) - - t.Run("Boolean => Boolean within fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment booleanArgFrag on ComplicatedArgs { - booleanArgField(booleanArg: $booleanArg) - } - query Query($booleanArg: Boolean) - { - complicatedArgs { - ...booleanArgFrag - } - } - `) - - ExpectValid(t, ` - query Query($booleanArg: Boolean) - { - complicatedArgs { - ...booleanArgFrag - } - } - fragment booleanArgFrag on ComplicatedArgs { - booleanArgField(booleanArg: $booleanArg) - } - `) - }) - - t.Run("Boolean! => Boolean", func(t *testing.T) { - ExpectValid(t, ` - query Query($nonNullBooleanArg: Boolean!) - { - complicatedArgs { - booleanArgField(booleanArg: $nonNullBooleanArg) - } - } - `) - }) - - t.Run("Boolean! => Boolean within fragment", func(t *testing.T) { - ExpectValid(t, ` - fragment booleanArgFrag on ComplicatedArgs { - booleanArgField(booleanArg: $nonNullBooleanArg) - } - - query Query($nonNullBooleanArg: Boolean!) - { - complicatedArgs { - ...booleanArgFrag - } - } - `) - }) - - t.Run("[String] => [String]", func(t *testing.T) { - ExpectValid(t, ` - query Query($stringListVar: [String]) - { - complicatedArgs { - stringListArgField(stringListArg: $stringListVar) - } - } - `) - }) - - t.Run("[String!] => [String]", func(t *testing.T) { - ExpectValid(t, ` - query Query($stringListVar: [String!]) - { - complicatedArgs { - stringListArgField(stringListArg: $stringListVar) - } - } - `) - }) - - t.Run("String => [String] in item position", func(t *testing.T) { - ExpectValid(t, ` - query Query($stringVar: String) - { - complicatedArgs { - stringListArgField(stringListArg: [$stringVar]) - } - } - `) - }) - - t.Run("String! => [String] in item position", func(t *testing.T) { - ExpectValid(t, ` - query Query($stringVar: String!) - { - complicatedArgs { - stringListArgField(stringListArg: [$stringVar]) - } - } - `) - }) - - t.Run("ComplexInput => ComplexInput", func(t *testing.T) { - ExpectValid(t, ` - query Query($complexVar: ComplexInput) - { - complicatedArgs { - complexArgField(complexArg: $complexVar) - } - } - `) - }) - - t.Run("ComplexInput => ComplexInput in field position", func(t *testing.T) { - ExpectValid(t, ` - query Query($boolVar: Boolean = false) - { - complicatedArgs { - complexArgField(complexArg: {requiredField: $boolVar}) # requiredArg is not exists in complex input - } - } - `) - }) - - t.Run("Boolean! => Boolean! in directive", func(t *testing.T) { - ExpectValid(t, ` - query Query($boolVar: Boolean!) - { - dog @include(if: $boolVar) - } - `) - }) - - t.Run("Int => Int!", func(t *testing.T) { - ExpectErrors(t, ` - query Query($intArg: Int) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - } - `)([]Err{ - { - message: `Variable "$intArg" of type "Int" used in position expecting type "Int!".`, - locations: []Loc{ - {line: 2, column: 19}, - {line: 4, column: 45}, - }, - }, - }) - }) - - t.Run("Int => Int! within fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment nonNullIntArgFieldFrag on ComplicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - - query Query($intArg: Int) { - complicatedArgs { - ...nonNullIntArgFieldFrag - } - } - `)([]Err{ - { - message: `Variable "$intArg" of type "Int" used in position expecting type "Int!".`, - locations: []Loc{ - {line: 6, column: 19}, - {line: 3, column: 43}, - }, - }, - }) - }) - - t.Run("Int => Int! within nested fragment", func(t *testing.T) { - ExpectErrors(t, ` - fragment outerFrag on ComplicatedArgs { - ...nonNullIntArgFieldFrag - } - - fragment nonNullIntArgFieldFrag on ComplicatedArgs { - nonNullIntArgField(nonNullIntArg: $intArg) - } - - query Query($intArg: Int) { - complicatedArgs { - ...outerFrag - } - } - `)([]Err{ - { - message: `Variable "$intArg" of type "Int" used in position expecting type "Int!".`, - locations: []Loc{ - {line: 10, column: 19}, - {line: 7, column: 43}, - }, - }, - }) - }) - - t.Run("String over Boolean", func(t *testing.T) { - ExpectErrors(t, ` - query Query($stringVar: String) { - complicatedArgs { - booleanArgField(booleanArg: $stringVar) - } - } - `)([]Err{ - { - message: `Variable "$stringVar" of type "String" used in position expecting type "Boolean".`, - locations: []Loc{ - {line: 2, column: 19}, - {line: 4, column: 39}, - }, - }, - }) - }) - - t.Run("String => [String]", func(t *testing.T) { - ExpectErrors(t, ` - query Query($stringVar: String) { - complicatedArgs { - stringListArgField(stringListArg: $stringVar) - } - } - `)([]Err{ - { - message: `Variable "$stringVar" of type "String" used in position expecting type "[String]".`, - locations: []Loc{ - {line: 2, column: 19}, - {line: 4, column: 45}, - }, - }, - }) - }) - - t.Run("Boolean => Boolean! in directive", func(t *testing.T) { - ExpectErrors(t, ` - query Query($boolVar: Boolean) { - dog @include(if: $boolVar) - } - `)([]Err{ - { - message: `Variable "$boolVar" of type "Boolean" used in position expecting type "Boolean!".`, - locations: []Loc{ - {line: 2, column: 19}, - {line: 3, column: 26}, - }, - }, - }) - }) - - t.Run("String => Boolean! in directive", func(t *testing.T) { - ExpectErrors(t, ` - query Query($stringVar: String) { - dog @include(if: $stringVar) - } - `)([]Err{ - { - message: `Variable "$stringVar" of type "String" used in position expecting type "Boolean!".`, - locations: []Loc{ - {line: 2, column: 19}, - {line: 3, column: 26}, - }, - }, - }) - }) - - t.Run("[String] => [String!]", func(t *testing.T) { - ExpectErrors(t, ` - query Query($stringListVar: [String]) - { - complicatedArgs { - stringListNonNullArgField(stringListNonNullArg: $stringListVar) - } - } - `)([]Err{ - { - message: `Variable "$stringListVar" of type "[String]" used in position expecting type "[String!]".`, - locations: []Loc{ - {line: 2, column: 19}, - {line: 5, column: 59}, - }, - }, - }) - }) - - t.Run("Allows optional (nullable) variables with default values", func(t *testing.T) { - t.Run("Int => Int! fails when variable provides null default value", func(t *testing.T) { - ExpectErrors(t, ` - query Query($intVar: Int = null) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intVar) - } - } - `)([]Err{ - { - message: `Variable "$intVar" of type "Int" used in position expecting type "Int!".`, - locations: []Loc{ - {line: 2, column: 21}, - {line: 4, column: 47}, - }, - }, - }) - }) - - t.Run("Int => Int! when variable provides non-null default value", func(t *testing.T) { - ExpectValid(t, ` - query Query($intVar: Int = 1) { - complicatedArgs { - nonNullIntArgField(nonNullIntArg: $intVar) - } - }`) - }) - - t.Run("Int => Int! when optional argument provides default value", func(t *testing.T) { - ExpectValid(t, ` - query Query($intVar: Int) { - complicatedArgs { - nonNullFieldWithDefault(nonNullIntArg: $intVar) - } - }`) - }) - - t.Run("Boolean => Boolean! in directive with default value with option", func(t *testing.T) { - ExpectValid(t, ` - query Query($boolVar: Boolean = false) { - dog @include(if: $boolVar) - }`) - }) - }) - }) - -} diff --git a/pkg/astvalidation/reference/testsgo/harness_test.go b/pkg/astvalidation/reference/testsgo/harness_test.go deleted file mode 100644 index 4c8c95fe5..000000000 --- a/pkg/astvalidation/reference/testsgo/harness_test.go +++ /dev/null @@ -1,323 +0,0 @@ -package testsgo - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const ( - NotSupportedSuggestionsSkipMsg = "Suggestions is not supported" - - RuleHasNoMapping = `Validation rule: "%s" has no mapped rule` -) - -const ( - ExecutableDefinitionsRule = "ExecutableDefinitionsRule" - FieldsOnCorrectTypeRule = "FieldsOnCorrectTypeRule" - KnownArgumentNamesRule = "KnownArgumentNamesRule" - KnownArgumentNamesOnDirectivesRule = "KnownArgumentNamesOnDirectivesRule" - KnownDirectivesRule = "KnownDirectivesRule" - KnownTypeNamesRule = "KnownTypeNamesRule" - KnownTypeNamesOperationRule = "KnownTypeNamesOperationRule" - LoneAnonymousOperationRule = "LoneAnonymousOperationRule" - NoUndefinedVariablesRule = "NoUndefinedVariablesRule" - NoUnusedVariablesRule = "NoUnusedVariablesRule" - OverlappingFieldsCanBeMergedRule = "OverlappingFieldsCanBeMergedRule" - ProvidedRequiredArgumentsRule = "ProvidedRequiredArgumentsRule" - ProvidedRequiredArgumentsOnDirectivesRule = "ProvidedRequiredArgumentsOnDirectivesRule" - SingleFieldSubscriptionsRule = "SingleFieldSubscriptionsRule" - UniqueArgumentNamesRule = "UniqueArgumentNamesRule" - UniqueDirectivesPerLocationRule = "UniqueDirectivesPerLocationRule" - UniqueEnumValueNamesRule = "UniqueEnumValueNamesRule" - UniqueFieldDefinitionNamesRule = "UniqueFieldDefinitionNamesRule" - UniqueOperationNamesRule = "UniqueOperationNamesRule" - UniqueOperationTypesRule = "UniqueOperationTypesRule" - UniqueTypeNamesRule = "UniqueTypeNamesRule" - UniqueVariableNamesRule = "UniqueVariableNamesRule" - ValuesOfCorrectTypeRule = "ValuesOfCorrectTypeRule" - VariablesAreInputTypesRule = "VariablesAreInputTypesRule" - VariablesInAllowedPositionRule = "VariablesInAllowedPositionRule" - - FragmentsOnCompositeTypesRule = "FragmentsOnCompositeTypesRule" - KnownFragmentNamesRule = "KnownFragmentNamesRule" - NoFragmentCyclesRule = "NoFragmentCyclesRule" - NoUnusedFragmentsRule = "NoUnusedFragmentsRule" - PossibleFragmentSpreadsRule = "PossibleFragmentSpreadsRule" - UniqueFragmentNamesRule = "UniqueFragmentNamesRule" - - UniqueInputFieldNamesRule = "UniqueInputFieldNamesRule" - UniqueDirectiveNamesRule = "UniqueDirectiveNamesRule" - LoneSchemaDefinitionRule = "LoneSchemaDefinitionRule" - ScalarLeafsRule = "ScalarLeafsRule" - PossibleTypeExtensionsRule = "PossibleTypeExtensionsRule" -) - -var rulesMap = map[string][]astvalidation.Rule{ - ExecutableDefinitionsRule: {astvalidation.DocumentContainsExecutableOperation()}, - FieldsOnCorrectTypeRule: {astvalidation.FieldSelections()}, - KnownArgumentNamesRule: {astvalidation.KnownArguments()}, - KnownArgumentNamesOnDirectivesRule: {}, - KnownDirectivesRule: {astvalidation.DirectivesAreDefined()}, - KnownTypeNamesRule: {astvalidation.KnownTypeNames()}, - LoneAnonymousOperationRule: {astvalidation.LoneAnonymousOperation()}, - NoUndefinedVariablesRule: {astvalidation.AllVariableUsesDefined()}, - NoUnusedVariablesRule: {astvalidation.AllVariablesUsed()}, - OverlappingFieldsCanBeMergedRule: {astvalidation.FieldSelectionMerging()}, - ProvidedRequiredArgumentsRule: {astvalidation.RequiredArguments()}, - ProvidedRequiredArgumentsOnDirectivesRule: {}, - SingleFieldSubscriptionsRule: {astvalidation.SubscriptionSingleRootField()}, - UniqueArgumentNamesRule: {astvalidation.ArgumentUniqueness()}, - UniqueDirectivesPerLocationRule: {astvalidation.DirectivesAreUniquePerLocation()}, - UniqueEnumValueNamesRule: {astvalidation.UniqueEnumValueNames()}, - UniqueFieldDefinitionNamesRule: {astvalidation.UniqueFieldDefinitionNames()}, - UniqueOperationNamesRule: {astvalidation.OperationNameUniqueness()}, - UniqueOperationTypesRule: {astvalidation.UniqueOperationTypes()}, - UniqueTypeNamesRule: {astvalidation.UniqueTypeNames()}, - UniqueVariableNamesRule: {astvalidation.VariableUniqueness()}, - ValuesOfCorrectTypeRule: {astvalidation.Values()}, - VariablesAreInputTypesRule: {astvalidation.VariablesAreInputTypes()}, - KnownTypeNamesOperationRule: {astvalidation.VariablesAreInputTypes(), astvalidation.Fragments()}, - VariablesInAllowedPositionRule: {astvalidation.ValidArguments(), astvalidation.Values()}, - - // fragments rules - FragmentsOnCompositeTypesRule: {astvalidation.Fragments()}, - KnownFragmentNamesRule: {astvalidation.Fragments()}, - NoFragmentCyclesRule: {astvalidation.Fragments()}, - NoUnusedFragmentsRule: {astvalidation.Fragments()}, - PossibleFragmentSpreadsRule: {astvalidation.Fragments()}, - UniqueFragmentNamesRule: {astvalidation.Fragments()}, - - // not mapped rules - - UniqueInputFieldNamesRule: {astvalidation.Values()}, - UniqueDirectiveNamesRule: {}, - LoneSchemaDefinitionRule: {}, - ScalarLeafsRule: {}, - PossibleTypeExtensionsRule: {}, -} - -func operationValidatorFor(rule string) (*astvalidation.OperationValidator, bool) { - rules, ok := rulesMap[rule] - if !ok { - return nil, false - } - return astvalidation.NewOperationValidator(rules), true -} - -func definitionValidatorFor(rule string) (*astvalidation.DefinitionValidator, bool) { - rules, ok := rulesMap[rule] - if !ok { - return nil, false - } - return astvalidation.NewDefinitionValidator(rules...), true -} - -// Loc - local type representing location of validation error message -type Loc struct { - line, column uint32 -} - -// Err - local type representing validation error message -type Err struct { - message string - locations []Loc -} - -// MessageCompare - is a function which allows to check that report has an expectedErrMsg -type MessageCompare func(expectedErrMsg string) - -// ResultCompare - is a function to compare report errors with expectedErrors -type ResultCompare func(expectedErrors []Err) - -// ExpectValidationErrorsWithSchema - is a helper to run operation validation -// returns ResultCompare function -func ExpectValidationErrorsWithSchema(t *testing.T, schema string, rule string, queryStr string) ResultCompare { - t.Helper() - - op, opReport := astparser.ParseGraphqlDocumentString(queryStr) - def := prepareSchema(schema) - - if opReport.HasErrors() { - t.Log("operation report has errors") - return compareReportErrors(t, opReport) - } - - var ( - report = operationreport.Report{} - validator *astvalidation.OperationValidator - ) - - validator, ok := operationValidatorFor(rule) - if !ok { - t.Fatalf(RuleHasNoMapping, rule) - return nil - } - - validator.Validate(&op, &def, &report) - - return compareReportErrors(t, report) -} - -// ExpectValidationErrors - a wrapper for ExpectValidationErrorsWithSchema which uses default testSchema -// returns ResultCompare function -func ExpectValidationErrors(t *testing.T, rule string, queryStr string) ResultCompare { - return ExpectValidationErrorsWithSchema(t, testSchema, rule, queryStr) -} - -// ExpectSDLValidationErrors - is a helper to run schema definition validation -// returns ResultCompare function -// in reference tests schema is optional but leaves on a first param -func ExpectSDLValidationErrors(t *testing.T, schema string, rule string, sdlStr string) ResultCompare { - t.Helper() - - def := prepareSchema(sdlStr) - - if schema != "" { - // merge schema additions - def.Input.AppendInputBytes([]byte(schema)) - parser := astparser.NewParser() - mergeReport := operationreport.Report{} - parser.Parse(&def, &mergeReport) - - if mergeReport.HasErrors() { - t.Log("merge failed") - return compareReportErrors(t, mergeReport) - } - } - - // validate schema sdl - var ( - report = operationreport.Report{} - validator *astvalidation.DefinitionValidator - ) - - validator, ok := definitionValidatorFor(rule) - if !ok { - t.Fatalf(RuleHasNoMapping, rule) - return nil - } - - validator.Validate(&def, &report) - - return compareReportErrors(t, report) -} - -// BuildSchema - helper used in reference test. -// As we handle validation differently return same schema string -func BuildSchema(sdl string) string { - return sdl -} - -// ExpectValidationErrorMessage - is a helper to run operation validation and check single error message -// returns MessageCompare -func ExpectValidationErrorMessage(t *testing.T, schema string, queryStr string) MessageCompare { - op, opReport := astparser.ParseGraphqlDocumentString(queryStr) - def := prepareSchema(schema) - - if opReport.HasErrors() { - t.Log("operation report has errors") - return hasReportError(t, opReport) - } - - report := operationreport.Report{} - validator := astvalidation.DefaultOperationValidator() - validator.Validate(&op, &def, &report) - - return hasReportError(t, report) -} - -// ExtendSchema - helper to extend schema with provided sdl -// -//nolint:unused -func ExtendSchema(schema string, sdlStr string) string { - if sdlStr != "" { - schema = schema + "\n" + sdlStr - } - - definition := prepareSchema(schema) - parser := astparser.NewParser() - report := operationreport.Report{} - parser.Parse(&definition, &report) - - res, _ := astprinter.PrintStringIndent(&definition, nil, " ") - - return res -} - -func prepareSchema(schema string) ast.Document { - definition, report := astparser.ParseGraphqlDocumentString(schema) - if report.HasErrors() { - panic(report.Error()) - } - - _ = asttransform.MergeDefinitionWithBaseSchema(&definition) - - return definition -} - -// externalErrors - converts external errors to simple local type Err -// convertor could be adjusted to use exact type -func externalErrors(report operationreport.Report) (out []Err) { - out = make([]Err, 0) - - for _, externalError := range report.ExternalErrors { - var locations []Loc - - for _, location := range externalError.Locations { - locations = append(locations, Loc{ - line: location.Line, - column: location.Column, - }) - } - - out = append(out, Err{ - message: externalError.Message, - locations: locations, - }) - } - - return -} - -// compareReportErrors - helper returns ResultCompare function for operationreport.Report -func compareReportErrors(t *testing.T, report operationreport.Report) ResultCompare { - return func(expectedErrors []Err) { - actualErrors := externalErrors(report) - assert.Equal(t, expectedErrors, actualErrors) - } -} - -// hasReportError - helper returns MessageCompare function for operationreport.Report -func hasReportError(t *testing.T, report operationreport.Report) MessageCompare { - return func(msg string) { - actualErrors := externalErrors(report) - - var messages []string - for _, actualError := range actualErrors { - messages = append(messages, actualError.message) - } - - assert.Contains(t, messages, msg) - } -} - -// testSchema - represents schema definition used in reference tests -var testSchema string - -func init() { - content, err := os.ReadFile("test_schema.graphql") - if err != nil { - panic(err) - } - - testSchema = string(content) -} diff --git a/pkg/astvalidation/reference/testsgo/test_schema.graphql b/pkg/astvalidation/reference/testsgo/test_schema.graphql deleted file mode 100644 index 308893229..000000000 --- a/pkg/astvalidation/reference/testsgo/test_schema.graphql +++ /dev/null @@ -1,131 +0,0 @@ -interface Being { - name(surname: Boolean): String -} - -interface Mammal { - mother: Mammal - father: Mammal -} - -interface Pet implements Being { - name(surname: Boolean): String -} - -interface Canine implements Mammal & Being { - name(surname: Boolean): String - mother: Canine - father: Canine -} - -enum DogCommand { - SIT - HEEL - DOWN -} - -type Dog implements Being & Pet & Mammal & Canine { - name(surname: Boolean): String - nickname: String - barkVolume: Int - barks: Boolean - doesKnowCommand(dogCommand: DogCommand): Boolean - isHouseTrained(atOtherHomes: Boolean = true): Boolean - isAtLocation(x: Int, y: Int): Boolean - mother: Dog - father: Dog -} - -type Cat implements Being & Pet { - name(surname: Boolean): String - nickname: String - meows: Boolean - meowsVolume: Int - furColor: FurColor -} - -union CatOrDog = Cat | Dog - -interface Intelligent { - iq: Int -} - -type Human implements Being & Intelligent { - name(surname: Boolean): String - pets: [Pet] - relatives: [Human] - iq: Int -} - -type Alien implements Being & Intelligent { - name(surname: Boolean): String - numEyes: Int - iq: Int -} - -union DogOrHuman = Dog | Human - -union HumanOrAlien = Human | Alien - -enum FurColor { - BROWN - BLACK - TAN - SPOTTED - NO_FUR - UNKNOWN -} - -input ComplexInput { - requiredField: Boolean! - nonNullField: Boolean! = false - intField: Int - stringField: String - booleanField: Boolean - stringListField: [String] -} - -type ComplicatedArgs { - # TODO List - # TODO Coercion - # TODO NotNulls - intArgField(intArg: Int): String - nonNullIntArgField(nonNullIntArg: Int!): String - stringArgField(stringArg: String): String - booleanArgField(booleanArg: Boolean): String - enumArgField(enumArg: FurColor): String - floatArgField(floatArg: Float): String - idArgField(idArg: ID): String - stringListArgField(stringListArg: [String]): String - stringListNonNullArgField(stringListNonNullArg: [String!]): String - complexArgField(complexArg: ComplexInput): String - multipleReqs(req1: Int!, req2: Int!): String - nonNullFieldWithDefault(arg: Int! = 0): String - multipleOpts(opt1: Int = 0, opt2: Int = 0): String - multipleOptAndReq(req1: Int!, req2: Int!, opt1: Int = 0, opt2: Int = 0): String -} - -type QueryRoot { - human(id: ID): Human - alien: Alien - dog: Dog - cat: Cat - pet: Pet - catOrDog: CatOrDog - dogOrHuman: DogOrHuman - humanOrAlien: HumanOrAlien - complicatedArgs: ComplicatedArgs - field(strArg: String, boolListArg: [Boolean!]!, inputArg: ComplexInput): String # need to be here to not have an error of not existing field in visitor in TestVariablesAreInputTypesRule -} - -schema { - query: QueryRoot -} - -directive @onQuery on QUERY -directive @onMutation on MUTATION -directive @onSubscription on SUBSCRIPTION -directive @onField on FIELD -directive @onFragmentDefinition on FRAGMENT_DEFINITION -directive @onFragmentSpread on FRAGMENT_SPREAD -directive @onInlineFragment on INLINE_FRAGMENT -directive @onVariableDefinition on VARIABLE_DEFINITION diff --git a/pkg/astvalidation/rule.go b/pkg/astvalidation/rule.go deleted file mode 100644 index ab0814b0a..000000000 --- a/pkg/astvalidation/rule.go +++ /dev/null @@ -1,10 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -var reservedFieldPrefix = []byte("__") - -// Rule is hook to register callback functions on the Walker -type Rule func(walker *astvisitor.Walker) diff --git a/pkg/astvalidation/rule_implement_transitive_interfaces.go b/pkg/astvalidation/rule_implement_transitive_interfaces.go deleted file mode 100644 index 0849dd466..000000000 --- a/pkg/astvalidation/rule_implement_transitive_interfaces.go +++ /dev/null @@ -1,141 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func ImplementTransitiveInterfaces() Rule { - return func(walker *astvisitor.Walker) { - visitor := &implementTransitiveInterfacesVisitor{ - Walker: walker, - } - - walker.RegisterDocumentVisitor(visitor) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterEnterInterfaceTypeExtensionVisitor(visitor) - walker.RegisterEnterObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(visitor) - } -} - -type implementTransitiveInterfacesVisitor struct { - *astvisitor.Walker - definition *ast.Document - typesImplementingInterfaces map[string][]string -} - -func (v *implementTransitiveInterfacesVisitor) EnterDocument(operation, definition *ast.Document) { - v.definition = operation - v.typesImplementingInterfaces = map[string][]string{} -} - -// LeaveDocument will iterate over the types implementing interfaces lookup map -// and check if a types with interfaces has all the transitive interfaces in their slice. -// -// Valid (typeName contains interfaceBase from interfaceOne): -// -// typeName -> [interfaceOne, interfaceBase] -// interfaceOne -> [interfaceBase] -// -// Invalid (typeName does not contain interfaceBase from interfaceOne): -// -// typeName -> [interfaceOne] -// interfaceOne -> [interfaceBase] -func (v *implementTransitiveInterfacesVisitor) LeaveDocument(operation, definition *ast.Document) { - for typeName, interfaceNames := range v.typesImplementingInterfaces { - interfaceNamesLookupList := map[string]bool{} - for i := 0; i < len(interfaceNames); i++ { - interfaceNamesLookupList[interfaceNames[i]] = true - } - - for i := 0; i < len(interfaceNames); i++ { - implementedInterfaceName := interfaceNames[i] - if _, ok := v.typesImplementingInterfaces[implementedInterfaceName]; !ok { - continue - } - - for j := 0; j < len(v.typesImplementingInterfaces[implementedInterfaceName]); j++ { - transitiveInterfaceName := v.typesImplementingInterfaces[implementedInterfaceName][j] - if _, ok := interfaceNamesLookupList[transitiveInterfaceName]; !ok { - v.Report.AddExternalError(operationreport.ErrTransitiveInterfaceNotImplemented([]byte(typeName), []byte(transitiveInterfaceName))) - } - } - } - } -} - -func (v *implementTransitiveInterfacesVisitor) EnterInterfaceTypeDefinition(ref int) { - implementsInterfaces := len(v.definition.InterfaceTypeDefinitions[ref].ImplementsInterfaces.Refs) > 0 - if !implementsInterfaces { - return - } - - interfaceName := v.definition.InterfaceTypeDefinitionNameString(ref) - v.collectImplementedInterfaces(interfaceName, v.definition.InterfaceTypeDefinitions[ref].ImplementsInterfaces.Refs) -} - -func (v *implementTransitiveInterfacesVisitor) EnterInterfaceTypeExtension(ref int) { - implementsInterfaces := len(v.definition.InterfaceTypeExtensions[ref].ImplementsInterfaces.Refs) > 0 - if !implementsInterfaces { - return - } - - interfaceName := v.definition.InterfaceTypeExtensionNameString(ref) - fieldDefinitionRefs := v.definition.InterfaceTypeExtensions[ref].FieldsDefinition.Refs - if len(fieldDefinitionRefs) == 0 { - v.Report.AddExternalError(operationreport.ErrTransitiveInterfaceExtensionImplementingWithoutBody([]byte(interfaceName))) - } - v.collectImplementedInterfaces(interfaceName, v.definition.InterfaceTypeExtensions[ref].ImplementsInterfaces.Refs) -} - -func (v *implementTransitiveInterfacesVisitor) EnterObjectTypeDefinition(ref int) { - implementsInterfaces := len(v.definition.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs) > 0 - if !implementsInterfaces { - return - } - - objectTypeName := v.definition.ObjectTypeDefinitionNameString(ref) - v.collectImplementedInterfaces(objectTypeName, v.definition.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs) -} - -func (v *implementTransitiveInterfacesVisitor) EnterObjectTypeExtension(ref int) { - implementsInterfaces := len(v.definition.ObjectTypeExtensions[ref].ImplementsInterfaces.Refs) > 0 - if !implementsInterfaces { - return - } - - objectTypeName := v.definition.ObjectTypeExtensionNameString(ref) - v.collectImplementedInterfaces(objectTypeName, v.definition.ObjectTypeExtensions[ref].ImplementsInterfaces.Refs) -} - -// collectImplementedInterfaces iterates over all implemented interfaces over a given type so that the -// names can be saved into the lookup map on the visitor -// -// Result: -// -// typeName -> [interfaceOne, interfaceBase] -// interfaceOne -> [interfaceBase] -func (v *implementTransitiveInterfacesVisitor) collectImplementedInterfaces(typeName string, implementedInterfacesRefs []int) { - for i := 0; i < len(implementedInterfacesRefs); i++ { - implementedInterfaceRef := implementedInterfacesRefs[i] - implementedInterfaceName := v.definition.TypeNameString(implementedInterfaceRef) - - if _, ok := v.typesImplementingInterfaces[typeName]; !ok { - v.typesImplementingInterfaces[typeName] = []string{implementedInterfaceName} - } - - skipInterface := false - for j := 0; j < len(v.typesImplementingInterfaces[typeName]); j++ { - if v.typesImplementingInterfaces[typeName][j] == implementedInterfaceName { - skipInterface = true - break - } - } - - if !skipInterface { - v.typesImplementingInterfaces[typeName] = append(v.typesImplementingInterfaces[typeName], implementedInterfaceName) - } - } -} diff --git a/pkg/astvalidation/rule_implement_transitive_interfaces_test.go b/pkg/astvalidation/rule_implement_transitive_interfaces_test.go deleted file mode 100644 index 799869f75..000000000 --- a/pkg/astvalidation/rule_implement_transitive_interfaces_test.go +++ /dev/null @@ -1,257 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestImplementTransitiveInterfaces(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("interface and type implementing the same interface without transition", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - type Record implements IDType { - id: ID! - data: String! - } - `, Valid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface implementing interface and type implementing transitive interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - type Record implements SoftDelete & IDType { - id: ID! - deleted: Boolean! - data: String! - } - `, Valid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface extension implements interface and type implementing transitive interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete { - deleted: Boolean! - } - - extend interface SoftDelete implements IDType { - id: ID! - } - - type Record implements SoftDelete & IDType { - id: ID! - deleted: Boolean! - data: String! - } - `, Valid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface extension implements interface and type extension implementing transitive interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete { - deleted: Boolean! - } - - extend interface SoftDelete implements IDType { - id: ID! - } - - type Record { - data: String! - } - - extend type Record implements SoftDelete & IDType { - id: ID! - deleted: Boolean! - } - `, Valid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface extension implements interface and type extension implementing transitive interface as more complex example", func(t *testing.T) { - runDefinitionValidation(t, ` - interface BaseInterface { - fieldOne: Bool! - } - - interface SecondInterface implements BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - } - - interface ThirdInterface { - fieldThree: Bool! - } - - extend interface ThirdInterface implements SecondInterface & BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - } - - interface FourthInterface implements ThirdInterface & SecondInterface & BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - fieldThree: Bool! - fieldFour: Bool! - } - - type ImplementingType { - fieldObjectType: Bool! - } - - extend type ImplementingType implements FourthInterface & ThirdInterface & SecondInterface & BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - fieldThree: Bool! - fieldFour: Bool! - } - `, Valid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface implementing interface and type not implementing transitive interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - type Record implements SoftDelete { - id: ID! - deleted: Boolean! - data: String! - } - `, Invalid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface implementing interface and type extension not implementing transitive interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - type Record { - data: String! - } - - extend type Record implements SoftDelete { - id: ID! - deleted: Boolean! - } - `, Invalid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("interface implementing interface and type extension not implementing transitive interface as more complex example", func(t *testing.T) { - runDefinitionValidation(t, ` - interface BaseInterface { - fieldOne: Bool! - } - - interface SecondInterface implements BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - } - - interface ThirdInterface { - fieldThree: Bool! - } - - extend interface ThirdInterface implements SecondInterface { - fieldOne: Bool! - fieldTwo: Bool! - } - - interface FourthInterface implements ThirdInterface & SecondInterface & BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - fieldThree: Bool! - fieldFour: Bool! - } - - type ImplementingType { - fieldObjectType: Bool! - } - - extend type ImplementingType implements FourthInterface & ThirdInterface & SecondInterface & BaseInterface { - fieldOne: Bool! - fieldTwo: Bool! - fieldThree: Bool! - fieldFour: Bool! - } - `, Invalid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("Interface extension implementing interface which also already implements same interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - extend interface SoftDelete implements IDType { - canBeRecovered: Boolean! - } - `, Valid, ImplementTransitiveInterfaces(), - ) - }) - - t.Run("Interface extension implementing interface without body", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete { - id: ID! - deleted: Boolean! - } - - extend interface SoftDelete implements IDType - `, Invalid, ImplementTransitiveInterfaces(), - ) - }) - - }) -} diff --git a/pkg/astvalidation/rule_implementing_types_are_supersets.go b/pkg/astvalidation/rule_implementing_types_are_supersets.go deleted file mode 100644 index de45931d1..000000000 --- a/pkg/astvalidation/rule_implementing_types_are_supersets.go +++ /dev/null @@ -1,246 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func ImplementingTypesAreSupersets() Rule { - return func(walker *astvisitor.Walker) { - visitor := &implementingTypesAreSupersetsVisitor{ - Walker: walker, - } - - walker.RegisterDocumentVisitor(visitor) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterEnterInterfaceTypeExtensionVisitor(visitor) - walker.RegisterEnterObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(visitor) - } -} - -type implementingTypesAreSupersetsVisitor struct { - *astvisitor.Walker - definition *ast.Document - implementingTypesWithFields map[string][]string - implementingTypesWithInterfacesNames map[string][]string -} - -func (v *implementingTypesAreSupersetsVisitor) EnterDocument(operation, definition *ast.Document) { - v.definition = operation - v.implementingTypesWithFields = make(map[string][]string) - v.implementingTypesWithInterfacesNames = make(map[string][]string) -} - -// LeaveDocument will iterate over all types which implement an interface by using the interface name. If a -// field does exist on the implemented interface but not on the implementing type, then the rule will consider it -// as invalid. -// -// Valid: -// -// ( interfaceBase -> [fieldA] ) -// interfaceOneImplementingInterfaceBase -> [fieldA, fieldB] -// objectTypeImplementingInterfaceOne -> [fieldA, fieldB, fieldC] -// -// Invalid: -// -// ( interfaceBase -> [fieldA] ) -// interfaceOneImplementingInterfaceBase -> [fieldA, fieldB] -// objectTypeImplementingInterfaceOne -> [fieldA, fieldC] -func (v *implementingTypesAreSupersetsVisitor) LeaveDocument(operation, definition *ast.Document) { - for typeName, interfacesNames := range v.implementingTypesWithInterfacesNames { - typeNameHasFields := true - typeNameFields, exists := v.implementingTypesWithFields[typeName] - if !exists || len(typeNameFields) == 0 { - typeNameHasFields = false - } - - typeNameFieldsLookupMap := map[string]bool{} - for i := 0; i < len(typeNameFields); i++ { - typeNameFieldsLookupMap[typeNameFields[i]] = true - } - - for i := 0; i < len(interfacesNames); i++ { - nodes, exists := v.definition.Index.NodesByNameStr(interfacesNames[i]) - if !exists { - continue - } - - var interfaceFieldRefs []int - for j := 0; j < len(nodes); j++ { - switch nodes[j].Kind { - case ast.NodeKindInterfaceTypeDefinition: - interfaceFieldRefs = append(interfaceFieldRefs, v.definition.InterfaceTypeDefinitions[nodes[j].Ref].FieldsDefinition.Refs...) - case ast.NodeKindInterfaceTypeExtension: - interfaceFieldRefs = append(interfaceFieldRefs, v.definition.InterfaceTypeExtensions[nodes[j].Ref].FieldsDefinition.Refs...) - default: - continue - } - } - - if !typeNameHasFields && len(interfaceFieldRefs) > 0 { - v.Report.AddExternalError(operationreport.ErrImplementingTypeDoesNotHaveFields([]byte(typeName))) - continue - } - - for j := 0; j < len(interfaceFieldRefs); j++ { - interfaceFieldName := v.definition.FieldDefinitionNameString(interfaceFieldRefs[j]) - if existsOnType := typeNameFieldsLookupMap[interfaceFieldName]; !existsOnType { - v.Report.AddExternalError(operationreport.ErrTypeDoesNotImplementFieldFromInterface( - []byte(typeName), - []byte(interfacesNames[i]), - []byte(interfaceFieldName), - )) - } - } - } - } -} - -func (v *implementingTypesAreSupersetsVisitor) EnterInterfaceTypeDefinition(ref int) { - interfacesRefs := v.definition.InterfaceTypeDefinitions[ref].ImplementsInterfaces.Refs - if len(interfacesRefs) == 0 { - return - } - - typeName := v.definition.InterfaceTypeDefinitionNameString(ref) - fieldDefinitionRefs := v.definition.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs - v.collectFieldsForTypeName(typeName, fieldDefinitionRefs) - v.collectInterfaceNamesForImplementedInterfacesByTypeName(typeName, interfacesRefs) -} - -func (v *implementingTypesAreSupersetsVisitor) EnterInterfaceTypeExtension(ref int) { - interfacesRefs := v.definition.InterfaceTypeExtensions[ref].ImplementsInterfaces.Refs - if len(interfacesRefs) == 0 { - return - } - - typeName := v.definition.InterfaceTypeExtensionNameString(ref) - fieldDefinitionRefs := v.definition.InterfaceTypeExtensions[ref].FieldsDefinition.Refs - - nodesWithTypeName, exists := v.definition.Index.NodesByNameStr(typeName) - if !exists { - return // if exists is false then something is really wrong - } - - for i := 0; i < len(nodesWithTypeName); i++ { - switch nodesWithTypeName[i].Kind { - case ast.NodeKindInterfaceTypeDefinition: - baseInterfaceRef := nodesWithTypeName[i].Ref - baseInterfaceTypeFieldRefs := v.definition.InterfaceTypeDefinitions[baseInterfaceRef].FieldsDefinition.Refs - for j := 0; j < len(baseInterfaceTypeFieldRefs); j++ { - fieldDefinitionRefs = append(fieldDefinitionRefs, baseInterfaceTypeFieldRefs[j]) - } - default: - continue - } - } - - v.collectFieldsForTypeName(typeName, fieldDefinitionRefs) - v.collectInterfaceNamesForImplementedInterfacesByTypeName(typeName, interfacesRefs) -} - -func (v *implementingTypesAreSupersetsVisitor) EnterObjectTypeDefinition(ref int) { - interfacesRefs := v.definition.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs - if len(interfacesRefs) == 0 { - return - } - - typeName := v.definition.ObjectTypeDefinitionNameString(ref) - fieldDefinitionRefs := v.definition.ObjectTypeDefinitions[ref].FieldsDefinition.Refs - v.collectFieldsForTypeName(typeName, fieldDefinitionRefs) - v.collectInterfaceNamesForImplementedInterfacesByTypeName(typeName, interfacesRefs) -} - -func (v *implementingTypesAreSupersetsVisitor) EnterObjectTypeExtension(ref int) { - interfacesRefs := v.definition.ObjectTypeExtensions[ref].ImplementsInterfaces.Refs - if len(interfacesRefs) == 0 { - return - } - - typeName := v.definition.ObjectTypeExtensionNameString(ref) - fieldDefinitionRefs := v.definition.ObjectTypeExtensions[ref].FieldsDefinition.Refs - - nodesWithTypeName, exists := v.definition.Index.NodesByNameStr(typeName) - if !exists { - return // if exists is false then something is really wrong - } - - for i := 0; i < len(nodesWithTypeName); i++ { - switch nodesWithTypeName[i].Kind { - case ast.NodeKindObjectTypeDefinition: - baseObjectTypeRef := nodesWithTypeName[i].Ref - baseObjectTypeInterfaceRefs := v.definition.ObjectTypeDefinitions[baseObjectTypeRef].FieldsDefinition.Refs - for j := 0; j < len(baseObjectTypeInterfaceRefs); j++ { - fieldDefinitionRefs = append(fieldDefinitionRefs, baseObjectTypeInterfaceRefs[j]) - } - default: - continue - } - } - - v.collectFieldsForTypeName(typeName, fieldDefinitionRefs) - v.collectInterfaceNamesForImplementedInterfacesByTypeName(typeName, interfacesRefs) -} - -// collectFieldsForTypeName will add all field names of a type which implements an interface to a slice in a -// map entry, so that it can be used as a lookup table later on. -// -// Example: -// -// interfaceOne -> [fieldA, fieldB] -// objectType -> [fieldA, fieldB, fieldC] -func (v *implementingTypesAreSupersetsVisitor) collectFieldsForTypeName(typeName string, fieldDefinitionRefs []int) { - if _, ok := v.implementingTypesWithFields[typeName]; !ok { - v.implementingTypesWithFields[typeName] = []string{} - } - - for i := 0; i < len(fieldDefinitionRefs); i++ { - fieldName := v.definition.FieldDefinitionNameString(fieldDefinitionRefs[i]) - - skipFieldName := false - for j := 0; j < len(v.implementingTypesWithFields[typeName]); j++ { - if fieldName == v.implementingTypesWithFields[typeName][j] { - skipFieldName = true - break - } - } - - if skipFieldName { - continue - } - - v.implementingTypesWithFields[typeName] = append(v.implementingTypesWithFields[typeName], fieldName) - } -} - -// collectInterfaceNamesForImplementedInterfacesByTypeName will add all interface names implemented by the given type, -// so it can be used to iterate over them when leaving the document. -// -// Example: -// -// interfaceOne -> [interfaceBase] -// objectType -> [interfaceOne, interfaceBase] -func (v *implementingTypesAreSupersetsVisitor) collectInterfaceNamesForImplementedInterfacesByTypeName(typeName string, typeRefs []int) { - if _, ok := v.implementingTypesWithInterfacesNames[typeName]; !ok { - v.implementingTypesWithInterfacesNames[typeName] = []string{} - } - - for i := 0; i < len(typeRefs); i++ { - interfaceName := v.definition.TypeNameString(typeRefs[i]) - skipInterfaceName := false - for j := 0; j < len(v.implementingTypesWithInterfacesNames[typeName]); j++ { - if interfaceName == v.implementingTypesWithInterfacesNames[typeName][j] { - skipInterfaceName = true - break - } - } - - if skipInterfaceName { - continue - } - - v.implementingTypesWithInterfacesNames[typeName] = append(v.implementingTypesWithInterfacesNames[typeName], interfaceName) - } -} diff --git a/pkg/astvalidation/rule_implementing_types_are_supersets_test.go b/pkg/astvalidation/rule_implementing_types_are_supersets_test.go deleted file mode 100644 index 7f14216f4..000000000 --- a/pkg/astvalidation/rule_implementing_types_are_supersets_test.go +++ /dev/null @@ -1,110 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestImplementingTypesAreSupersets(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("all implementing types are supersets of their interfaces", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - type Record implements SoftDelete & IDType { - id: ID! - deleted: Boolean! - data: String! - } - `, Valid, ImplementingTypesAreSupersets(), - ) - }) - - t.Run("all implementing types and extensions are supersets of their interfaces", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete { - deleted: Boolean! - } - - extend interface SoftDelete implements IDType { - id: ID! - } - - type Record { - data: String! - } - - extend type Record implements SoftDelete & IDType { - id: ID! - deleted: Boolean! - } - `, Valid, ImplementingTypesAreSupersets(), - ) - }) - - t.Run("not all implementing types are supersets of their interfaces", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType { - id: ID! - deleted: Boolean! - } - - type Record implements SoftDelete & IDType { - id: ID! - data: String! - } - `, Invalid, ImplementingTypesAreSupersets(), - ) - }) - - t.Run("not all implementing types and extensions are supersets of their interfaces", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete { - deleted: Boolean! - } - - extend interface SoftDelete implements IDType { - id: ID! - } - - type Record { - data: String! - } - - extend type Record implements SoftDelete & IDType { - id: ID! - } - `, Invalid, ImplementingTypesAreSupersets(), - ) - }) - - t.Run("implementing type does not define any fields but interface has fields", func(t *testing.T) { - runDefinitionValidation(t, ` - interface IDType { - id: ID! - } - - interface SoftDelete implements IDType - `, Invalid, ImplementingTypesAreSupersets(), - ) - }) - }) -} diff --git a/pkg/astvalidation/rule_known_type_names.go b/pkg/astvalidation/rule_known_type_names.go deleted file mode 100644 index ac0325384..000000000 --- a/pkg/astvalidation/rule_known_type_names.go +++ /dev/null @@ -1,121 +0,0 @@ -package astvalidation - -import ( - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func KnownTypeNames() Rule { - return func(walker *astvisitor.Walker) { - visitor := &knownTypeNamesVisitor{ - Walker: walker, - } - - walker.RegisterDocumentVisitor(visitor) - walker.RegisterEnterRootOperationTypeDefinitionVisitor(visitor) - walker.RegisterEnterFieldDefinitionVisitor(visitor) - walker.RegisterEnterUnionMemberTypeVisitor(visitor) - walker.RegisterEnterInputValueDefinitionVisitor(visitor) - walker.RegisterEnterObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(visitor) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterEnterScalarTypeDefinitionVisitor(visitor) - walker.RegisterEnterUnionTypeDefinitionVisitor(visitor) - walker.RegisterEnterInputObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterEnumTypeDefinitionVisitor(visitor) - } -} - -type knownTypeNamesVisitor struct { - *astvisitor.Walker - definition *ast.Document - definedTypeNameHashs map[uint64]bool - referencedTypeNames map[uint64][]byte -} - -func (u *knownTypeNamesVisitor) EnterDocument(operation, _ *ast.Document) { - u.definition = operation - u.definedTypeNameHashs = make(map[uint64]bool) - u.referencedTypeNames = make(map[uint64][]byte) -} - -func (u *knownTypeNamesVisitor) LeaveDocument(_, _ *ast.Document) { - for referencedTypeNameHash, referencedTypeName := range u.referencedTypeNames { - if !u.definedTypeNameHashs[referencedTypeNameHash] { - u.Report.AddExternalError(operationreport.ErrTypeUndefined(referencedTypeName)) - continue - } - } - -} - -func (u *knownTypeNamesVisitor) EnterRootOperationTypeDefinition(ref int) { - referencedTypeName := u.definition.Input.ByteSlice(u.definition.RootOperationTypeDefinitions[ref].NamedType.Name) - u.saveReferencedTypeName(referencedTypeName) -} - -func (u *knownTypeNamesVisitor) EnterFieldDefinition(ref int) { - referencedTypeRef := u.definition.ResolveUnderlyingType(u.definition.FieldDefinitions[ref].Type) - referencedTypeName := u.definition.TypeNameBytes(referencedTypeRef) - u.saveReferencedTypeName(referencedTypeName) -} - -func (u *knownTypeNamesVisitor) EnterUnionMemberType(ref int) { - referencedTypeName := u.definition.TypeNameBytes(ref) - u.saveReferencedTypeName(referencedTypeName) -} - -func (u *knownTypeNamesVisitor) EnterInputValueDefinition(ref int) { - referencedTypeRef := u.definition.InputValueDefinitions[ref].Type - referencedTypeName := u.definition.TypeNameBytes(referencedTypeRef) - u.saveReferencedTypeName(referencedTypeName) -} - -func (u *knownTypeNamesVisitor) EnterObjectTypeDefinition(ref int) { - typeName := u.definition.ObjectTypeDefinitionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) EnterObjectTypeExtension(ref int) { - typeName := u.definition.ObjectTypeExtensionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) EnterInterfaceTypeDefinition(ref int) { - typeName := u.definition.InterfaceTypeDefinitionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) EnterScalarTypeDefinition(ref int) { - typeName := u.definition.ScalarTypeDefinitionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) EnterUnionTypeDefinition(ref int) { - typeName := u.definition.UnionTypeDefinitionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) EnterInputObjectTypeDefinition(ref int) { - typeName := u.definition.InputObjectTypeDefinitionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) EnterEnumTypeDefinition(ref int) { - typeName := u.definition.EnumTypeDefinitionNameBytes(ref) - u.saveTypeName(typeName) -} - -func (u *knownTypeNamesVisitor) saveTypeName(typeName ast.ByteSlice) { - u.definedTypeNameHashs[xxhash.Sum64(typeName)] = true -} - -func (u *knownTypeNamesVisitor) saveReferencedTypeName(referencedTypeName ast.ByteSlice) { - if len(referencedTypeName) == 0 { - return - } - u.referencedTypeNames[xxhash.Sum64(referencedTypeName)] = referencedTypeName -} diff --git a/pkg/astvalidation/rule_known_type_names_test.go b/pkg/astvalidation/rule_known_type_names_test.go deleted file mode 100644 index 3c0d48e98..000000000 --- a/pkg/astvalidation/rule_known_type_names_test.go +++ /dev/null @@ -1,191 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestKnownTypeNames(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("use standard scalars", func(t *testing.T) { - runDefinitionValidation(t, ` - type Query { - string: String - int: Int - float: Float - boolean: Boolean - id: ID - } - `, Valid, KnownTypeNames(), - ) - }) - - t.Run("reference types defined inside the same document", func(t *testing.T) { - runDefinitionValidation(t, ` - union SomeUnion = SomeObject | AnotherObject - type SomeObject implements SomeInterface { - someScalar(arg: SomeInputObject): SomeScalar - } - type AnotherObject { - foo(arg: SomeInputObject): String - } - type SomeInterface { - someScalar(arg: SomeInputObject): SomeScalar - } - input SomeInputObject { - someScalar: SomeScalar - } - scalar SomeScalar - type RootQuery { - someInterface: SomeInterface - someUnion: SomeUnion - someScalar: SomeScalar - someObject: SomeObject - } - schema { - query: RootQuery - } - `, Valid, KnownTypeNames(), - ) - }) - - t.Run("reference types defined inside extension", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - type Bar - type Query { - foo: Foo - } - - extend type Query { - bar: Bar - } - `, Valid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references", func(t *testing.T) { - runDefinitionValidation(t, ` - type A - type B - type SomeObject implements C { - e(d: D): E - } - union SomeUnion = F | G - interface SomeInterface { - i(h: H): I - } - input SomeInput { - j: J - } - directive @SomeDirective(k: K) on QUERY - schema { - query: L - mutation: M - subscription: N - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references: root operation", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { - query: Query - mutation: B - } - - type Query { - foo: Foo - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references: interface", func(t *testing.T) { - runDefinitionValidation(t, ` - interface Foo { - bar: Bar - } - - type Query { - foo: Foo - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references: union", func(t *testing.T) { - runDefinitionValidation(t, ` - union Foo = Bar | Baz - - type Query { - foo: Foo - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references: input", func(t *testing.T) { - runDefinitionValidation(t, ` - input Foo { - bar: Bar - } - - type Query { - foo: String - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references: argument", func(t *testing.T) { - runDefinitionValidation(t, ` - type Query { - foo(bar: Bar): String - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unknown type references: directive", func(t *testing.T) { - runDefinitionValidation(t, ` - directive @SomeDirective(bar: Baz) on QUERY - schema { - query: MyQuery - } - - type MyQuery { - foo: String - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("does not consider non-type definitions", func(t *testing.T) { - runDefinitionValidation(t, ` - fragment Foo on Query { __typename } - directive @Foo on QUERY - type Query { - foo: Foo - __typename: String! - } - `, Invalid, KnownTypeNames(), - ) - }) - - t.Run("unkown reference type defined inside extension", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - type Query { - foo: Foo - } - - extend type Query { - bar: Bar - } - `, Invalid, KnownTypeNames(), - ) - }) - }) -} diff --git a/pkg/astvalidation/rule_populated_type_bodies.go b/pkg/astvalidation/rule_populated_type_bodies.go deleted file mode 100644 index 16820288f..000000000 --- a/pkg/astvalidation/rule_populated_type_bodies.go +++ /dev/null @@ -1,116 +0,0 @@ -package astvalidation - -import ( - "bytes" - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type populatedTypeBodiesVisitor struct { - *astvisitor.Walker - definition *ast.Document -} - -func PopulatedTypeBodies() Rule { - return func(walker *astvisitor.Walker) { - visitor := &populatedTypeBodiesVisitor{ - Walker: walker, - definition: nil, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterEnumTypeDefinitionVisitor(visitor) - walker.RegisterEnterEnumTypeExtensionVisitor(visitor) - walker.RegisterEnterInputObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterInputObjectTypeExtensionVisitor(visitor) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterEnterInterfaceTypeExtensionVisitor(visitor) - walker.RegisterEnterObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(visitor) - } -} - -func (p *populatedTypeBodiesVisitor) EnterDocument(operation, _ *ast.Document) { - p.definition = operation -} - -func (p populatedTypeBodiesVisitor) EnterEnumTypeDefinition(ref int) { - if !p.definition.EnumTypeDefinitions[ref].HasEnumValuesDefinition { - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("enum", p.definition.EnumTypeDefinitionNameString(ref))) - return - } -} - -func (p *populatedTypeBodiesVisitor) EnterEnumTypeExtension(ref int) { - if !p.definition.EnumTypeExtensions[ref].HasEnumValuesDefinition { - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("enum extension", p.definition.EnumTypeExtensionNameString(ref))) - return - } -} - -func (p populatedTypeBodiesVisitor) EnterInputObjectTypeDefinition(ref int) { - if !p.definition.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition { - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("input", p.definition.InputObjectTypeDefinitionNameString(ref))) - return - } -} - -func (p *populatedTypeBodiesVisitor) EnterInputObjectTypeExtension(ref int) { - if !p.definition.InputObjectTypeExtensions[ref].HasInputFieldsDefinition { - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("input extension", p.definition.InputObjectTypeExtensionNameString(ref))) - return - } -} - -func (p populatedTypeBodiesVisitor) EnterInterfaceTypeDefinition(ref int) { - switch p.definition.InterfaceTypeDefinitions[ref].HasFieldDefinitions { - case true: - if !p.doesTypeOnlyContainReservedFields(p.definition.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs) { - return - } - fallthrough - case false: - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("interface", p.definition.InterfaceTypeDefinitionNameString(ref))) - return - } -} - -func (p *populatedTypeBodiesVisitor) EnterInterfaceTypeExtension(ref int) { - if !p.definition.InterfaceTypeExtensions[ref].HasFieldDefinitions { - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("interface extension", p.definition.InterfaceTypeExtensionNameString(ref))) - return - } -} - -func (p populatedTypeBodiesVisitor) EnterObjectTypeDefinition(ref int) { - nameBytes := p.definition.ObjectTypeDefinitionNameBytes(ref) - object := p.definition.ObjectTypeDefinitions[ref] - switch object.HasFieldDefinitions { - case true: - if ast.IsRootType(nameBytes) || !p.doesTypeOnlyContainReservedFields(p.definition.ObjectTypeDefinitions[ref].FieldsDefinition.Refs) { - return - } - fallthrough - case false: - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("object", string(nameBytes))) - return - } -} - -func (p *populatedTypeBodiesVisitor) EnterObjectTypeExtension(ref int) { - if !p.definition.ObjectTypeExtensions[ref].HasFieldDefinitions { - p.Report.AddExternalError(operationreport.ErrTypeBodyMustNotBeEmpty("object extension", p.definition.ObjectTypeExtensionNameString(ref))) - return - } -} - -func (p *populatedTypeBodiesVisitor) doesTypeOnlyContainReservedFields(refs []int) bool { - for _, fieldRef := range refs { - fieldNameBytes := p.definition.FieldDefinitionNameBytes(fieldRef) - if len(fieldNameBytes) < 2 || !bytes.HasPrefix(fieldNameBytes, reservedFieldPrefix) { - return false - } - } - return true -} diff --git a/pkg/astvalidation/rule_populated_type_bodies_test.go b/pkg/astvalidation/rule_populated_type_bodies_test.go deleted file mode 100644 index 38c7c02e9..000000000 --- a/pkg/astvalidation/rule_populated_type_bodies_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestPopulatedTypeBodies(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("Populated type bodies are valid", func(t *testing.T) { - runDefinitionValidation(t, ` - enum Species { - CAT - } - - extend enum Color { - DOG - } - - input Message { - content: String! - } - - extend input Message { - updated: DateTime! - } - - interface Animal { - species: Species! - } - - extend interface Animal { - age: Int! - } - - type Cat implements Animal { - species: Species! - } - - extend type Cat implements Animal { - age: Int! - } - `, Valid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty enum is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - enum Species { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty enum extension is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - enum Species { - CAT - } - - extend enum Species { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty input is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - input Message { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty input extension is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - input Message { - content: String! - } - - extend input Message { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty interface is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - interface Animal { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty interface extension is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - interface Animal { - species: String! - } - - extend interface Animal { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty object is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - type Cat { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - - t.Run("Empty object extension is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - type Cat { - species: String! - } - - extend type Cat { - } - `, Invalid, PopulatedTypeBodies(), - ) - }) - }) -} diff --git a/pkg/astvalidation/rule_require_defined_types_for_extensions.go b/pkg/astvalidation/rule_require_defined_types_for_extensions.go deleted file mode 100644 index ad1b0524b..000000000 --- a/pkg/astvalidation/rule_require_defined_types_for_extensions.go +++ /dev/null @@ -1,89 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func RequireDefinedTypesForExtensions() Rule { - return func(walker *astvisitor.Walker) { - visitor := &requireDefinedTypesForExtensionsVisitor{ - Walker: walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterScalarTypeExtensionVisitor(visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(visitor) - walker.RegisterEnterInterfaceTypeExtensionVisitor(visitor) - walker.RegisterEnterUnionTypeExtensionVisitor(visitor) - walker.RegisterEnterEnumTypeExtensionVisitor(visitor) - walker.RegisterEnterInputObjectTypeExtensionVisitor(visitor) - } -} - -type requireDefinedTypesForExtensionsVisitor struct { - *astvisitor.Walker - definition *ast.Document -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterDocument(operation, definition *ast.Document) { - r.definition = operation -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterScalarTypeExtension(ref int) { - name := r.definition.ScalarTypeExtensionNameBytes(ref) - if !r.extensionIsValidForNodeKind(name, ast.NodeKindScalarTypeDefinition) { - r.Report.AddExternalError(operationreport.ErrScalarTypeUndefined(name)) - } -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterObjectTypeExtension(ref int) { - name := r.definition.ObjectTypeExtensionNameBytes(ref) - if !r.extensionIsValidForNodeKind(name, ast.NodeKindObjectTypeDefinition) { - r.Report.AddExternalError(operationreport.ErrTypeUndefined(name)) - } -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterInterfaceTypeExtension(ref int) { - name := r.definition.InterfaceTypeExtensionNameBytes(ref) - if !r.extensionIsValidForNodeKind(name, ast.NodeKindInterfaceTypeDefinition) { - r.Report.AddExternalError(operationreport.ErrInterfaceTypeUndefined(name)) - } -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterUnionTypeExtension(ref int) { - name := r.definition.UnionTypeExtensionNameBytes(ref) - if !r.extensionIsValidForNodeKind(name, ast.NodeKindUnionTypeDefinition) { - r.Report.AddExternalError(operationreport.ErrUnionTypeUndefined(name)) - } -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterEnumTypeExtension(ref int) { - name := r.definition.EnumTypeExtensionNameBytes(ref) - if !r.extensionIsValidForNodeKind(name, ast.NodeKindEnumTypeDefinition) { - r.Report.AddExternalError(operationreport.ErrEnumTypeUndefined(name)) - } -} - -func (r *requireDefinedTypesForExtensionsVisitor) EnterInputObjectTypeExtension(ref int) { - name := r.definition.InputObjectTypeExtensionNameBytes(ref) - if !r.extensionIsValidForNodeKind(name, ast.NodeKindInputObjectTypeDefinition) { - r.Report.AddExternalError(operationreport.ErrInputObjectTypeUndefined(name)) - } -} - -func (r *requireDefinedTypesForExtensionsVisitor) extensionIsValidForNodeKind(name ast.ByteSlice, definitionNodeKind ast.NodeKind) bool { - nodes, exists := r.definition.Index.NodesByNameBytes(name) - if !exists { - return true - } - - for i := 0; i < len(nodes); i++ { - if nodes[i].Kind == definitionNodeKind { - return true - } - } - - return false -} diff --git a/pkg/astvalidation/rule_require_defined_types_for_extensions_test.go b/pkg/astvalidation/rule_require_defined_types_for_extensions_test.go deleted file mode 100644 index 9b78ea3f3..000000000 --- a/pkg/astvalidation/rule_require_defined_types_for_extensions_test.go +++ /dev/null @@ -1,142 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestExtendOnlyOnDefinedTypes(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("scalar types", func(t *testing.T) { - t.Run("should be valid when scalar type is defined", func(t *testing.T) { - runDefinitionValidation(t, ` - directive @future on SCALAR - scalar Date - extend scalar Date @future - `, Valid, RequireDefinedTypesForExtensions(), - ) - }) - - t.Run("should be invalid when scalar type is not defined", func(t *testing.T) { - runDefinitionValidation(t, ` - directive @future on SCALAR - extend scalar Date @future - `, Invalid, RequireDefinedTypesForExtensions(), - ) - }) - }) - - t.Run("object types", func(t *testing.T) { - t.Run("should be valid when object type is defined", func(t *testing.T) { - runDefinitionValidation(t, ` - type User { - id: String - } - - extend type User { - email: String - } - `, Valid, RequireDefinedTypesForExtensions(), - ) - }) - - t.Run("should be invalid when object type is not defined", func(t *testing.T) { - runDefinitionValidation(t, ` - extend type User { - email: String - } - `, Invalid, RequireDefinedTypesForExtensions(), - ) - }) - }) - - t.Run("interface types", func(t *testing.T) { - t.Run("should be valid when interface type is defined", func(t *testing.T) { - runDefinitionValidation(t, ` - interface Animal { - name: String - } - - extend interface Animal { - weight: Float - } - `, Valid, RequireDefinedTypesForExtensions(), - ) - }) - - t.Run("should be invalid when interface type is not defined", func(t *testing.T) { - runDefinitionValidation(t, ` - extend interface Animal { - weight: Float - } - `, Invalid, RequireDefinedTypesForExtensions(), - ) - }) - }) - - t.Run("union types", func(t *testing.T) { - t.Run("should be valid when union type is defined", func(t *testing.T) { - runDefinitionValidation(t, ` - union Animal = Cat | Dog - extend union Animal = Bird - `, Valid, RequireDefinedTypesForExtensions(), - ) - }) - - t.Run("should be invalid when union type is not defined", func(t *testing.T) { - runDefinitionValidation(t, ` - extend union Animal = Bird - `, Invalid, RequireDefinedTypesForExtensions(), - ) - }) - }) - - t.Run("enum types", func(t *testing.T) { - t.Run("should be valid when enum type is defined", func(t *testing.T) { - runDefinitionValidation(t, ` - enum Currency { - USD - } - - extend enum Currency { - Euro - } - `, Valid, RequireDefinedTypesForExtensions(), - ) - }) - - t.Run("should be invalid when enum type is not defined", func(t *testing.T) { - runDefinitionValidation(t, ` - extend enum Currency { - Euro - } - `, Invalid, RequireDefinedTypesForExtensions(), - ) - }) - }) - - t.Run("input object types", func(t *testing.T) { - t.Run("should be valid when input object type is defined", func(t *testing.T) { - runDefinitionValidation(t, ` - input Point { - x: Int - y: Int - } - - extend input Point { - z: int - } - `, Valid, RequireDefinedTypesForExtensions(), - ) - }) - - t.Run("should be invalid when input object type is not defined", func(t *testing.T) { - runDefinitionValidation(t, ` - extend input Point { - z: int - } - `, Invalid, RequireDefinedTypesForExtensions(), - ) - }) - }) - }) -} diff --git a/pkg/astvalidation/rule_unique_enum_value_names.go b/pkg/astvalidation/rule_unique_enum_value_names.go deleted file mode 100644 index 5e78ffa9a..000000000 --- a/pkg/astvalidation/rule_unique_enum_value_names.go +++ /dev/null @@ -1,92 +0,0 @@ -package astvalidation - -import ( - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type hashedEnumValueNames map[uint64]bool - -func UniqueEnumValueNames() Rule { - return func(walker *astvisitor.Walker) { - visitor := &uniqueEnumValueNamesVisitor{ - Walker: walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterEnumValueDefinitionVisitor(visitor) - walker.RegisterEnumTypeDefinitionVisitor(visitor) - walker.RegisterEnumTypeExtensionVisitor(visitor) - } -} - -type uniqueEnumValueNamesVisitor struct { - *astvisitor.Walker - definition *ast.Document - currentEnumName ast.ByteSlice - currentEnumHash uint64 - usedEnumValues map[uint64]hashedEnumValueNames -} - -func (u *uniqueEnumValueNamesVisitor) EnterDocument(operation, definition *ast.Document) { - u.definition = operation - u.currentEnumName = u.currentEnumName[:0] - u.currentEnumHash = 0 - u.usedEnumValues = make(map[uint64]hashedEnumValueNames) -} - -func (u *uniqueEnumValueNamesVisitor) EnterEnumValueDefinition(ref int) { - enumValueName := u.definition.EnumValueDefinitionNameBytes(ref) - u.checkEnumValueName(enumValueName) -} - -func (u *uniqueEnumValueNamesVisitor) EnterEnumTypeDefinition(ref int) { - enumName := u.definition.EnumTypeDefinitionNameBytes(ref) - u.setCurrentEnum(enumName) -} - -func (u *uniqueEnumValueNamesVisitor) LeaveEnumTypeDefinition(ref int) { - u.unsetCurrentEnum() -} - -func (u *uniqueEnumValueNamesVisitor) EnterEnumTypeExtension(ref int) { - enumName := u.definition.EnumTypeExtensionNameBytes(ref) - u.setCurrentEnum(enumName) -} - -func (u *uniqueEnumValueNamesVisitor) LeaveEnumTypeExtension(ref int) { - u.unsetCurrentEnum() -} - -func (u *uniqueEnumValueNamesVisitor) setCurrentEnum(enumName ast.ByteSlice) { - u.currentEnumName = enumName - u.currentEnumHash = xxhash.Sum64(enumName) -} - -func (u *uniqueEnumValueNamesVisitor) unsetCurrentEnum() { - u.currentEnumName = u.currentEnumName[:0] - u.currentEnumHash = 0 -} - -func (u *uniqueEnumValueNamesVisitor) checkEnumValueName(enumValueName ast.ByteSlice) { - if len(u.currentEnumName) == 0 || u.currentEnumHash == 0 { - return - } - - enumValueNameHash := xxhash.Sum64(enumValueName) - enumValueNames, ok := u.usedEnumValues[u.currentEnumHash] - if !ok { - enumValueNames = make(hashedEnumValueNames) - } - - if enumValueNames[enumValueNameHash] { - u.Report.AddExternalError(operationreport.ErrEnumValueNameMustBeUnique(u.currentEnumName, enumValueName)) - return - } - - enumValueNames[enumValueNameHash] = true - u.usedEnumValues[u.currentEnumHash] = enumValueNames -} diff --git a/pkg/astvalidation/rule_unique_enum_value_names_test.go b/pkg/astvalidation/rule_unique_enum_value_names_test.go deleted file mode 100644 index dcf3b0498..000000000 --- a/pkg/astvalidation/rule_unique_enum_value_names_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestUniqueEnumValueNames(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("no values", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum - `, Valid, UniqueEnumValueNames(), - ) - }) - - t.Run("one value", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum { - FOO - } - `, Valid, UniqueEnumValueNames(), - ) - }) - - t.Run("multiple values", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum { - FOO - BAR - } - `, Valid, UniqueEnumValueNames(), - ) - }) - - t.Run("extend enum with new value", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum { - FOO - } - extend enum SomeEnum { - BAR - } - extend enum SomeEnum { - BAZ - } - `, Valid, UniqueEnumValueNames(), - ) - }) - - t.Run("duplicate values inside the same enum definition", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum { - FOO - BAR - FOO - } - `, Invalid, UniqueEnumValueNames(), - ) - }) - - t.Run("extend enum with duplicate value", func(t *testing.T) { - runDefinitionValidation(t, ` - extend enum SomeEnum { - FOO - } - enum SomeEnum { - FOO - } - `, Invalid, UniqueEnumValueNames(), - ) - }) - - t.Run("duplicate value inside extension", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum - extend enum SomeEnum { - FOO - BAR - FOO - } - `, Invalid, UniqueEnumValueNames(), - ) - }) - - t.Run("duplicate value inside different extensions", func(t *testing.T) { - runDefinitionValidation(t, ` - enum SomeEnum - extend enum SomeEnum { - FOO - } - extend enum SomeEnum { - FOO - } - `, Invalid, UniqueEnumValueNames(), - ) - }) - }) -} diff --git a/pkg/astvalidation/rule_unique_field_definition_names.go b/pkg/astvalidation/rule_unique_field_definition_names.go deleted file mode 100644 index 405a2cdd4..000000000 --- a/pkg/astvalidation/rule_unique_field_definition_names.go +++ /dev/null @@ -1,155 +0,0 @@ -package astvalidation - -import ( - "bytes" - - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type hashedFieldNames map[uint64]bool - -func UniqueFieldDefinitionNames() Rule { - return func(walker *astvisitor.Walker) { - visitor := &uniqueFieldDefinitionNamesVisitor{ - Walker: walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterFieldDefinitionVisitor(visitor) - walker.RegisterEnterInputValueDefinitionVisitor(visitor) - walker.RegisterObjectTypeDefinitionVisitor(visitor) - walker.RegisterObjectTypeExtensionVisitor(visitor) - walker.RegisterInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterInterfaceTypeExtensionVisitor(visitor) - walker.RegisterInputObjectTypeDefinitionVisitor(visitor) - walker.RegisterInputObjectTypeExtensionVisitor(visitor) - } -} - -type uniqueFieldDefinitionNamesVisitor struct { - *astvisitor.Walker - definition *ast.Document - currentTypeName ast.ByteSlice - currentTypeNameHash uint64 - currentTypeKind ast.NodeKind - usedFieldNames map[uint64]hashedFieldNames // map of hashed type names containing a map of hashed field names -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterDocument(operation, _ *ast.Document) { - u.definition = operation - u.currentTypeName = u.currentTypeName[:0] - u.currentTypeNameHash = 0 - u.currentTypeKind = ast.NodeKindUnknown - u.usedFieldNames = make(map[uint64]hashedFieldNames) -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterFieldDefinition(ref int) { - fieldName := u.definition.FieldDefinitionNameBytes(ref) - u.checkField(fieldName) -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterInputValueDefinition(ref int) { - if u.currentTypeKind != ast.NodeKindInputObjectTypeDefinition && u.currentTypeKind != ast.NodeKindInputObjectTypeExtension { - return - } - - name := u.definition.InputValueDefinitionNameBytes(ref) - u.checkField(name) -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterObjectTypeDefinition(ref int) { - typeName := u.definition.ObjectTypeDefinitionNameBytes(ref) - u.setCurrentTypeName(typeName, ast.NodeKindObjectTypeDefinition) -} - -func (u *uniqueFieldDefinitionNamesVisitor) LeaveObjectTypeDefinition(_ int) { - u.unsetCurrentTypeName() -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterObjectTypeExtension(ref int) { - typeName := u.definition.ObjectTypeExtensionNameBytes(ref) - u.setCurrentTypeName(typeName, ast.NodeKindObjectTypeExtension) -} - -func (u *uniqueFieldDefinitionNamesVisitor) LeaveObjectTypeExtension(_ int) { - u.unsetCurrentTypeName() -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterInterfaceTypeDefinition(ref int) { - typeName := u.definition.InterfaceTypeDefinitionNameBytes(ref) - u.setCurrentTypeName(typeName, ast.NodeKindInterfaceTypeDefinition) -} - -func (u *uniqueFieldDefinitionNamesVisitor) LeaveInterfaceTypeDefinition(_ int) { - u.unsetCurrentTypeName() -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterInterfaceTypeExtension(ref int) { - typeName := u.definition.InterfaceTypeExtensionNameBytes(ref) - u.setCurrentTypeName(typeName, ast.NodeKindInterfaceTypeExtension) -} - -func (u *uniqueFieldDefinitionNamesVisitor) LeaveInterfaceTypeExtension(_ int) { - u.unsetCurrentTypeName() -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterInputObjectTypeDefinition(ref int) { - typeName := u.definition.InputObjectTypeDefinitionNameBytes(ref) - u.setCurrentTypeName(typeName, ast.NodeKindInputObjectTypeDefinition) -} - -func (u *uniqueFieldDefinitionNamesVisitor) LeaveInputObjectTypeDefinition(_ int) { - u.unsetCurrentTypeName() -} - -func (u *uniqueFieldDefinitionNamesVisitor) EnterInputObjectTypeExtension(ref int) { - typeName := u.definition.InputObjectTypeExtensionNameBytes(ref) - u.setCurrentTypeName(typeName, ast.NodeKindInputObjectTypeExtension) -} - -func (u *uniqueFieldDefinitionNamesVisitor) LeaveInputObjectTypeExtension(_ int) { - u.unsetCurrentTypeName() -} - -func (u *uniqueFieldDefinitionNamesVisitor) setCurrentTypeName(typeName ast.ByteSlice, kind ast.NodeKind) { - if bytes.HasPrefix(typeName, []byte("__")) { // ignore graphql reserved types - return - } - - u.currentTypeName = typeName - u.currentTypeNameHash = xxhash.Sum64(typeName) - u.currentTypeKind = kind -} - -func (u *uniqueFieldDefinitionNamesVisitor) unsetCurrentTypeName() { - u.currentTypeName = u.currentTypeName[:0] - u.currentTypeNameHash = 0 - u.currentTypeKind = ast.NodeKindUnknown -} - -func (u *uniqueFieldDefinitionNamesVisitor) checkField(fieldName ast.ByteSlice) { - if bytes.HasPrefix(fieldName, reservedFieldPrefix) { // don't validate graphql reserved fields - return - } - - if len(u.currentTypeName) == 0 || u.currentTypeNameHash == 0 || u.currentTypeKind == ast.NodeKindUnknown { - return - } - - fieldNames, ok := u.usedFieldNames[u.currentTypeNameHash] - if !ok { - fieldNames = make(hashedFieldNames) - } - - if fieldNames[xxhash.Sum64(fieldName)] { - u.Report.AddExternalError(operationreport.ErrFieldNameMustBeUniqueOnType(fieldName, u.currentTypeName)) - return - } - - fieldNames[xxhash.Sum64(fieldName)] = true - u.usedFieldNames[u.currentTypeNameHash] = fieldNames -} diff --git a/pkg/astvalidation/rule_unique_field_definition_names_test.go b/pkg/astvalidation/rule_unique_field_definition_names_test.go deleted file mode 100644 index 7b8b9a875..000000000 --- a/pkg/astvalidation/rule_unique_field_definition_names_test.go +++ /dev/null @@ -1,243 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestUniqueFieldDefinitionNames(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("no fields", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject - interface SomeInterface - input SomeInputObject - `, Valid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("one field", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject { - foo: String - } - interface SomeInterface { - foo: String - } - input SomeInputObject { - foo: String - } - `, Valid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("multiple field", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject { - foo: String - bar: String - } - interface SomeInterface { - foo: String - bar: String - } - input SomeInputObject { - foo: String - bar: String - } - `, Valid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("extend type with new field", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject { - foo: String - } - extend type SomeObject { - bar: String - } - extend type SomeObject { - baz: String - } - interface SomeInterface { - foo: String - } - extend interface SomeInterface { - bar: String - } - extend interface SomeInterface { - baz: String - } - input SomeInputObject { - foo: String - } - extend input SomeInputObject { - bar: String - } - extend input SomeInputObject { - baz: String - } - `, Valid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("fields with arguments having the same name", func(t *testing.T) { - runDefinitionValidation(t, ` - type Query { - continents(filter: String): String! - continent(code: ID!): String! - countries(filter: String): String! - country(code: ID!): String! - languages(filter: String): String! - language(code: ID!): String! - } - `, Valid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("duplicate fields inside the same type definition", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject { - foo: String - bar: String - foo: String - } - interface SomeInterface { - foo: String - bar: String - foo: String - } - input SomeInputObject { - foo: String - bar: String - foo: String - } - `, Invalid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("duplicate fields on root definition types", func(t *testing.T) { - runDefinitionValidation(t, ` - type Mutation { - default: String - } - type Query { - default: String - default: String - } - `, Invalid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("extend type with duplicate field", func(t *testing.T) { - runDefinitionValidation(t, ` - extend type SomeObject { - foo: String - } - type SomeObject { - foo: String - } - extend interface SomeInterface { - foo: String - } - interface SomeInterface { - foo: String - } - extend input SomeInputObject { - foo: String - } - input SomeInputObject { - foo: String - } - `, Invalid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("duplicate field inside extension", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject - extend type SomeObject { - foo: String - bar: String - foo: String - } - interface SomeInterface - extend interface SomeInterface { - foo: String - bar: String - foo: String - } - input SomeInputObject - extend input SomeInputObject { - foo: String - bar: String - foo: String - } - `, Invalid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("duplicate field inside different extensions", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject - extend type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - } - interface SomeInterface - extend interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - } - input SomeInputObject - extend input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - } - `, Invalid, UniqueFieldDefinitionNames(), - ) - }) - - t.Run("Duplicate input fields are invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - input SomeInputObject { - foo: String - } - extend input SomeInputObject { - foo: String - bar: String - } - `, Invalid, UniqueFieldDefinitionNames()) - }) - - t.Run("Duplicate object fields are invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - type SomeObject { - foo: String - } - extend type SomeObject { - foo: String - bar: String - } - `, Invalid, UniqueFieldDefinitionNames()) - }) - - t.Run("Duplicate interface fields are invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - interface SomeInterface { - foo: String - } - extend interface SomeInterface { - foo: String - bar: String - } - `, Invalid, UniqueFieldDefinitionNames()) - }) - }) -} diff --git a/pkg/astvalidation/rule_unique_operation_types.go b/pkg/astvalidation/rule_unique_operation_types.go deleted file mode 100644 index e80addf1d..000000000 --- a/pkg/astvalidation/rule_unique_operation_types.go +++ /dev/null @@ -1,54 +0,0 @@ -package astvalidation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func UniqueOperationTypes() Rule { - return func(walker *astvisitor.Walker) { - visitor := &uniqueOperationTypesVisitor{ - Walker: walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterRootOperationTypeDefinitionVisitor(visitor) - } -} - -type uniqueOperationTypesVisitor struct { - *astvisitor.Walker - definition *ast.Document - queryIsDefined bool - mutationIsDefined bool - subscriptionIsDefined bool -} - -func (u *uniqueOperationTypesVisitor) EnterDocument(operation, definition *ast.Document) { - u.definition = operation - u.queryIsDefined = false - u.mutationIsDefined = false - u.subscriptionIsDefined = false -} - -func (u *uniqueOperationTypesVisitor) EnterRootOperationTypeDefinition(ref int) { - operationType := u.definition.RootOperationTypeDefinitions[ref].OperationType - switch operationType { - case ast.OperationTypeQuery: - if u.queryIsDefined { - u.Report.AddExternalError(operationreport.ErrOnlyOneQueryTypeAllowed()) - } - u.queryIsDefined = true - case ast.OperationTypeMutation: - if u.mutationIsDefined { - u.Report.AddExternalError(operationreport.ErrOnlyOneMutationTypeAllowed()) - } - u.mutationIsDefined = true - case ast.OperationTypeSubscription: - if u.subscriptionIsDefined { - u.Report.AddExternalError(operationreport.ErrOnlyOneSubscriptionTypeAllowed()) - } - u.subscriptionIsDefined = true - } -} diff --git a/pkg/astvalidation/rule_unique_operation_types_test.go b/pkg/astvalidation/rule_unique_operation_types_test.go deleted file mode 100644 index 0c2385779..000000000 --- a/pkg/astvalidation/rule_unique_operation_types_test.go +++ /dev/null @@ -1,123 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestUniqueOperationTypes(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("no schema definition", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - `, Valid, UniqueOperationTypes(), - ) - }) - - t.Run("schema definition with all types", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { - query: Foo - mutation: Foo - subscription: Foo - } - `, Valid, UniqueOperationTypes(), - ) - }) - - t.Run("schema definition with single extension", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { query: Foo } - extend schema { - mutation: Foo - subscription: Foo - } - `, Valid, UniqueOperationTypes(), - ) - }) - - t.Run("schema definition with separate extensions", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { query: Foo } - extend schema { mutation: Foo } - extend schema { subscription: Foo } - `, Valid, UniqueOperationTypes(), - ) - }) - - t.Run("duplicate operation types inside single schema definition", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { - query: Foo - mutation: Foo - subscription: Foo - query: Foo - mutation: Foo - subscription: Foo - } - `, Invalid, UniqueOperationTypes(), - ) - }) - - t.Run("duplicate operation types inside schema extension", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { - query: Foo - mutation: Foo - subscription: Foo - } - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `, Invalid, UniqueOperationTypes(), - ) - }) - - t.Run("duplicate operation types inside schema extension twice", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { - query: Foo - mutation: Foo - subscription: Foo - } - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `, Invalid, UniqueOperationTypes(), - ) - }) - - t.Run("duplicate operation types inside second schema extension", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - schema { - query: Foo - } - extend schema { - mutation: Foo - subscription: Foo - } - extend schema { - query: Foo - mutation: Foo - subscription: Foo - } - `, Invalid, UniqueOperationTypes(), - ) - }) - }) -} diff --git a/pkg/astvalidation/rule_unique_type_names.go b/pkg/astvalidation/rule_unique_type_names.go deleted file mode 100644 index 701ef7a9a..000000000 --- a/pkg/astvalidation/rule_unique_type_names.go +++ /dev/null @@ -1,75 +0,0 @@ -package astvalidation - -import ( - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func UniqueTypeNames() Rule { - return func(walker *astvisitor.Walker) { - visitor := &uniqueTypeNamesVisitor{ - Walker: walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterScalarTypeDefinitionVisitor(visitor) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(visitor) - walker.RegisterEnterUnionTypeDefinitionVisitor(visitor) - walker.RegisterEnterEnumTypeDefinitionVisitor(visitor) - walker.RegisterEnterInputObjectTypeDefinitionVisitor(visitor) - } -} - -type uniqueTypeNamesVisitor struct { - *astvisitor.Walker - definition *ast.Document - usedTypeNamesAsHash map[uint64]bool -} - -func (u *uniqueTypeNamesVisitor) EnterDocument(operation, definition *ast.Document) { - u.definition = operation - u.usedTypeNamesAsHash = make(map[uint64]bool) -} - -func (u *uniqueTypeNamesVisitor) EnterObjectTypeDefinition(ref int) { - typeName := u.definition.ObjectTypeDefinitionNameBytes(ref) - u.checkTypeName(typeName) -} - -func (u *uniqueTypeNamesVisitor) EnterScalarTypeDefinition(ref int) { - typeName := u.definition.ScalarTypeDefinitionNameBytes(ref) - u.checkTypeName(typeName) -} - -func (u *uniqueTypeNamesVisitor) EnterInterfaceTypeDefinition(ref int) { - typeName := u.definition.InterfaceTypeDefinitionNameBytes(ref) - u.checkTypeName(typeName) -} - -func (u *uniqueTypeNamesVisitor) EnterUnionTypeDefinition(ref int) { - typeName := u.definition.UnionTypeDefinitionNameBytes(ref) - u.checkTypeName(typeName) -} - -func (u *uniqueTypeNamesVisitor) EnterEnumTypeDefinition(ref int) { - typeName := u.definition.EnumTypeDefinitionNameBytes(ref) - u.checkTypeName(typeName) -} - -func (u *uniqueTypeNamesVisitor) EnterInputObjectTypeDefinition(ref int) { - typeName := u.definition.InputObjectTypeDefinitionNameBytes(ref) - u.checkTypeName(typeName) -} - -func (u *uniqueTypeNamesVisitor) checkTypeName(typeName ast.ByteSlice) { - hashedTypeName := xxhash.Sum64(typeName) - if u.usedTypeNamesAsHash[hashedTypeName] { - u.Report.AddExternalError(operationreport.ErrTypeNameMustBeUnique(typeName)) - return - } - u.usedTypeNamesAsHash[hashedTypeName] = true -} diff --git a/pkg/astvalidation/rule_unique_type_names_test.go b/pkg/astvalidation/rule_unique_type_names_test.go deleted file mode 100644 index 0357ebfec..000000000 --- a/pkg/astvalidation/rule_unique_type_names_test.go +++ /dev/null @@ -1,106 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestUniqueTypeNames(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("no types", func(t *testing.T) { - runDefinitionValidation(t, ` - directive @test on SCHEMA - `, Valid, UniqueTypeNames(), - ) - }) - - t.Run("one type", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - `, Valid, UniqueTypeNames(), - ) - }) - - t.Run("many types", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - type Bar - type Baz - `, Valid, UniqueTypeNames(), - ) - }) - - t.Run("type and non-type definitions named the same", func(t *testing.T) { - // Note: graphql-js uses following test case - // query Foo { __typename } - // fragment Foo on Query { __typename } - // directive @Foo on SCHEMA - // type Foo - runDefinitionValidation(t, ` - directive @Foo on SCHEMA - type Foo - `, Valid, UniqueTypeNames(), - ) - }) - - t.Run("types and non-types named different", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - scalar FooScalar - type FooBar - interface FooInterface - union FooUnion - enum FooEnum - input FooInput - `, Valid, UniqueTypeNames(), - ) - }) - - t.Run("types named the same", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - type Foo - `, Invalid, UniqueTypeNames(), - ) - }) - - t.Run("type and scalar named the same", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - scalar Foo - `, Invalid, UniqueTypeNames(), - ) - }) - - t.Run("type and interface named the same", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - interface Foo - `, Invalid, UniqueTypeNames(), - ) - }) - - t.Run("type and union named the same", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - union Foo - `, Invalid, UniqueTypeNames(), - ) - }) - - t.Run("type and enum named the same", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - enum Foo - `, Invalid, UniqueTypeNames(), - ) - }) - - t.Run("type and input named the same", func(t *testing.T) { - runDefinitionValidation(t, ` - type Foo - input Foo - `, Invalid, UniqueTypeNames(), - ) - }) - }) -} diff --git a/pkg/astvalidation/rule_unique_union_member_types.go b/pkg/astvalidation/rule_unique_union_member_types.go deleted file mode 100644 index 204a2ac53..000000000 --- a/pkg/astvalidation/rule_unique_union_member_types.go +++ /dev/null @@ -1,93 +0,0 @@ -package astvalidation - -import ( - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type hashedMembers map[uint64]bool - -type uniqueUnionMemberTypesVisitor struct { - *astvisitor.Walker - definition *ast.Document - currentUnionName ast.ByteSlice - currentUnionHash uint64 - presentMembers map[uint64]hashedMembers -} - -func UniqueUnionMemberTypes() Rule { - return func(walker *astvisitor.Walker) { - visitor := &uniqueUnionMemberTypesVisitor{ - Walker: walker, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterUnionTypeDefinitionVisitor(visitor) - walker.RegisterEnterUnionMemberTypeVisitor(visitor) - walker.RegisterUnionTypeDefinitionVisitor(visitor) - walker.RegisterUnionTypeExtensionVisitor(visitor) - } -} - -func (u *uniqueUnionMemberTypesVisitor) EnterDocument(operation, _ *ast.Document) { - u.definition = operation - u.currentUnionName = u.currentUnionName[:0] - u.currentUnionHash = 0 - u.presentMembers = make(map[uint64]hashedMembers) -} - -func (u *uniqueUnionMemberTypesVisitor) EnterUnionTypeDefinition(ref int) { - unionName := u.definition.UnionTypeDefinitionNameBytes(ref) - u.setCurrentUnion(unionName) -} - -func (u *uniqueUnionMemberTypesVisitor) LeaveUnionTypeDefinition(_ int) { - u.unsetCurrentUnion() -} - -func (u *uniqueUnionMemberTypesVisitor) EnterUnionMemberType(ref int) { - memberName := u.definition.TypeNameBytes(ref) - u.checkMemberName(memberName) -} - -func (u *uniqueUnionMemberTypesVisitor) EnterUnionTypeExtension(ref int) { - unionName := u.definition.UnionTypeExtensionNameBytes(ref) - u.setCurrentUnion(unionName) -} - -func (u *uniqueUnionMemberTypesVisitor) LeaveUnionTypeExtension(_ int) { - u.unsetCurrentUnion() -} - -func (u *uniqueUnionMemberTypesVisitor) setCurrentUnion(unionName ast.ByteSlice) { - u.currentUnionName = unionName - u.currentUnionHash = xxhash.Sum64(unionName) -} - -func (u *uniqueUnionMemberTypesVisitor) unsetCurrentUnion() { - u.currentUnionName = u.currentUnionName[:0] - u.currentUnionHash = 0 -} - -func (u *uniqueUnionMemberTypesVisitor) checkMemberName(memberName ast.ByteSlice) { - if len(u.currentUnionName) == 0 || u.currentUnionHash == 0 { - return - } - - memberNameHash := xxhash.Sum64(memberName) - memberNames, ok := u.presentMembers[u.currentUnionHash] - if !ok { - memberNames = make(hashedMembers) - } - - if memberNames[memberNameHash] { - u.Report.AddExternalError(operationreport.ErrUnionMembersMustBeUnique(u.currentUnionName, memberName)) - return - } - - memberNames[memberNameHash] = true - u.presentMembers[u.currentUnionHash] = memberNames -} diff --git a/pkg/astvalidation/rule_unique_union_member_types_test.go b/pkg/astvalidation/rule_unique_union_member_types_test.go deleted file mode 100644 index 0783ac5e7..000000000 --- a/pkg/astvalidation/rule_unique_union_member_types_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package astvalidation - -import ( - "testing" -) - -func TestUniqueMemberTypes(t *testing.T) { - t.Run("Definition", func(t *testing.T) { - t.Run("Union with a single member is valid", func(t *testing.T) { - runDefinitionValidation(t, ` - union Foo = Bar - `, Valid, UniqueUnionMemberTypes(), - ) - }) - - t.Run("Union with many members is valid", func(t *testing.T) { - runDefinitionValidation(t, ` - union Foo = Bar | FooBar | BarFoo - `, Valid, UniqueUnionMemberTypes(), - ) - }) - - t.Run("Union with duplicate members is invalid", func(t *testing.T) { - runDefinitionValidation(t, ` - union Foo = Bar | Bar - `, Invalid, UniqueUnionMemberTypes(), - ) - }) - }) -} diff --git a/pkg/astvalidation/validation_state.go b/pkg/astvalidation/validation_state.go deleted file mode 100644 index 00f7eb716..000000000 --- a/pkg/astvalidation/validation_state.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:generate stringer -type=ValidationState -output validation_state_string.go - -package astvalidation - -// ValidationState is the outcome of a validation -type ValidationState int - -const ( - UnknownState ValidationState = iota - Valid - Invalid -) diff --git a/pkg/astvalidation/validation_state_string.go b/pkg/astvalidation/validation_state_string.go deleted file mode 100644 index 686555d01..000000000 --- a/pkg/astvalidation/validation_state_string.go +++ /dev/null @@ -1,25 +0,0 @@ -// Code generated by "stringer -type=ValidationState -output validation_state_string.go"; DO NOT EDIT. - -package astvalidation - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[UnknownState-0] - _ = x[Valid-1] - _ = x[Invalid-2] -} - -const _ValidationState_name = "UnknownStateValidInvalid" - -var _ValidationState_index = [...]uint8{0, 12, 17, 24} - -func (i ValidationState) String() string { - if i < 0 || i >= ValidationState(len(_ValidationState_index)-1) { - return "ValidationState(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _ValidationState_name[_ValidationState_index[i]:_ValidationState_index[i+1]] -} diff --git a/pkg/astvisitor/astvisitor.go b/pkg/astvisitor/astvisitor.go deleted file mode 100644 index 49c522c61..000000000 --- a/pkg/astvisitor/astvisitor.go +++ /dev/null @@ -1,8 +0,0 @@ -// Package astvisitor enables efficient and powerful traversal of GraphQL document AST's. -// -// Visitor has more options to configure the behaviour and offers more meta data than SimpleVisitor. -// SimpleVisitor on the other hand is more performant. -// -// If all Nodes should be visited and not much meta data is needed, go with SimpleVisitor. -// If you only need to visit a subset of Nodes or want specific meta data, e.g. TypeDefinitions you should go with Visitor. -package astvisitor diff --git a/pkg/astvisitor/fixtures/path.golden b/pkg/astvisitor/fixtures/path.golden deleted file mode 100644 index 7856363df..000000000 --- a/pkg/astvisitor/fixtures/path.golden +++ /dev/null @@ -1,14 +0,0 @@ -EnterField: posts, path: [query] -EnterField: id, path: [query,posts] -EnterField: description, path: [query,posts] -EnterField: user, path: [query,posts] -EnterField: id, path: [query,posts,user] -EnterField: name, path: [query,posts,user] -EnterField: posts, path: [query] -EnterField: id, path: [query,posts] -EnterField: description, path: [query,posts] -EnterField: user, path: [query,posts] -EnterField: id, path: [query,posts,user] -EnterField: name, path: [query,posts,user] -EnterField: posts, path: [query,posts,user] -EnterField: id, path: [query,posts,user,posts] diff --git a/pkg/astvisitor/fixtures/schema_visitor.golden b/pkg/astvisitor/fixtures/schema_visitor.golden deleted file mode 100644 index b832463a6..000000000 --- a/pkg/astvisitor/fixtures/schema_visitor.golden +++ /dev/null @@ -1,87 +0,0 @@ -EnterDirectiveDefinition(awesome): ref: 0 - EnterDirectiveLocation(TypeSystemDirectiveLocationSchema) - LeaveDirectiveLocation(TypeSystemDirectiveLocationSchema) - EnterDirectiveLocation(TypeSystemDirectiveLocationScalar) - LeaveDirectiveLocation(TypeSystemDirectiveLocationScalar) -LeaveDirectiveDefinition(awesome): ref: 0 - -EnterObjectTypeDefinition(Foo): ref: 0 - EnterFieldDefinition(field): ref: 0 - LeaveFieldDefinition(field): ref: 0 -LeaveObjectTypeDefinition(Foo): ref: 0 - -EnterObjectTypeDefinition(FooBar): ref: 1 - EnterFieldDefinition(field): ref: 1 - LeaveFieldDefinition(field): ref: 1 -LeaveObjectTypeDefinition(FooBar): ref: 1 - -EnterObjectTypeExtension(Foo): ref: 0 - EnterFieldDefinition(field2): ref: 2 - LeaveFieldDefinition(field2): ref: 2 -LeaveObjectTypeExtension(Foo): ref: 0 - -EnterInterfaceTypeDefinition(Bar): ref: 0 - EnterFieldDefinition(field): ref: 3 - LeaveFieldDefinition(field): ref: 3 -LeaveInterfaceTypeDefinition(Bar): ref: 0 - -EnterInterfaceTypeExtension(Bar): ref: 0 - EnterFieldDefinition(field2): ref: 4 - LeaveFieldDefinition(field2): ref: 4 -LeaveInterfaceTypeExtension(Bar): ref: 0 - -EnterEnumTypeDefinition(Bat): ref: 0 - EnterEnumValueDefinition(BAR): ref: 0 - LeaveEnumValueDefinition(BAR): ref: 0 -LeaveEnumTypeDefinition(Bat): ref: 0 - -EnterEnumTypeExtension(Bat): ref: 0 - EnterEnumValueDefinition(BAL): ref: 1 - LeaveEnumValueDefinition(BAL): ref: 1 -LeaveEnumTypeExtension(Bat): ref: 0 - -EnterUnionTypeDefinition(Fooniun): ref: 0 - EnterUnionMemberType(Foo): ref: 5 - LeaveUnionMemberType(Foo): ref: 5 -LeaveUnionTypeDefinition(Fooniun): ref: 0 - -EnterUnionTypeExtension(Fooniun): ref: 0 - EnterUnionMemberType(FooBar): ref: 6 - LeaveUnionMemberType(FooBar): ref: 6 -LeaveUnionTypeExtension(Fooniun): ref: 0 - -EnterInputObjectTypeDefinition(Bart): ref: 0 - EnterInputValueDefinition(field): ref: 0 - LeaveInputValueDefinition(field): ref: 0 -LeaveInputObjectTypeDefinition(Bart): ref: 0 - -EnterInputObjectTypeExtension(Bart): ref: 0 - EnterInputValueDefinition(field2): ref: 1 - LeaveInputValueDefinition(field2): ref: 1 -LeaveInputObjectTypeExtension(Bart): ref: 0 - -EnterScalarTypeDefinition(JSON): ref: 0 -LeaveScalarTypeDefinition(JSON): ref: 0 - -EnterScalarTypeExtension(JSON): ref: 0 - EnterDirective(awesome): ref: 0 - LeaveDirective(awesome): ref: 0 -LeaveScalarTypeExtension(JSON): ref: 0 - -EnterSchemaDefinition: ref: 0 - EnterRootOperationTypeDefinition(OperationTypeQuery): ref: 0 - LeaveRootOperationTypeDefinition(OperationTypeQuery): ref: 0 - EnterRootOperationTypeDefinition(OperationTypeMutation): ref: 1 - LeaveRootOperationTypeDefinition(OperationTypeMutation): ref: 1 -LeaveSchemaDefinition: ref: 0 - -EnterSchemaExtension: ref: 0 - EnterDirective(awesome): ref: 1 - LeaveDirective(awesome): ref: 1 -LeaveSchemaExtension: ref: 0 - -EnterSchemaExtension: ref: 1 - EnterRootOperationTypeDefinition(OperationTypeSubscription): ref: 2 - LeaveRootOperationTypeDefinition(OperationTypeSubscription): ref: 2 -LeaveSchemaExtension: ref: 1 - diff --git a/pkg/astvisitor/fixtures/visitor.golden b/pkg/astvisitor/fixtures/visitor.golden deleted file mode 100644 index 640e1ad04..000000000 --- a/pkg/astvisitor/fixtures/visitor.golden +++ /dev/null @@ -1,77 +0,0 @@ -EnterOperationDefinition (PostsUserQuery): ref: 0 - EnterSelectionSet(Query): ref: 2 - EnterField(posts::Query): ref: 5 - EnterSelectionSet(Post): ref: 1 - EnterField(id::Post): ref: 0 - LeaveField(id::Post): ref: 0 - EnterField(description::Post): ref: 1 - LeaveField(description::Post): ref: 1 - EnterField(user::Post): ref: 4 - EnterSelectionSet(User): ref: 0 - EnterField(id::User): ref: 2 - LeaveField(id::User): ref: 2 - EnterField(name::User): ref: 3 - LeaveField(name::User): ref: 3 - LeaveSelectionSet(User): ref: 0 - LeaveField(user::Post): ref: 4 - LeaveSelectionSet(Post): ref: 1 - LeaveField(posts::Query): ref: 5 - LeaveSelectionSet(Query): ref: 2 -LeaveOperationDefinition(PostsUserQuery): ref: 0 - -EnterFragmentDefinition(FirstFragment): ref: 0 - EnterSelectionSet(Post): ref: 3 - EnterField(id::Post): ref: 6 - LeaveField(id::Post): ref: 6 - LeaveSelectionSet(Post): ref: 3 -LeaveFragmentDefinition(FirstFragment): ref: 0 - -EnterOperationDefinition (ArgsQuery): ref: 1 - EnterSelectionSet(Query): ref: 5 - EnterField(foo::Query): ref: 8 - EnterArgument(bar::Foo): ref: 0 - LeaveArgument(bar::Foo): ref: 0 - EnterArgument(baz::Foo): ref: 1 - LeaveArgument(baz::Foo): ref: 1 - EnterSelectionSet(Foo): ref: 4 - EnterField(fooField::Foo): ref: 7 - LeaveField(fooField::Foo): ref: 7 - LeaveSelectionSet(Foo): ref: 4 - LeaveField(foo::Query): ref: 8 - LeaveSelectionSet(Query): ref: 5 -LeaveOperationDefinition(ArgsQuery): ref: 1 - -EnterOperationDefinition (VariableQuery): ref: 2 - EnterVariableDefinition(bar): ref: 0 - LeaveVariableDefinition(bar): ref: 0 - EnterVariableDefinition(baz): ref: 1 - LeaveVariableDefinition(baz): ref: 1 - EnterSelectionSet(Query): ref: 7 - EnterField(foo::Query): ref: 10 - EnterArgument(bar::Foo): ref: 2 - LeaveArgument(bar::Foo): ref: 2 - EnterArgument(baz::Foo): ref: 3 - LeaveArgument(baz::Foo): ref: 3 - EnterSelectionSet(Foo): ref: 6 - EnterField(fooField::Foo): ref: 9 - LeaveField(fooField::Foo): ref: 9 - LeaveSelectionSet(Foo): ref: 6 - LeaveField(foo::Query): ref: 10 - LeaveSelectionSet(Query): ref: 7 -LeaveOperationDefinition(VariableQuery): ref: 2 - -EnterOperationDefinition (VariableQuery): ref: 3 - EnterSelectionSet(Query): ref: 9 - EnterField(posts::Query): ref: 12 - EnterSelectionSet(Post): ref: 8 - EnterField(id::Post): ref: 11 - EnterDirective(include): ref: 0 - EnterArgument(if::ID): ref: 4 - LeaveArgument(if::ID): ref: 4 - LeaveDirective(include): ref: 0 - LeaveField(id::Post): ref: 11 - LeaveSelectionSet(Post): ref: 8 - LeaveField(posts::Query): ref: 12 - LeaveSelectionSet(Query): ref: 9 -LeaveOperationDefinition(VariableQuery): ref: 3 - diff --git a/pkg/astvisitor/fixtures/visitor_skip.golden b/pkg/astvisitor/fixtures/visitor_skip.golden deleted file mode 100644 index f532a6c87..000000000 --- a/pkg/astvisitor/fixtures/visitor_skip.golden +++ /dev/null @@ -1,13 +0,0 @@ -EnterOperationDefinition (PostsUserQuery): ref: 0 - EnterSelectionSet(Query): ref: 2 - EnterField(posts::Query): ref: 5 - EnterSelectionSet(Post): ref: 1 - EnterField(id::Post): ref: 0 - LeaveField(id::Post): ref: 0 - EnterField(description::Post): ref: 1 - LeaveField(description::Post): ref: 1 - LeaveSelectionSet(Post): ref: 1 - LeaveField(posts::Query): ref: 5 - LeaveSelectionSet(Query): ref: 2 -LeaveOperationDefinition(PostsUserQuery): ref: 0 - diff --git a/pkg/astvisitor/simplevisitor.go b/pkg/astvisitor/simplevisitor.go deleted file mode 100644 index d52be379c..000000000 --- a/pkg/astvisitor/simplevisitor.go +++ /dev/null @@ -1,787 +0,0 @@ -package astvisitor - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -type SimpleWalker struct { - err error - document *ast.Document - Depth int - Ancestors []ast.Node - visitor AllNodesVisitor - SelectionsBefore []int - SelectionsAfter []int -} - -func NewSimpleWalker(ancestorSize int) SimpleWalker { - return SimpleWalker{ - Ancestors: make([]ast.Node, 0, ancestorSize), - } -} - -func (w *SimpleWalker) SetVisitor(visitor AllNodesVisitor) { - w.visitor = visitor -} - -func (w *SimpleWalker) Walk(document, definition *ast.Document) error { - return w.WalkDocument(document) -} - -func (w *SimpleWalker) WalkDocument(document *ast.Document) error { - - if w.visitor == nil { - return fmt.Errorf("visitor must not be nil, use SetVisitor()") - } - - w.err = nil - w.Ancestors = w.Ancestors[:0] - w.document = document - w.Depth = 0 - w.walk() - return w.err -} - -func (w *SimpleWalker) appendAncestor(ref int, kind ast.NodeKind) { - w.Ancestors = append(w.Ancestors, ast.Node{ - Kind: kind, - Ref: ref, - }) -} - -func (w *SimpleWalker) removeLastAncestor() { - w.Ancestors = w.Ancestors[:len(w.Ancestors)-1] -} - -func (w *SimpleWalker) increaseDepth() { - w.Depth++ -} - -func (w *SimpleWalker) decreaseDepth() { - w.Depth-- -} - -func (w *SimpleWalker) walk() { - - if w.document == nil { - w.err = fmt.Errorf("document must not be nil") - return - } - - w.visitor.EnterDocument(w.document, nil) - - for i := range w.document.RootNodes { - isLast := i == len(w.document.RootNodes)-1 - switch w.document.RootNodes[i].Kind { - case ast.NodeKindOperationDefinition: - w.walkOperationDefinition(w.document.RootNodes[i].Ref, isLast) - case ast.NodeKindFragmentDefinition: - w.walkFragmentDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindSchemaDefinition: - w.walkSchemaDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindSchemaExtension: - w.walkSchemaExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindDirectiveDefinition: - w.walkDirectiveDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindObjectTypeDefinition: - w.walkObjectTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindObjectTypeExtension: - w.walkObjectTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindInterfaceTypeDefinition: - w.walkInterfaceTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindInterfaceTypeExtension: - w.walkInterfaceTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindScalarTypeDefinition: - w.walkScalarTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindScalarTypeExtension: - w.walkScalarTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindUnionTypeDefinition: - w.walkUnionTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindUnionTypeExtension: - w.walkUnionTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindEnumTypeDefinition: - w.walkEnumTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindEnumTypeExtension: - w.walkEnumTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindInputObjectTypeDefinition: - w.walkInputObjectTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindInputObjectTypeExtension: - w.walkInputObjectTypeExtension(w.document.RootNodes[i].Ref) - } - } - - w.visitor.LeaveDocument(w.document, nil) -} - -func (w *SimpleWalker) walkOperationDefinition(ref int, isLastRootNode bool) { - w.increaseDepth() - - w.visitor.EnterOperationDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindOperationDefinition) - - if w.document.OperationDefinitions[ref].HasVariableDefinitions { - for _, i := range w.document.OperationDefinitions[ref].VariableDefinitions.Refs { - w.walkVariableDefinition(i) - } - } - - if w.document.OperationDefinitions[ref].HasDirectives { - for _, i := range w.document.OperationDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.OperationDefinitions[ref].HasSelections { - w.walkSelectionSet(w.document.OperationDefinitions[ref].SelectionSet) - } - - w.removeLastAncestor() - - w.visitor.LeaveOperationDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkVariableDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterVariableDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindVariableDefinition) - - if w.document.VariableDefinitions[ref].HasDirectives { - for _, i := range w.document.VariableDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveVariableDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkSelectionSet(ref int) { - w.increaseDepth() - - w.visitor.EnterSelectionSet(ref) - - w.appendAncestor(ref, ast.NodeKindSelectionSet) - - for i, j := range w.document.SelectionSets[ref].SelectionRefs { - - w.SelectionsBefore = w.document.SelectionSets[ref].SelectionRefs[:i] - w.SelectionsAfter = w.document.SelectionSets[ref].SelectionRefs[i+1:] - - switch w.document.Selections[j].Kind { - case ast.SelectionKindField: - w.walkField(w.document.Selections[j].Ref) - case ast.SelectionKindFragmentSpread: - w.walkFragmentSpread(w.document.Selections[j].Ref) - case ast.SelectionKindInlineFragment: - w.walkInlineFragment(w.document.Selections[j].Ref) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveSelectionSet(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkField(ref int) { - w.increaseDepth() - - selectionsBefore := w.SelectionsBefore - selectionsAfter := w.SelectionsAfter - w.visitor.EnterField(ref) - - w.appendAncestor(ref, ast.NodeKindField) - - if len(w.document.Fields[ref].Arguments.Refs) != 0 { - for _, i := range w.document.Fields[ref].Arguments.Refs { - w.walkArgument(i) - } - } - - if w.document.Fields[ref].HasDirectives { - for _, i := range w.document.Fields[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.Fields[ref].HasSelections { - w.walkSelectionSet(w.document.Fields[ref].SelectionSet) - } - - w.removeLastAncestor() - - w.SelectionsBefore = selectionsBefore - w.SelectionsAfter = selectionsAfter - w.visitor.LeaveField(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkDirective(ref int) { - w.increaseDepth() - - w.visitor.EnterDirective(ref) - - w.appendAncestor(ref, ast.NodeKindDirective) - - if w.document.Directives[ref].HasArguments { - for _, i := range w.document.Directives[ref].Arguments.Refs { - w.walkArgument(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveDirective(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkArgument(ref int) { - w.increaseDepth() - - w.visitor.EnterArgument(ref) - w.visitor.LeaveArgument(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkFragmentSpread(ref int) { - w.increaseDepth() - - w.visitor.EnterFragmentSpread(ref) - w.visitor.LeaveFragmentSpread(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkInlineFragment(ref int) { - w.increaseDepth() - - selectionsBefore := w.SelectionsBefore - selectionsAfter := w.SelectionsAfter - w.visitor.EnterInlineFragment(ref) - - w.appendAncestor(ref, ast.NodeKindInlineFragment) - - if w.document.InlineFragments[ref].HasDirectives { - for _, i := range w.document.InlineFragments[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.InlineFragments[ref].HasSelections { - w.walkSelectionSet(w.document.InlineFragments[ref].SelectionSet) - } - - w.removeLastAncestor() - - w.SelectionsBefore = selectionsBefore - w.SelectionsAfter = selectionsAfter - w.visitor.LeaveInlineFragment(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkFragmentDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterFragmentDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindFragmentDefinition) - - if w.document.FragmentDefinitions[ref].HasDirectives { - for _, i := range w.document.FragmentDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.FragmentDefinitions[ref].HasSelections { - w.walkSelectionSet(w.document.FragmentDefinitions[ref].SelectionSet) - } - - w.removeLastAncestor() - - w.visitor.LeaveFragmentDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkObjectTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterObjectTypeDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindObjectTypeDefinition) - - if w.document.ObjectTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.ObjectTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.ObjectTypeDefinitions[ref].HasFieldDefinitions { - for _, i := range w.document.ObjectTypeDefinitions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveObjectTypeDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkObjectTypeExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterObjectTypeExtension(ref) - w.appendAncestor(ref, ast.NodeKindObjectTypeExtension) - - if w.document.ObjectTypeExtensions[ref].HasDirectives { - for _, i := range w.document.ObjectTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.ObjectTypeExtensions[ref].HasFieldDefinitions { - for _, i := range w.document.ObjectTypeExtensions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveObjectTypeExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkFieldDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterFieldDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindFieldDefinition) - - if w.document.FieldDefinitions[ref].HasArgumentsDefinitions { - for _, i := range w.document.FieldDefinitions[ref].ArgumentsDefinition.Refs { - w.walkInputValueDefinition(i) - } - } - - if w.document.FieldDefinitions[ref].HasDirectives { - for _, i := range w.document.FieldDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveFieldDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkInputValueDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterInputValueDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindInputValueDefinition) - - if w.document.InputValueDefinitions[ref].HasDirectives { - for _, i := range w.document.InputValueDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveInputValueDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkInterfaceTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterInterfaceTypeDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindInterfaceTypeDefinition) - - if w.document.InterfaceTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.InterfaceTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.InterfaceTypeDefinitions[ref].HasFieldDefinitions { - for _, i := range w.document.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveInterfaceTypeDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkInterfaceTypeExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterInterfaceTypeExtension(ref) - - w.appendAncestor(ref, ast.NodeKindInterfaceTypeExtension) - - if w.document.InterfaceTypeExtensions[ref].HasDirectives { - for _, i := range w.document.InterfaceTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.InterfaceTypeExtensions[ref].HasFieldDefinitions { - for _, i := range w.document.InterfaceTypeExtensions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveInterfaceTypeExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkScalarTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterScalarTypeDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindScalarTypeDefinition) - - if w.document.ScalarTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.ScalarTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveScalarTypeDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkScalarTypeExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterScalarTypeExtension(ref) - - w.appendAncestor(ref, ast.NodeKindScalarTypeExtension) - - if w.document.ScalarTypeExtensions[ref].HasDirectives { - for _, i := range w.document.ScalarTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveScalarTypeExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkUnionTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterUnionTypeDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindUnionTypeDefinition) - - if w.document.UnionTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.UnionTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.UnionTypeDefinitions[ref].HasUnionMemberTypes { - for _, i := range w.document.UnionTypeDefinitions[ref].UnionMemberTypes.Refs { - w.walkUnionMemberType(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveUnionTypeDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkUnionTypeExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterUnionTypeExtension(ref) - - w.appendAncestor(ref, ast.NodeKindUnionTypeExtension) - - if w.document.UnionTypeExtensions[ref].HasDirectives { - for _, i := range w.document.UnionTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.UnionTypeExtensions[ref].HasUnionMemberTypes { - for _, i := range w.document.UnionTypeExtensions[ref].UnionMemberTypes.Refs { - w.walkUnionMemberType(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveUnionTypeExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkUnionMemberType(ref int) { - w.increaseDepth() - - w.visitor.EnterUnionMemberType(ref) - - w.visitor.LeaveUnionMemberType(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkEnumTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterEnumTypeDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindEnumTypeDefinition) - - if w.document.EnumTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.EnumTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinition { - for _, i := range w.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs { - w.walkEnumValueDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveEnumTypeDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkEnumTypeExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterEnumTypeExtension(ref) - - w.appendAncestor(ref, ast.NodeKindEnumTypeExtension) - - if w.document.EnumTypeExtensions[ref].HasDirectives { - for _, i := range w.document.EnumTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinition { - for _, i := range w.document.EnumTypeExtensions[ref].EnumValuesDefinition.Refs { - w.walkEnumValueDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveEnumTypeExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkEnumValueDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterEnumValueDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindEnumValueDefinition) - - if w.document.EnumValueDefinitions[ref].HasDirectives { - for _, i := range w.document.EnumValueDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveEnumValueDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkInputObjectTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterInputObjectTypeDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindInputObjectTypeDefinition) - - if w.document.InputObjectTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.InputObjectTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition { - for _, i := range w.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs { - w.walkInputValueDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveInputObjectTypeDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkInputObjectTypeExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterInputObjectTypeExtension(ref) - - w.appendAncestor(ref, ast.NodeKindInputObjectTypeExtension) - - if w.document.InputObjectTypeExtensions[ref].HasDirectives { - for _, i := range w.document.InputObjectTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinition { - for _, i := range w.document.InputObjectTypeExtensions[ref].InputFieldsDefinition.Refs { - w.walkInputValueDefinition(i) - } - } - - w.removeLastAncestor() - - w.visitor.LeaveInputObjectTypeExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkDirectiveDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterDirectiveDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindDirectiveDefinition) - - if w.document.DirectiveDefinitions[ref].HasArgumentsDefinitions { - for _, i := range w.document.DirectiveDefinitions[ref].ArgumentsDefinition.Refs { - w.walkInputValueDefinition(i) - } - } - - iter := w.document.DirectiveDefinitions[ref].DirectiveLocations.Iterable() - for iter.Next() { - w.walkDirectiveLocation(iter.Value()) - } - - w.removeLastAncestor() - - w.visitor.LeaveDirectiveDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkDirectiveLocation(location ast.DirectiveLocation) { - w.increaseDepth() - - w.visitor.EnterDirectiveLocation(location) - - w.visitor.LeaveDirectiveLocation(location) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkSchemaDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterSchemaDefinition(ref) - - w.appendAncestor(ref, ast.NodeKindSchemaDefinition) - - if w.document.SchemaDefinitions[ref].HasDirectives { - for _, i := range w.document.SchemaDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - for _, i := range w.document.SchemaDefinitions[ref].RootOperationTypeDefinitions.Refs { - w.walkRootOperationTypeDefinition(i) - } - - w.removeLastAncestor() - - w.visitor.LeaveSchemaDefinition(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkSchemaExtension(ref int) { - w.increaseDepth() - - w.visitor.EnterSchemaExtension(ref) - - w.appendAncestor(ref, ast.NodeKindSchemaExtension) - - if w.document.SchemaExtensions[ref].HasDirectives { - for _, i := range w.document.SchemaExtensions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - for _, i := range w.document.SchemaExtensions[ref].RootOperationTypeDefinitions.Refs { - w.walkRootOperationTypeDefinition(i) - } - - w.removeLastAncestor() - - w.visitor.LeaveSchemaExtension(ref) - - w.decreaseDepth() -} - -func (w *SimpleWalker) walkRootOperationTypeDefinition(ref int) { - w.increaseDepth() - - w.visitor.EnterRootOperationTypeDefinition(ref) - - w.visitor.LeaveRootOperationTypeDefinition(ref) - - w.decreaseDepth() -} diff --git a/pkg/astvisitor/simplevisitor_test.go b/pkg/astvisitor/simplevisitor_test.go deleted file mode 100644 index 9c91e76e2..000000000 --- a/pkg/astvisitor/simplevisitor_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package astvisitor - -import ( - "testing" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func BenchmarkSimpleVisitor(b *testing.B) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(testOperation) - - visitor := &dummyVisitor{} - - walker := NewSimpleWalker(48) - walker.SetVisitor(visitor) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - must(walker.Walk(&operation, &definition)) - } -} diff --git a/pkg/astvisitor/visitor.go b/pkg/astvisitor/visitor.go deleted file mode 100644 index 86c05d28b..000000000 --- a/pkg/astvisitor/visitor.go +++ /dev/null @@ -1,3654 +0,0 @@ -package astvisitor - -import ( - "bytes" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -var ( - ErrDocumentMustNotBeNil = fmt.Errorf("document must not be nil") - ErrDefinitionMustNotBeNil = fmt.Errorf("definition must not be nil when walking operations") -) - -// Walker orchestrates the process of walking an AST and calling all registered callbacks -// Always use NewWalker to instantiate a new Walker -type Walker struct { - // Ancestors is the slice of Nodes to the current Node in a callback - // don't keep a reference to this slice, always copy it if you want to work with it after the callback returned - Ancestors []ast.Node - // Path is the slice of PathItems leading to the current Node - // don't keep a reference to this slice, always copy it if you want to work with it after the callback returned - Path ast.Path - // EnclosingTypeDefinition is the TypeDefinition Node of the parent object of the current callback - // e.g. if the current callback is a Field the EnclosingTypeDefinition will be the TypeDefinition of the parent object of such Field - EnclosingTypeDefinition ast.Node - // SelectionsBefore is the slice of references to selections before the current selection - // This is only valid when inside a SelectionSet - SelectionsBefore []int - // SelectionsAfter is the slice of references to selections before the current selection - // This is only valid when inside a SelectionSet - SelectionsAfter []int - // Report is the object to collect errors when walking the AST - Report *operationreport.Report - CurrentRef int - CurrentKind ast.NodeKind - document *ast.Document - definition *ast.Document - visitors visitors - Depth int - typeDefinitions []ast.Node - stop bool - skip bool - revisit bool - filter VisitorFilter - deferred []func() -} - -// NewWalker returns a fully initialized Walker -func NewWalker(ancestorSize int) Walker { - return Walker{ - Ancestors: make([]ast.Node, 0, ancestorSize), - Path: make([]ast.PathItem, 0, ancestorSize), - typeDefinitions: make([]ast.Node, 0, ancestorSize), - deferred: make([]func(), 0, 8), - } -} - -type ( - // EnterOperationDefinitionVisitor is the callback when the walker enters an operation definition - EnterOperationDefinitionVisitor interface { - // EnterOperationDefinition gets called when the walker enters an operation definition - // ref is the reference to the operation definition on the AST - EnterOperationDefinition(ref int) - } - // LeaveOperationDefinitionVisitor is the callback when the walker leaves an operation definition - LeaveOperationDefinitionVisitor interface { - // LeaveOperationDefinition gets called when the walker leaves an operation definition - // ref is the reference to the operation definition on the AST - LeaveOperationDefinition(ref int) - } - // OperationDefinitionVisitor is the callback when the walker enters or leaves an operation - OperationDefinitionVisitor interface { - EnterOperationDefinitionVisitor - LeaveOperationDefinitionVisitor - } - // EnterSelectionSetVisitor is the callback when the walker enters a selection set - EnterSelectionSetVisitor interface { - // EnterSelectionSet gets called when the walker enters a selection set - // ref is the reference to the selection set on the AST - EnterSelectionSet(ref int) - } - // LeaveSelectionSetVisitor is the callback when the walker leaves a selection set visitor - LeaveSelectionSetVisitor interface { - // LeaveSelectionSet gets called when the walker leaves a selection set - // ref is the reference to the selection set on the AST - LeaveSelectionSet(ref int) - } - // SelectionSetVisitor is the callback when the walker enters or leaves a selection set - SelectionSetVisitor interface { - EnterSelectionSetVisitor - LeaveSelectionSetVisitor - } - // EnterFieldVisitor is the callback when the walker enters a field - EnterFieldVisitor interface { - // EnterField gets called when the walker enters a field - // ref is the reference to the selection set on the AST - EnterField(ref int) - } - // LeaveFieldVisitor is the callback when the walker leaves a field - LeaveFieldVisitor interface { - // LeaveField gets called when the walker leaves a field - // ref is the reference to the selection set on the AST - LeaveField(ref int) - } - // FieldVisitor is the callback when the walker enters or leaves a field - FieldVisitor interface { - EnterFieldVisitor - LeaveFieldVisitor - } - // EnterArgumentVisitor is the callback when the walker enters an argument - EnterArgumentVisitor interface { - // EnterArgument gets called when the walker enters an argument - // ref is the reference to the selection set on the AST - EnterArgument(ref int) - } - // LeaveArgumentVisitor is the callback when the walker leaves an argument - LeaveArgumentVisitor interface { - // LeaveArgument gets called when the walker leaves an argument - // ref is the reference to the selection set on the AST - LeaveArgument(ref int) - } - // ArgumentVisitor is the callback when the walker enters or leaves an argument - ArgumentVisitor interface { - EnterArgumentVisitor - LeaveArgumentVisitor - } - // EnterFragmentSpreadVisitor is the callback when the walker enters a fragment spread - EnterFragmentSpreadVisitor interface { - // EnterFragmentSpread gets called when the walker enters a fragment spread - // ref is the reference to the selection set on the AST - EnterFragmentSpread(ref int) - } - // LeaveFragmentSpreadVisitor is the callback when the walker leaves a fragment spread - LeaveFragmentSpreadVisitor interface { - // LeaveFragmentSpread gets called when the walker leaves a fragment spread - // ref is the reference to the selection set on the AST - LeaveFragmentSpread(ref int) - } - // FragmentSpreadVisitor is the callback when the walker enters or leaves a fragment spread - FragmentSpreadVisitor interface { - EnterFragmentSpreadVisitor - LeaveFragmentSpreadVisitor - } - // EnterInlineFragmentVisitor is the callback when the walker enters an inline fragment - EnterInlineFragmentVisitor interface { - // EnterInlineFragment gets called when the walker enters an inline fragment - // ref is the reference to the selection set on the AST - EnterInlineFragment(ref int) - } - // LeaveInlineFragmentVisitor is the callback when the walker leaves an inline fragment - LeaveInlineFragmentVisitor interface { - // LeaveInlineFragment gets called when the walker leaves an inline fragment - // ref is the reference to the selection set on the AST - LeaveInlineFragment(ref int) - } - // InlineFragmentVisitor is the callback when the walker enters or leaves an inline fragment - InlineFragmentVisitor interface { - EnterInlineFragmentVisitor - LeaveInlineFragmentVisitor - } - // EnterFragmentDefinitionVisitor is the callback when the walker enters a fragment definition - EnterFragmentDefinitionVisitor interface { - // EnterFragmentDefinition gets called when the walker enters a fragment definition - // ref is the reference to the selection set on the AST - EnterFragmentDefinition(ref int) - } - // LeaveFragmentDefinitionVisitor is the callback when the walker leaves a fragment definition - LeaveFragmentDefinitionVisitor interface { - // LeaveFragmentDefinition gets called when the walker leaves a fragment definition - // ref is the reference to the selection set on the AST - LeaveFragmentDefinition(ref int) - } - // FragmentDefinitionVisitor is the callback when the walker enters or leaves a fragment definition - FragmentDefinitionVisitor interface { - EnterFragmentDefinitionVisitor - LeaveFragmentDefinitionVisitor - } - // EnterFragmentDefinitionVisitor is the callback when the walker enters a variable definition - EnterVariableDefinitionVisitor interface { - // EnterVariableDefinition gets called when the walker enters a variable definition - // ref is the reference to the selection set on the AST - EnterVariableDefinition(ref int) - } - // LeaveVariableDefinitionVisitor is the callback when the walker leaves a variable definition - LeaveVariableDefinitionVisitor interface { - // LeaveVariableDefinition gets called when the walker leaves a variable definition - // ref is the reference to the selection set on the AST - LeaveVariableDefinition(ref int) - } - // VariableDefinitionVisitor is the callback when the walker enters or leaves a variable definition - VariableDefinitionVisitor interface { - EnterVariableDefinitionVisitor - LeaveVariableDefinitionVisitor - } - // EnterDirectiveVisitor is the callback when the walker enters a directive - EnterDirectiveVisitor interface { - // EnterDirective gets called when the walker enters a directive - // ref is the reference to the selection set on the AST - EnterDirective(ref int) - } - // LeaveDirectiveVisitor is the callback when the walker leaves a directive - LeaveDirectiveVisitor interface { - // LeaveDirective gets called when the walker leaves a directive - // ref is the reference to the selection set on the AST - LeaveDirective(ref int) - } - // DirectiveVisitor is the callback when the walker enters or leaves a directive - DirectiveVisitor interface { - EnterDirectiveVisitor - LeaveDirectiveVisitor - } - // EnterObjectTypeDefinitionVisitor is the callback when the walker enters an object type definition - EnterObjectTypeDefinitionVisitor interface { - // EnterObjectTypeDefinition gets called when the walker enters an object type definition - // ref is the reference to the selection set on the AST - EnterObjectTypeDefinition(ref int) - } - // LeaveObjectTypeDefinitionVisitor is the callback when the walker leaves an object type definition - LeaveObjectTypeDefinitionVisitor interface { - // LeaveObjectTypeDefinition gets called when the walker leaves an object type definition - // ref is the reference to the selection set on the AST - LeaveObjectTypeDefinition(ref int) - } - // ObjectTypeDefinitionVisitor is the callback when the walker enters or leaves an object type definition - ObjectTypeDefinitionVisitor interface { - EnterObjectTypeDefinitionVisitor - LeaveObjectTypeDefinitionVisitor - } - // EnterObjectTypeExtensionVisitor is the callback when the walker enters an object type extension - EnterObjectTypeExtensionVisitor interface { - // EnterObjectTypeExtension gets called when the walker enters an object type extension - // ref is the reference to the selection set on the AST - EnterObjectTypeExtension(ref int) - } - // LeaveObjectTypeExtensionVisitor is the callback when the walker leaves an object type extension - LeaveObjectTypeExtensionVisitor interface { - // LeaveObjectTypeExtension gets called when the walker leaves an object type extension - // ref is the reference to the selection set on the AST - LeaveObjectTypeExtension(ref int) - } - // ObjectTypeExtensionVisitor is the callback when the walker enters or leaves an object type extension - ObjectTypeExtensionVisitor interface { - EnterObjectTypeExtensionVisitor - LeaveObjectTypeExtensionVisitor - } - // EnterFieldDefinitionVisitor is the callback when the walker enters a field definition - EnterFieldDefinitionVisitor interface { - // EnterFieldDefinition gets called when the walker enters a field definition - // ref is the reference to the selection set on the AST - EnterFieldDefinition(ref int) - } - // LeaveFieldDefinitionVisitor is the callback when the walker leaves a field definition - LeaveFieldDefinitionVisitor interface { - // LeaveFieldDefinition gets called when the walker leaves a field definition - // ref is the reference to the selection set on the AST - LeaveFieldDefinition(ref int) - } - // FieldDefinitionVisitor is the callback when the walker enters or leaves a field definition - FieldDefinitionVisitor interface { - EnterFieldDefinitionVisitor - LeaveFieldDefinitionVisitor - } - // EnterInputValueDefinitionVisitor is the callback when the walker enters an input value definition - EnterInputValueDefinitionVisitor interface { - // EnterInputValueDefinition gets called when the walker enters an input value definition - // ref is the reference to the selection set on the AST - EnterInputValueDefinition(ref int) - } - // LeaveInputValueDefinitionVisitor is the callback when the walker leaves an input value definition - LeaveInputValueDefinitionVisitor interface { - // LeaveInputValueDefinition gets called when the walker leaves an input value definition - // ref is the reference to the selection set on the AST - LeaveInputValueDefinition(ref int) - } - // InputValueDefinitionVisitor is the callback when the walker enters or leaves an input value definition - InputValueDefinitionVisitor interface { - EnterInputValueDefinitionVisitor - LeaveInputValueDefinitionVisitor - } - // EnterInterfaceTypeDefinitionVisitor is the callback when the walker enters an interface type definition - EnterInterfaceTypeDefinitionVisitor interface { - // EnterInterfaceTypeDefinition gets called when the walker enters an interface type definition - // ref is the reference to the selection set on the AST - EnterInterfaceTypeDefinition(ref int) - } - // LeaveInterfaceTypeDefinitionVisitor is the callback when the walker leaves an interface type definition - LeaveInterfaceTypeDefinitionVisitor interface { - // LeaveInterfaceTypeDefinition gets called when the walker leaves an interface type definition - // ref is the reference to the selection set on the AST - LeaveInterfaceTypeDefinition(ref int) - } - // InterfaceTypeDefinitionVisitor is the callback when the walker enters or leaves an interface type definition - InterfaceTypeDefinitionVisitor interface { - EnterInterfaceTypeDefinitionVisitor - LeaveInterfaceTypeDefinitionVisitor - } - // EnterInterfaceTypeExtensionVisitor is the callback when the walker enters an interface type extension - EnterInterfaceTypeExtensionVisitor interface { - // EnterInterfaceTypeExtension gets called when the walker enters an interface type extension - // ref is the reference to the selection set on the AST - EnterInterfaceTypeExtension(ref int) - } - // LeaveInterfaceTypeExtensionVisitor is the callback when the walker leaves an interface type extension - LeaveInterfaceTypeExtensionVisitor interface { - // LeaveInterfaceTypeExtension gets called when the walker leaves an interface type extension - // ref is the reference to the selection set on the AST - LeaveInterfaceTypeExtension(ref int) - } - // InterfaceTypeExtensionVisitor is the callback when the walker enters or leaves an interface type extension - InterfaceTypeExtensionVisitor interface { - EnterInterfaceTypeExtensionVisitor - LeaveInterfaceTypeExtensionVisitor - } - // EnterScalarTypeDefinitionVisitor is the callback when the walker enters a scalar type definition - EnterScalarTypeDefinitionVisitor interface { - // EnterScalarTypeDefinition gets called when the walker enters a scalar type definition - // ref is the reference to the selection set on the AST - EnterScalarTypeDefinition(ref int) - } - // LeaveScalarTypeDefinitionVisitor is the callback when the walker leaves a scalar type definition - LeaveScalarTypeDefinitionVisitor interface { - // LeaveScalarTypeDefinition gets called when the walker leaves a scalar type definition - // ref is the reference to the selection set on the AST - LeaveScalarTypeDefinition(ref int) - } - // ScalarTypeDefinitionVisitor is the callback when the walker enters or leaves a scalar type definition - ScalarTypeDefinitionVisitor interface { - EnterScalarTypeDefinitionVisitor - LeaveScalarTypeDefinitionVisitor - } - // EnterScalarTypeExtensionVisitor is the callback when the walker enters a scalar type extension - EnterScalarTypeExtensionVisitor interface { - // EnterScalarTypeExtension gets called when the walker enters a scalar type extension - // ref is the reference to the selection set on the AST - EnterScalarTypeExtension(ref int) - } - // LeaveScalarTypeExtensionVisitor is the callback when the walker leaves a scalar type extension - LeaveScalarTypeExtensionVisitor interface { - // LeaveScalarTypeExtension gets called when the walker leaves a scalar type extension - // ref is the reference to the selection set on the AST - LeaveScalarTypeExtension(ref int) - } - // ScalarTypeExtensionVisitor is the callback when the walker enters or leaves a scalar type extension - ScalarTypeExtensionVisitor interface { - EnterScalarTypeExtensionVisitor - LeaveScalarTypeExtensionVisitor - } - // EnterUnionTypeDefinitionVisitor is the callback when the walker enters a union type definition - EnterUnionTypeDefinitionVisitor interface { - // EnterUnionTypeDefinition gets called when the walker enters a union type definition - // ref is the reference to the selection set on the AST - EnterUnionTypeDefinition(ref int) - } - // LeaveUnionTypeDefinitionVisitor is the callback when the walker leaves a union type definition - LeaveUnionTypeDefinitionVisitor interface { - // LeaveUnionTypeDefinition gets called when the walker leaves a union type definition - // ref is the reference to the selection set on the AST - LeaveUnionTypeDefinition(ref int) - } - // UnionTypeDefinitionVisitor is the callback when the walker enters or leaves a union type definition - UnionTypeDefinitionVisitor interface { - EnterUnionTypeDefinitionVisitor - LeaveUnionTypeDefinitionVisitor - } - // EnterUnionTypeExtensionVisitor is the callback when the walker enters a union type extension - EnterUnionTypeExtensionVisitor interface { - // EnterUnionTypeExtension gets called when the walker enters a union type extension - // ref is the reference to the selection set on the AST - EnterUnionTypeExtension(ref int) - } - // LeaveUnionTypeExtensionVisitor is the callback when the walker leaves a union type extension - LeaveUnionTypeExtensionVisitor interface { - // LeaveUnionTypeExtension gets called when the walker leaves a union type extension - // ref is the reference to the selection set on the AST - LeaveUnionTypeExtension(ref int) - } - // UnionTypeExtensionVisitor is the callback when the walker enters or leaves a union type extension - UnionTypeExtensionVisitor interface { - EnterUnionTypeExtensionVisitor - LeaveUnionTypeExtensionVisitor - } - // EnterUnionMemberTypeVisitor is the callback when the walker enters a union member type - EnterUnionMemberTypeVisitor interface { - // EnterUnionMemberType gets called when the walker enters a union member type - // ref is the reference to the selection set on the AST - EnterUnionMemberType(ref int) - } - // LeaveUnionMemberTypeVisitor is the callback when the walker leaves a union member type - LeaveUnionMemberTypeVisitor interface { - // LeaveUnionMemberType gets called when the walker leaves a union member type - // ref is the reference to the selection set on the AST - LeaveUnionMemberType(ref int) - } - // UnionMemberTypeVisitor is the callback when the walker enters or leaves a union member type - UnionMemberTypeVisitor interface { - EnterUnionMemberTypeVisitor - LeaveUnionMemberTypeVisitor - } - // EnterEnumTypeDefinitionVisitor is the callback when the walker enters an enum type definition - EnterEnumTypeDefinitionVisitor interface { - // EnterEnumTypeDefinition gets called when the walker enters an enum type definition - // ref is the reference to the selection set on the AST - EnterEnumTypeDefinition(ref int) - } - // LeaveEnumTypeDefinitionVisitor is the callback when the walker leaves an enum type definition - LeaveEnumTypeDefinitionVisitor interface { - // LeaveEnumTypeDefinition gets called when the walker leaves an enum type definition - // ref is the reference to the selection set on the AST - LeaveEnumTypeDefinition(ref int) - } - // EnumTypeDefinitionVisitor is the callback when the walker enters or leaves an enum type definition - EnumTypeDefinitionVisitor interface { - EnterEnumTypeDefinitionVisitor - LeaveEnumTypeDefinitionVisitor - } - // EnterEnumTypeExtensionVisitor is the callback when the walker enters an enum type extension - EnterEnumTypeExtensionVisitor interface { - // EnterEnumTypeExtension gets called when the walker enters an enum type extension - // ref is the reference to the selection set on the AST - EnterEnumTypeExtension(ref int) - } - // LeaveEnumTypeExtensionVisitor is the callback when the walker leaves an enum type extension - LeaveEnumTypeExtensionVisitor interface { - // LeaveEnumTypeExtension gets called when the walker leaves an enum type extension - // ref is the reference to the selection set on the AST - LeaveEnumTypeExtension(ref int) - } - // EnumTypeExtensionVisitor is the callback when the walker enters or leaves an enum type extension - EnumTypeExtensionVisitor interface { - EnterEnumTypeExtensionVisitor - LeaveEnumTypeExtensionVisitor - } - // EnterEnumValueDefinitionVisitor is the callback when the walker enters an enum value definition - EnterEnumValueDefinitionVisitor interface { - // EnterEnumValueDefinition gets called when the walker enters an enum value definition - // ref is the reference to the selection set on the AST - EnterEnumValueDefinition(ref int) - } - // LeaveEnumValueDefinitionVisitor is the callback when the walker leaves an enum value definition - LeaveEnumValueDefinitionVisitor interface { - // LeaveEnumValueDefinition gets called when the walker leaves an enum value definition - // ref is the reference to the selection set on the AST - LeaveEnumValueDefinition(ref int) - } - // EnumValueDefinitionVisitor is the callback when the walker enters or leaves an enum value definition - EnumValueDefinitionVisitor interface { - EnterEnumValueDefinitionVisitor - LeaveEnumValueDefinitionVisitor - } - // EnterInputObjectTypeDefinitionVisitor is the callback when the walker enters an input object type definition - EnterInputObjectTypeDefinitionVisitor interface { - // EnterInputObjectTypeDefinition gets called when the walker enters an input object type definition - // ref is the reference to the selection set on the AST - EnterInputObjectTypeDefinition(ref int) - } - // LeaveInputObjectTypeDefinitionVisitor is the callback when the walker leaves an input object type definition - LeaveInputObjectTypeDefinitionVisitor interface { - // LeaveInputObjectTypeDefinition gets called when the walker leaves an input object type definition - // ref is the reference to the selection set on the AST - LeaveInputObjectTypeDefinition(ref int) - } - // InputObjectTypeDefinitionVisitor is the callback when the walker enters or leaves an input object type definition - InputObjectTypeDefinitionVisitor interface { - EnterInputObjectTypeDefinitionVisitor - LeaveInputObjectTypeDefinitionVisitor - } - // EnterInputObjectTypeExtensionVisitor is the callback when the walker enters an input object type extension - EnterInputObjectTypeExtensionVisitor interface { - // EnterInputObjectTypeExtension gets called when the walker enters an input object type extension - // ref is the reference to the selection set on the AST - EnterInputObjectTypeExtension(ref int) - } - // LeaveInputObjectTypeExtensionVisitor is the callback when the walker leaves an input object type extension - LeaveInputObjectTypeExtensionVisitor interface { - // LeaveInputObjectTypeExtension gets called when the walker leaves an input object type extension - // ref is the reference to the selection set on the AST - LeaveInputObjectTypeExtension(ref int) - } - // InputObjectTypeExtensionVisitor is the callback when the walker enters or leaves an input object type extension - InputObjectTypeExtensionVisitor interface { - EnterInputObjectTypeExtensionVisitor - LeaveInputObjectTypeExtensionVisitor - } - // EnterDirectiveDefinitionVisitor is the callback when the walker enters a directive definition - EnterDirectiveDefinitionVisitor interface { - // EnterDirectiveDefinition gets called when the walker enters a directive definition - // ref is the reference to the selection set on the AST - EnterDirectiveDefinition(ref int) - } - // LeaveDirectiveDefinitionVisitor is the callback when the walker leaves a directive definition - LeaveDirectiveDefinitionVisitor interface { - // LeaveDirectiveDefinition gets called when the walker leaves a directive definition - // ref is the reference to the selection set on the AST - LeaveDirectiveDefinition(ref int) - } - // DirectiveDefinitionVisitor is the callback when the walker enters or leaves a directive definition - DirectiveDefinitionVisitor interface { - EnterDirectiveDefinitionVisitor - LeaveDirectiveDefinitionVisitor - } - // EnterDirectiveLocationVisitor is the callback when the walker enters a directive location - EnterDirectiveLocationVisitor interface { - // EnterDirectiveLocation gets called when the walker enters a directive location - // ref is the reference to the selection set on the AST - EnterDirectiveLocation(location ast.DirectiveLocation) - } - // LeaveDirectiveLocationVisitor is the callback when the walker leaves a directive location - LeaveDirectiveLocationVisitor interface { - // LeaveDirectiveLocation gets called when the walker leaves a directive location - // ref is the reference to the selection set on the AST - LeaveDirectiveLocation(location ast.DirectiveLocation) - } - // DirectiveLocationVisitor is the callback when the walker enters or leaves a directive location - DirectiveLocationVisitor interface { - EnterDirectiveLocationVisitor - LeaveDirectiveLocationVisitor - } - // EnterSchemaDefinitionVisitor is the callback when the walker enters a schema definition - EnterSchemaDefinitionVisitor interface { - // EnterSchemaDefinition gets called when the walker enters a schema definition - // ref is the reference to the selection set on the AST - EnterSchemaDefinition(ref int) - } - // LeaveSchemaDefinitionVisitor is the callback when the walker leaves a schema definition - LeaveSchemaDefinitionVisitor interface { - // LeaveSchemaDefinition gets called when the walker leaves a schema definition - // ref is the reference to the selection set on the AST - LeaveSchemaDefinition(ref int) - } - // SchemaDefinitionVisitor is the callback when the walker enters or leaves a schema definition - SchemaDefinitionVisitor interface { - EnterSchemaDefinitionVisitor - LeaveSchemaDefinitionVisitor - } - // EnterSchemaExtensionVisitor is the callback when the walker enters a schema extension - EnterSchemaExtensionVisitor interface { - // EnterSchemaExtension gets called when the walker enters a schema extension - // ref is the reference to the selection set on the AST - EnterSchemaExtension(ref int) - } - // LeaveSchemaExtensionVisitor is the callback when the walker leaves a schema extension - LeaveSchemaExtensionVisitor interface { - // LeaveSchemaExtension gets called when the walker leaves a schema extension - // ref is the reference to the selection set on the AST - LeaveSchemaExtension(ref int) - } - // SchemaExtensionVisitor is the callback when the walker enters or leaves a schema extension - SchemaExtensionVisitor interface { - EnterSchemaExtensionVisitor - LeaveSchemaExtensionVisitor - } - // EnterRootOperationTypeDefinitionVisitor is the callback when the walker enters a root operation type definition - EnterRootOperationTypeDefinitionVisitor interface { - // EnterRootOperationTypeDefinition gets called when the walker enters a root operation type definition - // ref is the reference to the selection set on the AST - EnterRootOperationTypeDefinition(ref int) - } - // LeaveRootOperationTypeDefinitionVisitor is the callback when the walker leaves a root operation type definition - LeaveRootOperationTypeDefinitionVisitor interface { - // LeaveRootOperationTypeDefinition gets called when the walker leaves a root operation type definition - // ref is the reference to the selection set on the AST - LeaveRootOperationTypeDefinition(ref int) - } - // RootOperationTypeDefinitionVisitor is the callback when the walker enters or leaves a root operation type definition - RootOperationTypeDefinitionVisitor interface { - EnterRootOperationTypeDefinitionVisitor - LeaveRootOperationTypeDefinitionVisitor - } - // TypeSystemVisitor is the callback when the walker enters or leaves any of the type definitions - TypeSystemVisitor interface { - ObjectTypeDefinitionVisitor - ObjectTypeExtensionVisitor - FieldDefinitionVisitor - InputValueDefinitionVisitor - InterfaceTypeDefinitionVisitor - InterfaceTypeExtensionVisitor - ScalarTypeDefinitionVisitor - ScalarTypeExtensionVisitor - UnionTypeDefinitionVisitor - UnionTypeExtensionVisitor - UnionMemberTypeVisitor - EnumTypeDefinitionVisitor - EnumTypeExtensionVisitor - EnumValueDefinitionVisitor - InputObjectTypeDefinitionVisitor - InputObjectTypeExtensionVisitor - DirectiveDefinitionVisitor - DirectiveLocationVisitor - SchemaDefinitionVisitor - SchemaExtensionVisitor - RootOperationTypeDefinitionVisitor - } - // ExecutableVisitor is the callback when the walker enters or leaves any of the executable definitions - ExecutableVisitor interface { - OperationDefinitionVisitor - SelectionSetVisitor - FieldVisitor - ArgumentVisitor - FragmentSpreadVisitor - InlineFragmentVisitor - FragmentDefinitionVisitor - VariableDefinitionVisitor - DirectiveVisitor - } - // EnterDocumentVisitor is the callback when the walker enters a document - EnterDocumentVisitor interface { - // EnterDocument gets called when the walker enters a document - EnterDocument(operation, definition *ast.Document) - } - LeaveDocumentVisitor interface { - // LeaveDocument gets called when the walker leaves a document - LeaveDocument(operation, definition *ast.Document) - } - // DocumentVisitor is the callback when the walker enters or leaves a document - DocumentVisitor interface { - EnterDocumentVisitor - LeaveDocumentVisitor - } - // AllNodesVisitor is the callback when the walker enters or leaves any Node - AllNodesVisitor interface { - DocumentVisitor - TypeSystemVisitor - ExecutableVisitor - } - // VisitorFilter can be defined to prevent specific visitors from getting invoked - VisitorFilter interface { - AllowVisitor(kind VisitorKind, ref int, visitor interface{}) bool - } -) - -type VisitorKind int - -const ( - EnterOperation VisitorKind = iota + 1 - LeaveOperation - EnterSelectionSet - LeaveSelectionSet - EnterField - LeaveField - EnterArgument - LeaveArgument - EnterFragmentSpread - LeaveFragmentSpread - EnterInlineFragment - LeaveInlineFragment - EnterFragmentDefinition - LeaveFragmentDefinition - EnterDocument - LeaveDocument - EnterVariableDefinition - LeaveVariableDefinition - EnterDirective - LeaveDirective - EnterObjectTypeDefinition - LeaveObjectTypeDefinition - EnterFieldDefinition - LeaveFieldDefinition - EnterInputValueDefinition - LeaveInputValueDefinition - EnterInterfaceTypeDefinition - LeaveInterfaceTypeDefinition - EnterInterfaceTypeExtension - LeaveInterfaceTypeExtension - EnterObjectTypeExtension - LeaveObjectTypeExtension - EnterScalarTypeDefinition - LeaveScalarTypeDefinition - EnterScalarTypeExtension - LeaveScalarTypeExtension - EnterUnionTypeDefinition - LeaveUnionTypeDefinition - EnterUnionTypeExtension - LeaveUnionTypeExtension - EnterUnionMemberType - LeaveUnionMemberType - EnterEnumTypeDefinition - LeaveEnumTypeDefinition - EnterEnumTypeExtension - LeaveEnumTypeExtension - EnterEnumValueDefinition - LeaveEnumValueDefinition - EnterInputObjectTypeDefinition - LeaveInputObjectTypeDefinition - EnterInputObjectTypeExtension - LeaveInputObjectTypeExtension - EnterDirectiveDefinition - LeaveDirectiveDefinition - EnterDirectiveLocation - LeaveDirectiveLocation - EnterSchemaDefinition - LeaveSchemaDefinition - EnterSchemaExtension - LeaveSchemaExtension - EnterRootOperationTypeDefinition - LeaveRootOperationTypeDefinition -) - -type visitors struct { - enterOperation []EnterOperationDefinitionVisitor - leaveOperation []LeaveOperationDefinitionVisitor - enterSelectionSet []EnterSelectionSetVisitor - leaveSelectionSet []LeaveSelectionSetVisitor - enterField []EnterFieldVisitor - leaveField []LeaveFieldVisitor - enterArgument []EnterArgumentVisitor - leaveArgument []LeaveArgumentVisitor - enterFragmentSpread []EnterFragmentSpreadVisitor - leaveFragmentSpread []LeaveFragmentSpreadVisitor - enterInlineFragment []EnterInlineFragmentVisitor - leaveInlineFragment []LeaveInlineFragmentVisitor - enterFragmentDefinition []EnterFragmentDefinitionVisitor - leaveFragmentDefinition []LeaveFragmentDefinitionVisitor - enterDocument []EnterDocumentVisitor - leaveDocument []LeaveDocumentVisitor - enterVariableDefinition []EnterVariableDefinitionVisitor - leaveVariableDefinition []LeaveVariableDefinitionVisitor - enterDirective []EnterDirectiveVisitor - leaveDirective []LeaveDirectiveVisitor - enterObjectTypeDefinition []EnterObjectTypeDefinitionVisitor - leaveObjectTypeDefinition []LeaveObjectTypeDefinitionVisitor - enterFieldDefinition []EnterFieldDefinitionVisitor - leaveFieldDefinition []LeaveFieldDefinitionVisitor - enterInputValueDefinition []EnterInputValueDefinitionVisitor - leaveInputValueDefinition []LeaveInputValueDefinitionVisitor - enterInterfaceTypeDefinition []EnterInterfaceTypeDefinitionVisitor - leaveInterfaceTypeDefinition []LeaveInterfaceTypeDefinitionVisitor - enterInterfaceTypeExtension []EnterInterfaceTypeExtensionVisitor - leaveInterfaceTypeExtension []LeaveInterfaceTypeExtensionVisitor - enterObjectTypeExtension []EnterObjectTypeExtensionVisitor - leaveObjectTypeExtension []LeaveObjectTypeExtensionVisitor - enterScalarTypeDefinition []EnterScalarTypeDefinitionVisitor - leaveScalarTypeDefinition []LeaveScalarTypeDefinitionVisitor - enterScalarTypeExtension []EnterScalarTypeExtensionVisitor - leaveScalarTypeExtension []LeaveScalarTypeExtensionVisitor - enterUnionTypeDefinition []EnterUnionTypeDefinitionVisitor - leaveUnionTypeDefinition []LeaveUnionTypeDefinitionVisitor - enterUnionTypeExtension []EnterUnionTypeExtensionVisitor - leaveUnionTypeExtension []LeaveUnionTypeExtensionVisitor - enterUnionMemberType []EnterUnionMemberTypeVisitor - leaveUnionMemberType []LeaveUnionMemberTypeVisitor - enterEnumTypeDefinition []EnterEnumTypeDefinitionVisitor - leaveEnumTypeDefinition []LeaveEnumTypeDefinitionVisitor - enterEnumTypeExtension []EnterEnumTypeExtensionVisitor - leaveEnumTypeExtension []LeaveEnumTypeExtensionVisitor - enterEnumValueDefinition []EnterEnumValueDefinitionVisitor - leaveEnumValueDefinition []LeaveEnumValueDefinitionVisitor - enterInputObjectTypeDefinition []EnterInputObjectTypeDefinitionVisitor - leaveInputObjectTypeDefinition []LeaveInputObjectTypeDefinitionVisitor - enterInputObjectTypeExtension []EnterInputObjectTypeExtensionVisitor - leaveInputObjectTypeExtension []LeaveInputObjectTypeExtensionVisitor - enterDirectiveDefinition []EnterDirectiveDefinitionVisitor - leaveDirectiveDefinition []LeaveDirectiveDefinitionVisitor - enterDirectiveLocation []EnterDirectiveLocationVisitor - leaveDirectiveLocation []LeaveDirectiveLocationVisitor - enterSchemaDefinition []EnterSchemaDefinitionVisitor - leaveSchemaDefinition []LeaveSchemaDefinitionVisitor - enterSchemaExtension []EnterSchemaExtensionVisitor - leaveSchemaExtension []LeaveSchemaExtensionVisitor - enterRootOperationTypeDefinition []EnterRootOperationTypeDefinitionVisitor - leaveRootOperationTypeDefinition []LeaveRootOperationTypeDefinitionVisitor -} - -// ResetVisitors empties all registered visitors / unregisters all callbacks -func (w *Walker) ResetVisitors() { - w.visitors.enterOperation = w.visitors.enterOperation[:0] - w.visitors.leaveOperation = w.visitors.leaveOperation[:0] - w.visitors.enterSelectionSet = w.visitors.enterSelectionSet[:0] - w.visitors.leaveSelectionSet = w.visitors.leaveSelectionSet[:0] - w.visitors.enterField = w.visitors.enterField[:0] - w.visitors.leaveField = w.visitors.leaveField[:0] - w.visitors.enterArgument = w.visitors.enterArgument[:0] - w.visitors.leaveArgument = w.visitors.leaveArgument[:0] - w.visitors.enterFragmentSpread = w.visitors.enterFragmentSpread[:0] - w.visitors.leaveFragmentSpread = w.visitors.leaveFragmentSpread[:0] - w.visitors.enterInlineFragment = w.visitors.enterInlineFragment[:0] - w.visitors.leaveInlineFragment = w.visitors.leaveInlineFragment[:0] - w.visitors.enterFragmentDefinition = w.visitors.enterFragmentDefinition[:0] - w.visitors.leaveFragmentDefinition = w.visitors.leaveFragmentDefinition[:0] - w.visitors.enterDocument = w.visitors.enterDocument[:0] - w.visitors.leaveDocument = w.visitors.leaveDocument[:0] - w.visitors.enterVariableDefinition = w.visitors.enterVariableDefinition[:0] - w.visitors.leaveVariableDefinition = w.visitors.leaveVariableDefinition[:0] - w.visitors.enterDirective = w.visitors.enterDirective[:0] - w.visitors.leaveDirective = w.visitors.leaveDirective[:0] - w.visitors.enterObjectTypeDefinition = w.visitors.enterObjectTypeDefinition[:0] - w.visitors.leaveObjectTypeDefinition = w.visitors.leaveObjectTypeDefinition[:0] - w.visitors.enterFieldDefinition = w.visitors.enterFieldDefinition[:0] - w.visitors.leaveFieldDefinition = w.visitors.leaveFieldDefinition[:0] - w.visitors.enterInputValueDefinition = w.visitors.enterInputValueDefinition[:0] - w.visitors.leaveInputValueDefinition = w.visitors.leaveInputValueDefinition[:0] - w.visitors.enterInterfaceTypeDefinition = w.visitors.enterInterfaceTypeDefinition[:0] - w.visitors.leaveInterfaceTypeDefinition = w.visitors.leaveInterfaceTypeDefinition[:0] - w.visitors.enterInterfaceTypeExtension = w.visitors.enterInterfaceTypeExtension[:0] - w.visitors.leaveInterfaceTypeExtension = w.visitors.leaveInterfaceTypeExtension[:0] - w.visitors.enterObjectTypeExtension = w.visitors.enterObjectTypeExtension[:0] - w.visitors.leaveObjectTypeExtension = w.visitors.leaveObjectTypeExtension[:0] - w.visitors.enterScalarTypeDefinition = w.visitors.enterScalarTypeDefinition[:0] - w.visitors.leaveScalarTypeDefinition = w.visitors.leaveScalarTypeDefinition[:0] - w.visitors.enterScalarTypeExtension = w.visitors.enterScalarTypeExtension[:0] - w.visitors.leaveScalarTypeExtension = w.visitors.leaveScalarTypeExtension[:0] - w.visitors.enterUnionTypeDefinition = w.visitors.enterUnionTypeDefinition[:0] - w.visitors.leaveUnionTypeDefinition = w.visitors.leaveUnionTypeDefinition[:0] - w.visitors.enterUnionTypeExtension = w.visitors.enterUnionTypeExtension[:0] - w.visitors.leaveUnionTypeExtension = w.visitors.leaveUnionTypeExtension[:0] - w.visitors.enterUnionMemberType = w.visitors.enterUnionMemberType[:0] - w.visitors.leaveUnionMemberType = w.visitors.leaveUnionMemberType[:0] - w.visitors.enterEnumTypeDefinition = w.visitors.enterEnumTypeDefinition[:0] - w.visitors.leaveEnumTypeDefinition = w.visitors.leaveEnumTypeDefinition[:0] - w.visitors.enterEnumTypeExtension = w.visitors.enterEnumTypeExtension[:0] - w.visitors.leaveEnumTypeExtension = w.visitors.leaveEnumTypeExtension[:0] - w.visitors.enterEnumValueDefinition = w.visitors.enterEnumValueDefinition[:0] - w.visitors.leaveEnumValueDefinition = w.visitors.leaveEnumValueDefinition[:0] - w.visitors.enterInputObjectTypeDefinition = w.visitors.enterInputObjectTypeDefinition[:0] - w.visitors.leaveInputObjectTypeDefinition = w.visitors.leaveInputObjectTypeDefinition[:0] - w.visitors.enterInputObjectTypeExtension = w.visitors.enterInputObjectTypeExtension[:0] - w.visitors.leaveInputObjectTypeExtension = w.visitors.leaveInputObjectTypeExtension[:0] - w.visitors.enterDirectiveDefinition = w.visitors.enterDirectiveDefinition[:0] - w.visitors.leaveDirectiveDefinition = w.visitors.leaveDirectiveDefinition[:0] - w.visitors.enterDirectiveLocation = w.visitors.enterDirectiveLocation[:0] - w.visitors.leaveDirectiveLocation = w.visitors.leaveDirectiveLocation[:0] - w.visitors.enterSchemaDefinition = w.visitors.enterSchemaDefinition[:0] - w.visitors.leaveSchemaDefinition = w.visitors.leaveSchemaDefinition[:0] - w.visitors.enterSchemaExtension = w.visitors.enterSchemaExtension[:0] - w.visitors.leaveSchemaExtension = w.visitors.leaveSchemaExtension[:0] - w.visitors.enterRootOperationTypeDefinition = w.visitors.enterRootOperationTypeDefinition[:0] - w.visitors.leaveRootOperationTypeDefinition = w.visitors.leaveRootOperationTypeDefinition[:0] - w.deferred = w.deferred[:0] -} - -func (w *Walker) setCurrent(kind ast.NodeKind, ref int) { - w.CurrentKind = kind - w.CurrentRef = ref -} - -func (w *Walker) RegisterExecutableVisitor(visitor ExecutableVisitor) { - w.RegisterOperationDefinitionVisitor(visitor) - w.RegisterSelectionSetVisitor(visitor) - w.RegisterFieldVisitor(visitor) - w.RegisterArgumentVisitor(visitor) - w.RegisterFragmentSpreadVisitor(visitor) - w.RegisterInlineFragmentVisitor(visitor) - w.RegisterFragmentDefinitionVisitor(visitor) - w.RegisterVariableDefinitionVisitor(visitor) - w.RegisterDirectiveVisitor(visitor) -} - -func (w *Walker) RegisterTypeSystemVisitor(visitor TypeSystemVisitor) { - w.RegisterObjectTypeDefinitionVisitor(visitor) - w.RegisterObjectTypeExtensionVisitor(visitor) - w.RegisterFieldDefinitionVisitor(visitor) - w.RegisterInputValueDefinitionVisitor(visitor) - w.RegisterInterfaceTypeDefinitionVisitor(visitor) - w.RegisterInterfaceTypeExtensionVisitor(visitor) - w.RegisterScalarTypeDefinitionVisitor(visitor) - w.RegisterScalarTypeExtensionVisitor(visitor) - w.RegisterUnionTypeDefinitionVisitor(visitor) - w.RegisterUnionTypeExtensionVisitor(visitor) - w.RegisterUnionMemberTypeVisitor(visitor) - w.RegisterEnumTypeDefinitionVisitor(visitor) - w.RegisterEnumTypeExtensionVisitor(visitor) - w.RegisterEnumValueDefinitionVisitor(visitor) - w.RegisterInputObjectTypeDefinitionVisitor(visitor) - w.RegisterInputObjectTypeExtensionVisitor(visitor) - w.RegisterDirectiveDefinitionVisitor(visitor) - w.RegisterDirectiveLocationVisitor(visitor) - w.RegisterSchemaDefinitionVisitor(visitor) - w.RegisterSchemaExtensionVisitor(visitor) - w.RegisterRootOperationTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterRootOperationTypeDefinitionVisitor(visitor EnterRootOperationTypeDefinitionVisitor) { - w.visitors.enterRootOperationTypeDefinition = append(w.visitors.enterRootOperationTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveRootOperationTypeDefinitionVisitor(visitor LeaveRootOperationTypeDefinitionVisitor) { - w.visitors.leaveRootOperationTypeDefinition = append(w.visitors.leaveRootOperationTypeDefinition, visitor) -} - -func (w *Walker) RegisterRootOperationTypeDefinitionVisitor(visitor RootOperationTypeDefinitionVisitor) { - w.RegisterEnterRootOperationTypeDefinitionVisitor(visitor) - w.RegisterLeaveRootOperationTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterSchemaDefinitionVisitor(visitor EnterSchemaDefinitionVisitor) { - w.visitors.enterSchemaDefinition = append(w.visitors.enterSchemaDefinition, visitor) -} - -func (w *Walker) RegisterLeaveSchemaDefinitionVisitor(visitor LeaveSchemaDefinitionVisitor) { - w.visitors.leaveSchemaDefinition = append(w.visitors.leaveSchemaDefinition, visitor) -} - -func (w *Walker) RegisterSchemaDefinitionVisitor(visitor SchemaDefinitionVisitor) { - w.RegisterEnterSchemaDefinitionVisitor(visitor) - w.RegisterLeaveSchemaDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterSchemaExtensionVisitor(visitor EnterSchemaExtensionVisitor) { - w.visitors.enterSchemaExtension = append(w.visitors.enterSchemaExtension, visitor) -} - -func (w *Walker) RegisterLeaveSchemaExtensionVisitor(visitor LeaveSchemaExtensionVisitor) { - w.visitors.leaveSchemaExtension = append(w.visitors.leaveSchemaExtension, visitor) -} - -func (w *Walker) RegisterSchemaExtensionVisitor(visitor SchemaExtensionVisitor) { - w.RegisterEnterSchemaExtensionVisitor(visitor) - w.RegisterLeaveSchemaExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterDirectiveLocationVisitor(visitor EnterDirectiveLocationVisitor) { - w.visitors.enterDirectiveLocation = append(w.visitors.enterDirectiveLocation, visitor) -} - -func (w *Walker) RegisterLeaveDirectiveLocationVisitor(visitor LeaveDirectiveLocationVisitor) { - w.visitors.leaveDirectiveLocation = append(w.visitors.leaveDirectiveLocation, visitor) -} - -func (w *Walker) RegisterDirectiveLocationVisitor(visitor DirectiveLocationVisitor) { - w.RegisterEnterDirectiveLocationVisitor(visitor) - w.RegisterLeaveDirectiveLocationVisitor(visitor) -} - -func (w *Walker) RegisterEnterDirectiveDefinitionVisitor(visitor EnterDirectiveDefinitionVisitor) { - w.visitors.enterDirectiveDefinition = append(w.visitors.enterDirectiveDefinition, visitor) -} - -func (w *Walker) RegisterLeaveDirectiveDefinitionVisitor(visitor LeaveDirectiveDefinitionVisitor) { - w.visitors.leaveDirectiveDefinition = append(w.visitors.leaveDirectiveDefinition, visitor) -} - -func (w *Walker) RegisterDirectiveDefinitionVisitor(visitor DirectiveDefinitionVisitor) { - w.RegisterEnterDirectiveDefinitionVisitor(visitor) - w.RegisterLeaveDirectiveDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterUnionMemberTypeVisitor(visitor EnterUnionMemberTypeVisitor) { - w.visitors.enterUnionMemberType = append(w.visitors.enterUnionMemberType, visitor) -} - -func (w *Walker) RegisterLeaveUnionMemberTypeVisitor(visitor LeaveUnionMemberTypeVisitor) { - w.visitors.leaveUnionMemberType = append(w.visitors.leaveUnionMemberType, visitor) -} - -func (w *Walker) RegisterUnionMemberTypeVisitor(visitor UnionMemberTypeVisitor) { - w.RegisterEnterUnionMemberTypeVisitor(visitor) - w.RegisterLeaveUnionMemberTypeVisitor(visitor) -} - -func (w *Walker) RegisterEnterInputObjectTypeDefinitionVisitor(visitor EnterInputObjectTypeDefinitionVisitor) { - w.visitors.enterInputObjectTypeDefinition = append(w.visitors.enterInputObjectTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveInputObjectTypeDefinitionVisitor(visitor LeaveInputObjectTypeDefinitionVisitor) { - w.visitors.leaveInputObjectTypeDefinition = append(w.visitors.leaveInputObjectTypeDefinition, visitor) -} - -func (w *Walker) RegisterInputObjectTypeDefinitionVisitor(visitor InputObjectTypeDefinitionVisitor) { - w.RegisterEnterInputObjectTypeDefinitionVisitor(visitor) - w.RegisterLeaveInputObjectTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterInputObjectTypeExtensionVisitor(visitor EnterInputObjectTypeExtensionVisitor) { - w.visitors.enterInputObjectTypeExtension = append(w.visitors.enterInputObjectTypeExtension, visitor) -} - -func (w *Walker) RegisterLeaveInputObjectTypeExtensionVisitor(visitor LeaveInputObjectTypeExtensionVisitor) { - w.visitors.leaveInputObjectTypeExtension = append(w.visitors.leaveInputObjectTypeExtension, visitor) -} - -func (w *Walker) RegisterInputObjectTypeExtensionVisitor(visitor InputObjectTypeExtensionVisitor) { - w.RegisterEnterInputObjectTypeExtensionVisitor(visitor) - w.RegisterLeaveInputObjectTypeExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterEnumTypeDefinitionVisitor(visitor EnterEnumTypeDefinitionVisitor) { - w.visitors.enterEnumTypeDefinition = append(w.visitors.enterEnumTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveEnumTypeDefinitionVisitor(visitor LeaveEnumTypeDefinitionVisitor) { - w.visitors.leaveEnumTypeDefinition = append(w.visitors.leaveEnumTypeDefinition, visitor) -} - -func (w *Walker) RegisterEnumTypeDefinitionVisitor(visitor EnumTypeDefinitionVisitor) { - w.RegisterEnterEnumTypeDefinitionVisitor(visitor) - w.RegisterLeaveEnumTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterEnumTypeExtensionVisitor(visitor EnterEnumTypeExtensionVisitor) { - w.visitors.enterEnumTypeExtension = append(w.visitors.enterEnumTypeExtension, visitor) -} - -func (w *Walker) RegisterLeaveEnumTypeExtensionVisitor(visitor LeaveEnumTypeExtensionVisitor) { - w.visitors.leaveEnumTypeExtension = append(w.visitors.leaveEnumTypeExtension, visitor) -} - -func (w *Walker) RegisterEnumTypeExtensionVisitor(visitor EnumTypeExtensionVisitor) { - w.RegisterEnterEnumTypeExtensionVisitor(visitor) - w.RegisterLeaveEnumTypeExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterEnumValueDefinitionVisitor(visitor EnterEnumValueDefinitionVisitor) { - w.visitors.enterEnumValueDefinition = append(w.visitors.enterEnumValueDefinition, visitor) -} - -func (w *Walker) RegisterLeaveEnumValueDefinitionVisitor(visitor LeaveEnumValueDefinitionVisitor) { - w.visitors.leaveEnumValueDefinition = append(w.visitors.leaveEnumValueDefinition, visitor) -} - -func (w *Walker) RegisterEnumValueDefinitionVisitor(visitor EnumValueDefinitionVisitor) { - w.RegisterEnterEnumValueDefinitionVisitor(visitor) - w.RegisterLeaveEnumValueDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterUnionTypeDefinitionVisitor(visitor EnterUnionTypeDefinitionVisitor) { - w.visitors.enterUnionTypeDefinition = append(w.visitors.enterUnionTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveUnionTypeDefinitionVisitor(visitor LeaveUnionTypeDefinitionVisitor) { - w.visitors.leaveUnionTypeDefinition = append(w.visitors.leaveUnionTypeDefinition, visitor) -} - -func (w *Walker) RegisterUnionTypeDefinitionVisitor(visitor UnionTypeDefinitionVisitor) { - w.RegisterEnterUnionTypeDefinitionVisitor(visitor) - w.RegisterLeaveUnionTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterUnionTypeExtensionVisitor(visitor EnterUnionTypeExtensionVisitor) { - w.visitors.enterUnionTypeExtension = append(w.visitors.enterUnionTypeExtension, visitor) -} - -func (w *Walker) RegisterLeaveUnionTypeExtensionVisitor(visitor LeaveUnionTypeExtensionVisitor) { - w.visitors.leaveUnionTypeExtension = append(w.visitors.leaveUnionTypeExtension, visitor) -} - -func (w *Walker) RegisterUnionTypeExtensionVisitor(visitor UnionTypeExtensionVisitor) { - w.RegisterEnterUnionTypeExtensionVisitor(visitor) - w.RegisterLeaveUnionTypeExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterScalarTypeExtensionVisitor(visitor EnterScalarTypeExtensionVisitor) { - w.visitors.enterScalarTypeExtension = append(w.visitors.enterScalarTypeExtension, visitor) -} - -func (w *Walker) RegisterLeaveScalarTypeExtensionVisitor(visitor LeaveScalarTypeExtensionVisitor) { - w.visitors.leaveScalarTypeExtension = append(w.visitors.leaveScalarTypeExtension, visitor) -} - -func (w *Walker) RegisterScalarTypeExtensionVisitor(visitor ScalarTypeExtensionVisitor) { - w.RegisterEnterScalarTypeExtensionVisitor(visitor) - w.RegisterLeaveScalarTypeExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterScalarTypeDefinitionVisitor(visitor EnterScalarTypeDefinitionVisitor) { - w.visitors.enterScalarTypeDefinition = append(w.visitors.enterScalarTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveScalarTypeDefinitionVisitor(visitor LeaveScalarTypeDefinitionVisitor) { - w.visitors.leaveScalarTypeDefinition = append(w.visitors.leaveScalarTypeDefinition, visitor) -} - -func (w *Walker) RegisterScalarTypeDefinitionVisitor(visitor ScalarTypeDefinitionVisitor) { - w.RegisterEnterScalarTypeDefinitionVisitor(visitor) - w.RegisterLeaveScalarTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterInterfaceTypeExtensionVisitor(visitor EnterInterfaceTypeExtensionVisitor) { - w.visitors.enterInterfaceTypeExtension = append(w.visitors.enterInterfaceTypeExtension, visitor) -} - -func (w *Walker) RegisterLeaveInterfaceTypeExtensionVisitor(visitor LeaveInterfaceTypeExtensionVisitor) { - w.visitors.leaveInterfaceTypeExtension = append(w.visitors.leaveInterfaceTypeExtension, visitor) -} - -func (w *Walker) RegisterInterfaceTypeExtensionVisitor(visitor InterfaceTypeExtensionVisitor) { - w.RegisterEnterInterfaceTypeExtensionVisitor(visitor) - w.RegisterLeaveInterfaceTypeExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterInterfaceTypeDefinitionVisitor(visitor EnterInterfaceTypeDefinitionVisitor) { - w.visitors.enterInterfaceTypeDefinition = append(w.visitors.enterInterfaceTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveInterfaceTypeDefinitionVisitor(visitor LeaveInterfaceTypeDefinitionVisitor) { - w.visitors.leaveInterfaceTypeDefinition = append(w.visitors.leaveInterfaceTypeDefinition, visitor) -} - -func (w *Walker) RegisterInterfaceTypeDefinitionVisitor(visitor InterfaceTypeDefinitionVisitor) { - w.RegisterEnterInterfaceTypeDefinitionVisitor(visitor) - w.RegisterLeaveInterfaceTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterInputValueDefinitionVisitor(visitor EnterInputValueDefinitionVisitor) { - w.visitors.enterInputValueDefinition = append(w.visitors.enterInputValueDefinition, visitor) -} - -func (w *Walker) RegisterLeaveInputValueDefinitionVisitor(visitor LeaveInputValueDefinitionVisitor) { - w.visitors.leaveInputValueDefinition = append(w.visitors.leaveInputValueDefinition, visitor) -} - -func (w *Walker) RegisterInputValueDefinitionVisitor(visitor InputValueDefinitionVisitor) { - w.RegisterEnterInputValueDefinitionVisitor(visitor) - w.RegisterLeaveInputValueDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterFieldDefinitionVisitor(visitor EnterFieldDefinitionVisitor) { - w.visitors.enterFieldDefinition = append(w.visitors.enterFieldDefinition, visitor) -} - -func (w *Walker) RegisterLeaveFieldDefinitionVisitor(visitor LeaveFieldDefinitionVisitor) { - w.visitors.leaveFieldDefinition = append(w.visitors.leaveFieldDefinition, visitor) -} - -func (w *Walker) RegisterFieldDefinitionVisitor(visitor FieldDefinitionVisitor) { - w.RegisterEnterFieldDefinitionVisitor(visitor) - w.RegisterLeaveFieldDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterObjectTypeExtensionVisitor(visitor EnterObjectTypeExtensionVisitor) { - w.visitors.enterObjectTypeExtension = append(w.visitors.enterObjectTypeExtension, visitor) -} - -func (w *Walker) RegisterLeaveObjectTypeExtensionVisitor(visitor LeaveObjectTypeExtensionVisitor) { - w.visitors.leaveObjectTypeExtension = append(w.visitors.leaveObjectTypeExtension, visitor) -} - -func (w *Walker) RegisterObjectTypeExtensionVisitor(visitor ObjectTypeExtensionVisitor) { - w.RegisterEnterObjectTypeExtensionVisitor(visitor) - w.RegisterLeaveObjectTypeExtensionVisitor(visitor) -} - -func (w *Walker) RegisterEnterObjectTypeDefinitionVisitor(visitor EnterObjectTypeDefinitionVisitor) { - w.visitors.enterObjectTypeDefinition = append(w.visitors.enterObjectTypeDefinition, visitor) -} - -func (w *Walker) RegisterLeaveObjectTypeDefinitionVisitor(visitor LeaveObjectTypeDefinitionVisitor) { - w.visitors.leaveObjectTypeDefinition = append(w.visitors.leaveObjectTypeDefinition, visitor) -} - -func (w *Walker) RegisterObjectTypeDefinitionVisitor(visitor ObjectTypeDefinitionVisitor) { - w.RegisterEnterObjectTypeDefinitionVisitor(visitor) - w.RegisterLeaveObjectTypeDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterFieldVisitor(visitor EnterFieldVisitor) { - w.visitors.enterField = append(w.visitors.enterField, visitor) -} - -func (w *Walker) RegisterLeaveFieldVisitor(visitor LeaveFieldVisitor) { - w.visitors.leaveField = append(w.visitors.leaveField, visitor) -} - -func (w *Walker) RegisterFieldVisitor(visitor FieldVisitor) { - w.RegisterEnterFieldVisitor(visitor) - w.RegisterLeaveFieldVisitor(visitor) -} - -func (w *Walker) RegisterEnterSelectionSetVisitor(visitor EnterSelectionSetVisitor) { - w.visitors.enterSelectionSet = append(w.visitors.enterSelectionSet, visitor) -} - -func (w *Walker) RegisterLeaveSelectionSetVisitor(visitor LeaveSelectionSetVisitor) { - w.visitors.leaveSelectionSet = append(w.visitors.leaveSelectionSet, visitor) -} - -func (w *Walker) RegisterSelectionSetVisitor(visitor SelectionSetVisitor) { - w.RegisterEnterSelectionSetVisitor(visitor) - w.RegisterLeaveSelectionSetVisitor(visitor) -} - -func (w *Walker) RegisterEnterArgumentVisitor(visitor EnterArgumentVisitor) { - w.visitors.enterArgument = append(w.visitors.enterArgument, visitor) -} - -func (w *Walker) RegisterLeaveArgumentVisitor(visitor LeaveArgumentVisitor) { - w.visitors.leaveArgument = append(w.visitors.leaveArgument, visitor) -} - -func (w *Walker) RegisterArgumentVisitor(visitor ArgumentVisitor) { - w.RegisterEnterArgumentVisitor(visitor) - w.RegisterLeaveArgumentVisitor(visitor) -} - -func (w *Walker) RegisterEnterFragmentSpreadVisitor(visitor EnterFragmentSpreadVisitor) { - w.visitors.enterFragmentSpread = append(w.visitors.enterFragmentSpread, visitor) -} - -func (w *Walker) RegisterLeaveFragmentSpreadVisitor(visitor LeaveFragmentSpreadVisitor) { - w.visitors.leaveFragmentSpread = append(w.visitors.leaveFragmentSpread, visitor) -} - -func (w *Walker) RegisterFragmentSpreadVisitor(visitor FragmentSpreadVisitor) { - w.RegisterEnterFragmentSpreadVisitor(visitor) - w.RegisterLeaveFragmentSpreadVisitor(visitor) -} - -func (w *Walker) RegisterEnterInlineFragmentVisitor(visitor EnterInlineFragmentVisitor) { - w.visitors.enterInlineFragment = append(w.visitors.enterInlineFragment, visitor) -} - -func (w *Walker) RegisterLeaveInlineFragmentVisitor(visitor LeaveInlineFragmentVisitor) { - w.visitors.leaveInlineFragment = append(w.visitors.leaveInlineFragment, visitor) -} - -func (w *Walker) RegisterInlineFragmentVisitor(visitor InlineFragmentVisitor) { - w.RegisterEnterInlineFragmentVisitor(visitor) - w.RegisterLeaveInlineFragmentVisitor(visitor) -} - -func (w *Walker) RegisterEnterFragmentDefinitionVisitor(visitor EnterFragmentDefinitionVisitor) { - w.visitors.enterFragmentDefinition = append(w.visitors.enterFragmentDefinition, visitor) -} - -func (w *Walker) RegisterLeaveFragmentDefinitionVisitor(visitor LeaveFragmentDefinitionVisitor) { - w.visitors.leaveFragmentDefinition = append(w.visitors.leaveFragmentDefinition, visitor) -} - -func (w *Walker) RegisterFragmentDefinitionVisitor(visitor FragmentDefinitionVisitor) { - w.RegisterEnterFragmentDefinitionVisitor(visitor) - w.RegisterLeaveFragmentDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterVariableDefinitionVisitor(visitor EnterVariableDefinitionVisitor) { - w.visitors.enterVariableDefinition = append(w.visitors.enterVariableDefinition, visitor) -} - -func (w *Walker) RegisterLeaveVariableDefinitionVisitor(visitor LeaveVariableDefinitionVisitor) { - w.visitors.leaveVariableDefinition = append(w.visitors.leaveVariableDefinition, visitor) -} - -func (w *Walker) RegisterVariableDefinitionVisitor(visitor VariableDefinitionVisitor) { - w.RegisterEnterVariableDefinitionVisitor(visitor) - w.RegisterLeaveVariableDefinitionVisitor(visitor) -} - -func (w *Walker) RegisterEnterOperationVisitor(visitor EnterOperationDefinitionVisitor) { - w.visitors.enterOperation = append(w.visitors.enterOperation, visitor) -} - -func (w *Walker) RegisterLeaveOperationVisitor(visitor LeaveOperationDefinitionVisitor) { - w.visitors.leaveOperation = append(w.visitors.leaveOperation, visitor) -} - -func (w *Walker) RegisterOperationDefinitionVisitor(visitor OperationDefinitionVisitor) { - w.RegisterEnterOperationVisitor(visitor) - w.RegisterLeaveOperationVisitor(visitor) -} - -func (w *Walker) RegisterEnterDirectiveVisitor(visitor EnterDirectiveVisitor) { - w.visitors.enterDirective = append(w.visitors.enterDirective, visitor) -} - -func (w *Walker) RegisterLeaveDirectiveVisitor(visitor LeaveDirectiveVisitor) { - w.visitors.leaveDirective = append(w.visitors.leaveDirective, visitor) -} - -func (w *Walker) RegisterDirectiveVisitor(visitor DirectiveVisitor) { - w.RegisterEnterDirectiveVisitor(visitor) - w.RegisterLeaveDirectiveVisitor(visitor) -} - -func (w *Walker) RegisterAllNodesVisitor(visitor AllNodesVisitor) { - w.RegisterDocumentVisitor(visitor) - w.RegisterExecutableVisitor(visitor) - w.RegisterTypeSystemVisitor(visitor) -} - -func (w *Walker) RegisterEnterDocumentVisitor(visitor EnterDocumentVisitor) { - w.visitors.enterDocument = append(w.visitors.enterDocument, visitor) -} - -func (w *Walker) RegisterLeaveDocumentVisitor(visitor LeaveDocumentVisitor) { - w.visitors.leaveDocument = append(w.visitors.leaveDocument, visitor) -} - -func (w *Walker) RegisterDocumentVisitor(visitor DocumentVisitor) { - w.RegisterEnterDocumentVisitor(visitor) - w.RegisterLeaveDocumentVisitor(visitor) -} - -func (w *Walker) SetVisitorFilter(filter VisitorFilter) { - w.filter = filter -} - -// Walk initiates the walker to start walking the AST from the top root Node -func (w *Walker) Walk(document, definition *ast.Document, report *operationreport.Report) { - if report == nil { - w.Report = &operationreport.Report{} - } else { - w.Report = report - } - w.Ancestors = w.Ancestors[:0] - w.Path = w.Path[:0] - w.typeDefinitions = w.typeDefinitions[:0] - w.document = document - w.definition = definition - w.Depth = 0 - w.stop = false - w.walk() -} - -// Defer runs the provided func() after the current batch of visitors -// This gives you the possibility to execute some code that should e.g. run after all EnterField Visitors -func (w *Walker) Defer(fn func()) { - w.deferred = append(w.deferred, fn) -} - -func (w *Walker) runDeferred() { - if len(w.deferred) == 0 { - return - } - for i := range w.deferred { - w.deferred[i]() - } - w.deferred = w.deferred[:0] -} - -func (w *Walker) appendAncestor(ref int, kind ast.NodeKind) { - w.Ancestors = append(w.Ancestors, ast.Node{ - Kind: kind, - Ref: ref, - }) - - var typeName ast.ByteSlice - - switch kind { - case ast.NodeKindOperationDefinition: - operationType := w.document.OperationDefinitions[ref].OperationType - switch operationType { - case ast.OperationTypeQuery: - typeName = w.definition.Index.QueryTypeName - w.Path = append(w.Path, ast.PathItem{ - Kind: ast.FieldName, - FieldName: literal.QUERY, - }) - case ast.OperationTypeMutation: - typeName = w.definition.Index.MutationTypeName - w.Path = append(w.Path, ast.PathItem{ - Kind: ast.FieldName, - FieldName: literal.MUTATION, - }) - case ast.OperationTypeSubscription: - typeName = w.definition.Index.SubscriptionTypeName - w.Path = append(w.Path, ast.PathItem{ - Kind: ast.FieldName, - FieldName: literal.SUBSCRIPTION, - }) - default: - w.StopWithExternalErr(operationreport.ErrInvalidOperationType(operationType)) - return - } - if len(typeName) == 0 { - w.StopWithExternalErr(operationreport.ErrOperationTypeUndefined(operationType)) - return - } - case ast.NodeKindInlineFragment: - if !w.document.InlineFragmentHasTypeCondition(ref) { - return - } - typeName = w.document.InlineFragmentTypeConditionName(ref) - case ast.NodeKindFragmentDefinition: - typeName = w.document.FragmentDefinitionTypeName(ref) - w.Path = append(w.Path, ast.PathItem{ - Kind: ast.FieldName, - ArrayIndex: 0, - FieldName: typeName, - }) - case ast.NodeKindField: - fieldName := w.document.FieldNameBytes(ref) - w.Path = append(w.Path, ast.PathItem{ - Kind: ast.FieldName, - ArrayIndex: 0, - FieldName: w.document.FieldAliasOrNameBytes(ref), - }) - if bytes.Equal(fieldName, literal.TYPENAME) { - typeName = literal.STRING - } - fields := w.definition.NodeFieldDefinitions(w.typeDefinitions[len(w.typeDefinitions)-1]) - for _, i := range fields { - if bytes.Equal(fieldName, w.definition.FieldDefinitionNameBytes(i)) { - typeName = w.definition.ResolveTypeNameBytes(w.definition.FieldDefinitionType(i)) - break - } - } - if typeName == nil { - typeName := w.definition.NodeNameBytes(w.typeDefinitions[len(w.typeDefinitions)-1]) - w.StopWithExternalErr(operationreport.ErrFieldUndefinedOnType(fieldName, typeName)) - return - } - case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition, ast.NodeKindUnionTypeDefinition: - w.EnclosingTypeDefinition = ast.Node{ - Kind: kind, - Ref: ref, - } - return - default: - return - } - - var exists bool - w.EnclosingTypeDefinition, exists = w.definition.Index.FirstNonExtensionNodeByNameBytes(typeName) - if !exists { - w.StopWithExternalErr(operationreport.ErrTypeUndefined(typeName)) - return - } - - w.typeDefinitions = append(w.typeDefinitions, w.EnclosingTypeDefinition) -} - -func (w *Walker) removeLastAncestor() { - - ancestor := w.Ancestors[len(w.Ancestors)-1] - w.Ancestors = w.Ancestors[:len(w.Ancestors)-1] - - switch ancestor.Kind { - case ast.NodeKindOperationDefinition, ast.NodeKindFragmentDefinition: - w.Path = w.Path[:len(w.Path)-1] - w.typeDefinitions = w.typeDefinitions[:len(w.typeDefinitions)-1] - w.EnclosingTypeDefinition.Kind = ast.NodeKindUnknown - w.EnclosingTypeDefinition.Ref = -1 - case ast.NodeKindInlineFragment: - if w.document.InlineFragmentHasTypeCondition(ancestor.Ref) { - w.typeDefinitions = w.typeDefinitions[:len(w.typeDefinitions)-1] - w.EnclosingTypeDefinition = w.typeDefinitions[len(w.typeDefinitions)-1] - } - case ast.NodeKindField: - w.Path = w.Path[:len(w.Path)-1] - w.typeDefinitions = w.typeDefinitions[:len(w.typeDefinitions)-1] - w.EnclosingTypeDefinition = w.typeDefinitions[len(w.typeDefinitions)-1] - case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition: - w.EnclosingTypeDefinition.Ref = -1 - w.EnclosingTypeDefinition.Kind = ast.NodeKindUnknown - default: - return - } -} - -func (w *Walker) increaseDepth() { - w.Depth++ -} - -func (w *Walker) decreaseDepth() { - w.Depth-- -} - -func (w *Walker) walk() { - - if w.document == nil { - w.Report.AddInternalError(ErrDocumentMustNotBeNil) - return - } - - for i := 0; i < len(w.visitors.enterDocument); { - if w.filter == nil || w.filter.AllowVisitor(EnterDocument, 0, w.visitors.enterDocument[i]) { - w.visitors.enterDocument[i].EnterDocument(w.document, w.definition) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - return - } - i++ - } - - for i := range w.document.RootNodes { - switch w.document.RootNodes[i].Kind { - case ast.NodeKindOperationDefinition: - if w.definition == nil { - w.Report.AddInternalError(ErrDefinitionMustNotBeNil) - return - } - w.walkOperationDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindFragmentDefinition: - if w.definition == nil { - w.Report.AddInternalError(ErrDefinitionMustNotBeNil) - return - } - w.walkFragmentDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindSchemaDefinition: - w.walkSchemaDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindSchemaExtension: - w.walkSchemaExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindDirectiveDefinition: - w.walkDirectiveDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindObjectTypeDefinition: - w.walkObjectTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindObjectTypeExtension: - w.walkObjectTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindInterfaceTypeDefinition: - w.walkInterfaceTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindInterfaceTypeExtension: - w.walkInterfaceTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindScalarTypeDefinition: - w.walkScalarTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindScalarTypeExtension: - w.walkScalarTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindUnionTypeDefinition: - w.walkUnionTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindUnionTypeExtension: - w.walkUnionTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindEnumTypeDefinition: - w.walkEnumTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindEnumTypeExtension: - w.walkEnumTypeExtension(w.document.RootNodes[i].Ref) - case ast.NodeKindInputObjectTypeDefinition: - w.walkInputObjectTypeDefinition(w.document.RootNodes[i].Ref) - case ast.NodeKindInputObjectTypeExtension: - w.walkInputObjectTypeExtension(w.document.RootNodes[i].Ref) - } - - if w.stop { - return - } - if w.skip { - w.skip = false - return - } - } - - for i := 0; i < len(w.visitors.leaveDocument); { - if w.filter == nil || w.filter.AllowVisitor(LeaveDocument, 0, w.visitors.leaveDocument[i]) { - w.visitors.leaveDocument[i].LeaveDocument(w.document, w.definition) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - return - } - i++ - } -} - -func (w *Walker) walkOperationDefinition(ref int) { - w.increaseDepth() - - for i := 0; i < len(w.visitors.enterOperation); { - if w.filter == nil || w.filter.AllowVisitor(EnterOperation, ref, w.visitors.enterOperation[i]) { - w.visitors.enterOperation[i].EnterOperationDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindOperationDefinition) - if w.stop { - return - } - - if w.document.OperationDefinitions[ref].HasVariableDefinitions { - for _, i := range w.document.OperationDefinitions[ref].VariableDefinitions.Refs { - w.walkVariableDefinition(i) - if w.stop { - return - } - } - } - - if w.document.OperationDefinitions[ref].HasDirectives { - for _, i := range w.document.OperationDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.OperationDefinitions[ref].HasSelections { - w.walkSelectionSet(w.document.OperationDefinitions[ref].SelectionSet) - if w.stop { - return - } - } - - w.removeLastAncestor() - - for i := 0; i < len(w.visitors.leaveOperation); { - if w.filter == nil || w.filter.AllowVisitor(LeaveOperation, ref, w.visitors.leaveOperation[i]) { - w.visitors.leaveOperation[i].LeaveOperationDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkVariableDefinition(ref int) { - w.increaseDepth() - - for i := 0; i < len(w.visitors.enterVariableDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterVariableDefinition, ref, w.visitors.enterVariableDefinition[i]) { - w.visitors.enterVariableDefinition[i].EnterVariableDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindVariableDefinition) - if w.stop { - return - } - - if w.document.VariableDefinitions[ref].HasDirectives { - for _, i := range w.document.VariableDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - for i := 0; i < len(w.visitors.leaveVariableDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveVariableDefinition, ref, w.visitors.leaveVariableDefinition[i]) { - w.visitors.leaveVariableDefinition[i].LeaveVariableDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkSelectionSet(ref int) { - w.increaseDepth() - - for i := 0; i < len(w.visitors.enterSelectionSet); { - if w.filter == nil || w.filter.AllowVisitor(EnterSelectionSet, ref, w.visitors.enterSelectionSet[i]) { - w.visitors.enterSelectionSet[i].EnterSelectionSet(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindSelectionSet) - if w.stop { - return - } - -RefsChanged: - for { - refs := w.document.SelectionSets[ref].SelectionRefs - for i, j := range refs { - - w.SelectionsBefore = refs[:i] - w.SelectionsAfter = refs[i+1:] - - switch w.document.Selections[j].Kind { - case ast.SelectionKindField: - w.walkField(w.document.Selections[j].Ref) - case ast.SelectionKindFragmentSpread: - w.walkFragmentSpread(w.document.Selections[j].Ref) - case ast.SelectionKindInlineFragment: - w.walkInlineFragment(w.document.Selections[j].Ref) - } - - if w.stop { - return - } - if !w.refsEqual(refs, w.document.SelectionSets[ref].SelectionRefs) { - continue RefsChanged - } - } - break - } - - w.removeLastAncestor() - - for i := 0; i < len(w.visitors.leaveSelectionSet); { - if w.filter == nil || w.filter.AllowVisitor(LeaveSelectionSet, ref, w.visitors.leaveSelectionSet[i]) { - w.visitors.leaveSelectionSet[i].LeaveSelectionSet(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkField(ref int) { - w.increaseDepth() - - selectionsBefore := w.SelectionsBefore - selectionsAfter := w.SelectionsAfter - - w.setCurrent(ast.NodeKindField, ref) - - for i := 0; i < len(w.visitors.enterField); { - if w.filter == nil || w.filter.AllowVisitor(EnterField, ref, w.visitors.enterField[i]) { - w.visitors.enterField[i].EnterField(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.runDeferred() - - w.appendAncestor(ref, ast.NodeKindField) - if w.stop { - return - } - - if len(w.document.Fields[ref].Arguments.Refs) != 0 { - for _, i := range w.document.Fields[ref].Arguments.Refs { - w.walkArgument(i) - if w.stop { - return - } - } - } - - if w.document.Fields[ref].HasDirectives { - for _, i := range w.document.Fields[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.Fields[ref].HasSelections { - w.walkSelectionSet(w.document.Fields[ref].SelectionSet) - } - - w.removeLastAncestor() - - w.SelectionsBefore = selectionsBefore - w.SelectionsAfter = selectionsAfter - - w.setCurrent(ast.NodeKindField, ref) - - for i := 0; i < len(w.visitors.leaveField); { - if w.filter == nil || w.filter.AllowVisitor(LeaveField, ref, w.visitors.leaveField[i]) { - w.visitors.leaveField[i].LeaveField(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkDirective(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindDirective, ref) - - for i := 0; i < len(w.visitors.enterDirective); { - if w.filter == nil || w.filter.AllowVisitor(EnterDirective, ref, w.visitors.enterDirective[i]) { - w.visitors.enterDirective[i].EnterDirective(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindDirective) - if w.stop { - return - } - - if w.document.Directives[ref].HasArguments { - for _, i := range w.document.Directives[ref].Arguments.Refs { - w.walkArgument(i) - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindDirective, ref) - - for i := 0; i < len(w.visitors.leaveDirective); { - if w.filter == nil || w.filter.AllowVisitor(LeaveDirective, ref, w.visitors.leaveDirective[i]) { - w.visitors.leaveDirective[i].LeaveDirective(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkArgument(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindArgument, ref) - - for i := 0; i < len(w.visitors.enterArgument); { - if w.filter == nil || w.filter.AllowVisitor(EnterArgument, ref, w.visitors.enterArgument[i]) { - w.visitors.enterArgument[i].EnterArgument(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - for i := 0; i < len(w.visitors.leaveArgument); { - if w.filter == nil || w.filter.AllowVisitor(LeaveArgument, ref, w.visitors.leaveArgument[i]) { - w.visitors.leaveArgument[i].LeaveArgument(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkFragmentSpread(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindFragmentSpread, ref) - - for i := 0; i < len(w.visitors.enterFragmentSpread); { - if w.filter == nil || w.filter.AllowVisitor(EnterFragmentSpread, ref, w.visitors.enterFragmentSpread[i]) { - w.visitors.enterFragmentSpread[i].EnterFragmentSpread(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - for i := 0; i < len(w.visitors.leaveFragmentSpread); { - if w.filter == nil || w.filter.AllowVisitor(LeaveFragmentSpread, ref, w.visitors.leaveFragmentSpread[i]) { - w.visitors.leaveFragmentSpread[i].LeaveFragmentSpread(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkInlineFragment(ref int) { - w.increaseDepth() - - selectionsBefore := w.SelectionsBefore - selectionsAfter := w.SelectionsAfter - - w.setCurrent(ast.NodeKindInlineFragment, ref) - - for i := 0; i < len(w.visitors.enterInlineFragment); { - if w.filter == nil || w.filter.AllowVisitor(EnterInlineFragment, ref, w.visitors.enterInlineFragment[i]) { - w.visitors.enterInlineFragment[i].EnterInlineFragment(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindInlineFragment) - if w.stop { - return - } - - if w.document.InlineFragments[ref].HasDirectives { - for _, i := range w.document.InlineFragments[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.InlineFragments[ref].HasSelections { - w.walkSelectionSet(w.document.InlineFragments[ref].SelectionSet) - if w.stop { - return - } - } - - w.removeLastAncestor() - - w.SelectionsBefore = selectionsBefore - w.SelectionsAfter = selectionsAfter - - w.setCurrent(ast.NodeKindInlineFragment, ref) - - for i := 0; i < len(w.visitors.leaveInlineFragment); { - if w.filter == nil || w.filter.AllowVisitor(LeaveInlineFragment, ref, w.visitors.leaveInlineFragment[i]) { - w.visitors.leaveInlineFragment[i].LeaveInlineFragment(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkFragmentDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindFragmentDefinition, ref) - - for i := 0; i < len(w.visitors.enterFragmentDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterFragmentDefinition, ref, w.visitors.enterFragmentDefinition[i]) { - w.visitors.enterFragmentDefinition[i].EnterFragmentDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindFragmentDefinition) - if w.stop { - return - } - - if w.document.FragmentDefinitions[ref].HasDirectives { - for _, i := range w.document.FragmentDefinitions[ref].Directives.Refs { - w.walkDirective(i) - } - } - - if w.document.FragmentDefinitions[ref].HasSelections { - w.walkSelectionSet(w.document.FragmentDefinitions[ref].SelectionSet) - if w.stop { - return - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindFragmentDefinition, ref) - - for i := 0; i < len(w.visitors.leaveFragmentDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveFragmentDefinition, ref, w.visitors.leaveFragmentDefinition[i]) { - w.visitors.leaveFragmentDefinition[i].LeaveFragmentDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkObjectTypeDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindObjectTypeDefinition, ref) - - for i := 0; i < len(w.visitors.enterObjectTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterObjectTypeDefinition, ref, w.visitors.enterObjectTypeDefinition[i]) { - w.visitors.enterObjectTypeDefinition[i].EnterObjectTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindObjectTypeDefinition) - if w.stop { - return - } - - if w.document.ObjectTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.ObjectTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.ObjectTypeDefinitions[ref].HasFieldDefinitions { - for _, i := range w.document.ObjectTypeDefinitions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindObjectTypeDefinition, ref) - - for i := 0; i < len(w.visitors.leaveObjectTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveObjectTypeDefinition, ref, w.visitors.leaveObjectTypeDefinition[i]) { - w.visitors.leaveObjectTypeDefinition[i].LeaveObjectTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkObjectTypeExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindObjectTypeExtension, ref) - - for i := 0; i < len(w.visitors.enterObjectTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterObjectTypeExtension, ref, w.visitors.enterObjectTypeExtension[i]) { - w.visitors.enterObjectTypeExtension[i].EnterObjectTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindObjectTypeExtension) - if w.stop { - return - } - - if w.document.ObjectTypeExtensions[ref].HasDirectives { - for _, i := range w.document.ObjectTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.ObjectTypeExtensions[ref].HasFieldDefinitions { - for _, i := range w.document.ObjectTypeExtensions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindObjectTypeExtension, ref) - - for i := 0; i < len(w.visitors.leaveObjectTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveObjectTypeExtension, ref, w.visitors.leaveObjectTypeExtension[i]) { - w.visitors.leaveObjectTypeExtension[i].LeaveObjectTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkFieldDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindFieldDefinition, ref) - - for i := 0; i < len(w.visitors.enterFieldDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterFieldDefinition, ref, w.visitors.enterFieldDefinition[i]) { - w.visitors.enterFieldDefinition[i].EnterFieldDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindFieldDefinition) - if w.stop { - return - } - - if w.document.FieldDefinitions[ref].HasArgumentsDefinitions { - for _, i := range w.document.FieldDefinitions[ref].ArgumentsDefinition.Refs { - w.walkInputValueDefinition(i) - if w.stop { - return - } - } - } - - if w.document.FieldDefinitions[ref].HasDirectives { - for _, i := range w.document.FieldDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindFieldDefinition, ref) - - for i := 0; i < len(w.visitors.leaveFieldDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveFieldDefinition, ref, w.visitors.leaveFieldDefinition[i]) { - w.visitors.leaveFieldDefinition[i].LeaveFieldDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkInputValueDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindInputValueDefinition, ref) - - for i := 0; i < len(w.visitors.enterInputValueDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterInputValueDefinition, ref, w.visitors.enterInputValueDefinition[i]) { - w.visitors.enterInputValueDefinition[i].EnterInputValueDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindInputValueDefinition) - if w.stop { - return - } - - if w.document.InputValueDefinitions[ref].HasDirectives { - for _, i := range w.document.InputValueDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindInputValueDefinition, ref) - - for i := 0; i < len(w.visitors.leaveInputValueDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveInputValueDefinition, ref, w.visitors.leaveInputValueDefinition[i]) { - w.visitors.leaveInputValueDefinition[i].LeaveInputValueDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkInterfaceTypeDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindInterfaceTypeDefinition, ref) - - for i := 0; i < len(w.visitors.enterInterfaceTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterInterfaceTypeDefinition, ref, w.visitors.enterInterfaceTypeDefinition[i]) { - w.visitors.enterInterfaceTypeDefinition[i].EnterInterfaceTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindInterfaceTypeDefinition) - if w.stop { - return - } - - if w.document.InterfaceTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.InterfaceTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.InterfaceTypeDefinitions[ref].HasFieldDefinitions { - for _, i := range w.document.InterfaceTypeDefinitions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindInterfaceTypeDefinition, ref) - - for i := 0; i < len(w.visitors.leaveInterfaceTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveInterfaceTypeDefinition, ref, w.visitors.leaveInterfaceTypeDefinition[i]) { - w.visitors.leaveInterfaceTypeDefinition[i].LeaveInterfaceTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkInterfaceTypeExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindInterfaceTypeExtension, ref) - - for i := 0; i < len(w.visitors.enterInterfaceTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterInterfaceTypeExtension, ref, w.visitors.enterInterfaceTypeExtension[i]) { - w.visitors.enterInterfaceTypeExtension[i].EnterInterfaceTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindInterfaceTypeExtension) - if w.stop { - return - } - - if w.document.InterfaceTypeExtensions[ref].HasDirectives { - for _, i := range w.document.InterfaceTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.InterfaceTypeExtensions[ref].HasFieldDefinitions { - for _, i := range w.document.InterfaceTypeExtensions[ref].FieldsDefinition.Refs { - w.walkFieldDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindInterfaceTypeExtension, ref) - - for i := 0; i < len(w.visitors.leaveInterfaceTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveInterfaceTypeExtension, ref, w.visitors.leaveInterfaceTypeExtension[i]) { - w.visitors.leaveInterfaceTypeExtension[i].LeaveInterfaceTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkScalarTypeDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindScalarTypeDefinition, ref) - - for i := 0; i < len(w.visitors.enterScalarTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterScalarTypeDefinition, ref, w.visitors.enterScalarTypeDefinition[i]) { - w.visitors.enterScalarTypeDefinition[i].EnterScalarTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindScalarTypeDefinition) - if w.stop { - return - } - - if w.document.ScalarTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.ScalarTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindScalarTypeDefinition, ref) - - for i := 0; i < len(w.visitors.leaveScalarTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveScalarTypeDefinition, ref, w.visitors.leaveScalarTypeDefinition[i]) { - w.visitors.leaveScalarTypeDefinition[i].LeaveScalarTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkScalarTypeExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindScalarTypeExtension, ref) - - for i := 0; i < len(w.visitors.enterScalarTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterScalarTypeExtension, ref, w.visitors.enterScalarTypeExtension[i]) { - w.visitors.enterScalarTypeExtension[i].EnterScalarTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindScalarTypeExtension) - if w.stop { - return - } - - if w.document.ScalarTypeExtensions[ref].HasDirectives { - for _, i := range w.document.ScalarTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindScalarTypeExtension, ref) - - for i := 0; i < len(w.visitors.leaveScalarTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveScalarTypeExtension, ref, w.visitors.leaveScalarTypeExtension[i]) { - w.visitors.leaveScalarTypeExtension[i].LeaveScalarTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkUnionTypeDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindUnionTypeDefinition, ref) - - for i := 0; i < len(w.visitors.enterUnionTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterUnionTypeDefinition, ref, w.visitors.enterUnionTypeDefinition[i]) { - w.visitors.enterUnionTypeDefinition[i].EnterUnionTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindUnionTypeDefinition) - if w.stop { - return - } - - if w.document.UnionTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.UnionTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.UnionTypeDefinitions[ref].HasUnionMemberTypes { - for _, i := range w.document.UnionTypeDefinitions[ref].UnionMemberTypes.Refs { - w.walkUnionMemberType(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindUnionTypeDefinition, ref) - - for i := 0; i < len(w.visitors.leaveUnionTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveUnionTypeDefinition, ref, w.visitors.leaveUnionTypeDefinition[i]) { - w.visitors.leaveUnionTypeDefinition[i].LeaveUnionTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkUnionTypeExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindUnionTypeExtension, ref) - - for i := 0; i < len(w.visitors.enterUnionTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterUnionTypeExtension, ref, w.visitors.enterUnionTypeExtension[i]) { - w.visitors.enterUnionTypeExtension[i].EnterUnionTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindUnionTypeExtension) - if w.stop { - return - } - - if w.document.UnionTypeExtensions[ref].HasDirectives { - for _, i := range w.document.UnionTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.UnionTypeExtensions[ref].HasUnionMemberTypes { - for _, i := range w.document.UnionTypeExtensions[ref].UnionMemberTypes.Refs { - w.walkUnionMemberType(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindUnionTypeExtension, ref) - - for i := 0; i < len(w.visitors.leaveUnionTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveUnionTypeExtension, ref, w.visitors.leaveUnionTypeExtension[i]) { - w.visitors.leaveUnionTypeExtension[i].LeaveUnionTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkUnionMemberType(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindUnionMemberType, ref) - - for i := 0; i < len(w.visitors.enterUnionMemberType); { - if w.filter == nil || w.filter.AllowVisitor(EnterUnionMemberType, ref, w.visitors.enterUnionMemberType[i]) { - w.visitors.enterUnionMemberType[i].EnterUnionMemberType(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - for i := 0; i < len(w.visitors.leaveUnionMemberType); { - if w.filter == nil || w.filter.AllowVisitor(LeaveUnionMemberType, ref, w.visitors.leaveUnionMemberType[i]) { - w.visitors.leaveUnionMemberType[i].LeaveUnionMemberType(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkEnumTypeDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindEnumTypeDefinition, ref) - - for i := 0; i < len(w.visitors.enterEnumTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterEnumTypeDefinition, ref, w.visitors.enterEnumTypeDefinition[i]) { - w.visitors.enterEnumTypeDefinition[i].EnterEnumTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindEnumTypeDefinition) - if w.stop { - return - } - - if w.document.EnumTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.EnumTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.EnumTypeDefinitions[ref].HasEnumValuesDefinition { - for _, i := range w.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs { - w.walkEnumValueDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindEnumTypeDefinition, ref) - - for i := 0; i < len(w.visitors.leaveEnumTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveEnumTypeDefinition, ref, w.visitors.leaveEnumTypeDefinition[i]) { - w.visitors.leaveEnumTypeDefinition[i].LeaveEnumTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkEnumTypeExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindEnumTypeExtension, ref) - - for i := 0; i < len(w.visitors.enterEnumTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterEnumTypeExtension, ref, w.visitors.enterEnumTypeExtension[i]) { - w.visitors.enterEnumTypeExtension[i].EnterEnumTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindEnumTypeExtension) - if w.stop { - return - } - - if w.document.EnumTypeExtensions[ref].HasDirectives { - for _, i := range w.document.EnumTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.EnumTypeExtensions[ref].HasEnumValuesDefinition { - for _, i := range w.document.EnumTypeExtensions[ref].EnumValuesDefinition.Refs { - w.walkEnumValueDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindEnumTypeExtension, ref) - - for i := 0; i < len(w.visitors.leaveEnumTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveEnumTypeExtension, ref, w.visitors.leaveEnumTypeExtension[i]) { - w.visitors.leaveEnumTypeExtension[i].LeaveEnumTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkEnumValueDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindEnumValueDefinition, ref) - - for i := 0; i < len(w.visitors.enterEnumValueDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterEnumValueDefinition, ref, w.visitors.enterEnumValueDefinition[i]) { - w.visitors.enterEnumValueDefinition[i].EnterEnumValueDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindEnumValueDefinition) - if w.stop { - return - } - - if w.document.EnumValueDefinitions[ref].HasDirectives { - for _, i := range w.document.EnumValueDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindEnumValueDefinition, ref) - - for i := 0; i < len(w.visitors.leaveEnumValueDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveEnumValueDefinition, ref, w.visitors.leaveEnumValueDefinition[i]) { - w.visitors.leaveEnumValueDefinition[i].LeaveEnumValueDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkInputObjectTypeDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindInputObjectTypeDefinition, ref) - - for i := 0; i < len(w.visitors.enterInputObjectTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterInputObjectTypeDefinition, ref, w.visitors.enterInputObjectTypeDefinition[i]) { - w.visitors.enterInputObjectTypeDefinition[i].EnterInputObjectTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindInputObjectTypeDefinition) - if w.stop { - return - } - - if w.document.InputObjectTypeDefinitions[ref].HasDirectives { - for _, i := range w.document.InputObjectTypeDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition { - for _, i := range w.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs { - w.walkInputValueDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindInputObjectTypeDefinition, ref) - - for i := 0; i < len(w.visitors.leaveInputObjectTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveInputObjectTypeDefinition, ref, w.visitors.leaveInputObjectTypeDefinition[i]) { - w.visitors.leaveInputObjectTypeDefinition[i].LeaveInputObjectTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkInputObjectTypeExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindInputObjectTypeExtension, ref) - - for i := 0; i < len(w.visitors.enterInputObjectTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterInputObjectTypeExtension, ref, w.visitors.enterInputObjectTypeExtension[i]) { - w.visitors.enterInputObjectTypeExtension[i].EnterInputObjectTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindInputObjectTypeExtension) - if w.stop { - return - } - - if w.document.InputObjectTypeExtensions[ref].HasDirectives { - for _, i := range w.document.InputObjectTypeExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - if w.document.InputObjectTypeExtensions[ref].HasInputFieldsDefinition { - for _, i := range w.document.InputObjectTypeExtensions[ref].InputFieldsDefinition.Refs { - w.walkInputValueDefinition(i) - if w.stop { - return - } - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindInputObjectTypeExtension, ref) - - for i := 0; i < len(w.visitors.leaveInputObjectTypeExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveInputObjectTypeExtension, ref, w.visitors.leaveInputObjectTypeExtension[i]) { - w.visitors.leaveInputObjectTypeExtension[i].LeaveInputObjectTypeExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkDirectiveDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindDirectiveDefinition, ref) - - for i := 0; i < len(w.visitors.enterDirectiveDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterDirectiveDefinition, ref, w.visitors.enterDirectiveDefinition[i]) { - w.visitors.enterDirectiveDefinition[i].EnterDirectiveDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindDirectiveDefinition) - if w.stop { - return - } - - if w.document.DirectiveDefinitions[ref].HasArgumentsDefinitions { - for _, i := range w.document.DirectiveDefinitions[ref].ArgumentsDefinition.Refs { - w.walkInputValueDefinition(i) - if w.stop { - return - } - } - } - - iter := w.document.DirectiveDefinitions[ref].DirectiveLocations.Iterable() - for iter.Next() { - w.walkDirectiveLocation(iter.Value()) - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindDirectiveDefinition, ref) - - for i := 0; i < len(w.visitors.leaveDirectiveDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveDirectiveDefinition, ref, w.visitors.leaveDirectiveDefinition[i]) { - w.visitors.leaveDirectiveDefinition[i].LeaveDirectiveDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkDirectiveLocation(location ast.DirectiveLocation) { - w.increaseDepth() - - for i := 0; i < len(w.visitors.enterDirectiveLocation); { - if w.filter == nil || w.filter.AllowVisitor(EnterDirectiveLocation, 0, w.visitors.enterDirectiveLocation[i]) { - w.visitors.enterDirectiveLocation[i].EnterDirectiveLocation(location) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - for i := 0; i < len(w.visitors.leaveDirectiveLocation); { - if w.filter == nil || w.filter.AllowVisitor(LeaveDirectiveLocation, 0, w.visitors.leaveDirectiveLocation[i]) { - w.visitors.leaveDirectiveLocation[i].LeaveDirectiveLocation(location) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkSchemaDefinition(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindSchemaDefinition, ref) - - for i := 0; i < len(w.visitors.enterSchemaDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterSchemaDefinition, ref, w.visitors.enterSchemaDefinition[i]) { - w.visitors.enterSchemaDefinition[i].EnterSchemaDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindSchemaDefinition) - if w.stop { - return - } - - if w.document.SchemaDefinitions[ref].HasDirectives { - for _, i := range w.document.SchemaDefinitions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - for _, i := range w.document.SchemaDefinitions[ref].RootOperationTypeDefinitions.Refs { - w.walkRootOperationTypeDefinition(i) - if w.stop { - return - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindSchemaDefinition, ref) - - for i := 0; i < len(w.visitors.leaveSchemaDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveSchemaDefinition, ref, w.visitors.leaveSchemaDefinition[i]) { - w.visitors.leaveSchemaDefinition[i].LeaveSchemaDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkSchemaExtension(ref int) { - w.increaseDepth() - - w.setCurrent(ast.NodeKindSchemaExtension, ref) - - for i := 0; i < len(w.visitors.enterSchemaExtension); { - if w.filter == nil || w.filter.AllowVisitor(EnterSchemaExtension, ref, w.visitors.enterSchemaExtension[i]) { - w.visitors.enterSchemaExtension[i].EnterSchemaExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.appendAncestor(ref, ast.NodeKindSchemaExtension) - if w.stop { - return - } - - if w.document.SchemaExtensions[ref].HasDirectives { - for _, i := range w.document.SchemaExtensions[ref].Directives.Refs { - w.walkDirective(i) - if w.stop { - return - } - } - } - - for _, i := range w.document.SchemaExtensions[ref].RootOperationTypeDefinitions.Refs { - w.walkRootOperationTypeDefinition(i) - if w.stop { - return - } - } - - w.removeLastAncestor() - - w.setCurrent(ast.NodeKindSchemaExtension, ref) - - for i := 0; i < len(w.visitors.leaveSchemaExtension); { - if w.filter == nil || w.filter.AllowVisitor(LeaveSchemaExtension, ref, w.visitors.leaveSchemaExtension[i]) { - w.visitors.leaveSchemaExtension[i].LeaveSchemaExtension(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) walkRootOperationTypeDefinition(ref int) { - w.increaseDepth() - - for i := 0; i < len(w.visitors.enterRootOperationTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(EnterRootOperationTypeDefinition, ref, w.visitors.enterRootOperationTypeDefinition[i]) { - w.visitors.enterRootOperationTypeDefinition[i].EnterRootOperationTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - for i := 0; i < len(w.visitors.leaveRootOperationTypeDefinition); { - if w.filter == nil || w.filter.AllowVisitor(LeaveRootOperationTypeDefinition, ref, w.visitors.leaveRootOperationTypeDefinition[i]) { - w.visitors.leaveRootOperationTypeDefinition[i].LeaveRootOperationTypeDefinition(ref) - } - if w.revisit { - w.revisit = false - continue - } - if w.stop { - return - } - if w.skip { - w.skip = false - w.decreaseDepth() - return - } - i++ - } - - w.decreaseDepth() -} - -func (w *Walker) refsEqual(left, right []int) bool { - if len(left) != len(right) { - return false - } - for i := range left { - if left[i] != right[i] { - return false - } - } - return true -} - -func (w *Walker) SkipNode() { - w.skip = true -} - -func (w *Walker) Stop() { - w.stop = true -} - -func (w *Walker) RevisitNode() { - w.revisit = true -} - -func (w *Walker) StopWithInternalErr(err error) { - w.stop = true - w.Report.AddInternalError(err) -} - -func (w *Walker) HandleInternalErr(err error) bool { - if err != nil { - w.StopWithInternalErr(err) - return true - } - return false -} - -func (w *Walker) StopWithExternalErr(err operationreport.ExternalError) { - w.stop = true - err.Path = w.Path - w.Report.AddExternalError(err) -} - -func (w *Walker) StopWithErr(internal error, external operationreport.ExternalError) { - w.stop = true - external.Path = w.Path - w.Report.AddInternalError(internal) - w.Report.AddExternalError(external) -} - -func (w *Walker) ArgumentInputValueDefinition(argument int) (definition int, exits bool) { - argumentName := w.document.ArgumentNameBytes(argument) - ancestor := w.Ancestors[len(w.Ancestors)-1] - switch ancestor.Kind { - case ast.NodeKindField: - fieldName := w.document.FieldNameBytes(ancestor.Ref) - fieldTypeDef := w.typeDefinitions[len(w.typeDefinitions)-2] - definition = w.definition.NodeFieldDefinitionArgumentDefinitionByName(fieldTypeDef, fieldName, argumentName) - exits = definition != -1 - case ast.NodeKindDirective: - directiveName := w.document.DirectiveNameBytes(ancestor.Ref) - definition = w.definition.DirectiveArgumentInputValueDefinition(directiveName, argumentName) - exits = definition != -1 - } - return -} - -// FieldDefinitionWithExists -// Deprecated: use FieldDefinition -func (w *Walker) FieldDefinitionWithExists(field int) (definition int, exists bool) { - return w.FieldDefinition(field) -} - -// FieldDefinition - returns field definition ref from schema definition -// field - ref to a field from operation -// returns: -// definition - ref to a field definition from schema definition document if it is exists otherwise returns ast.InvalidRef -// exists - true if field exists -func (w *Walker) FieldDefinition(field int) (definition int, exists bool) { - fieldName := w.document.FieldNameBytes(field) - return w.definition.NodeFieldDefinitionByName(w.EnclosingTypeDefinition, fieldName) -} - -func (w *Walker) Ancestor() ast.Node { - if len(w.Ancestors) == 0 { - return ast.InvalidNode - } - return w.Ancestors[len(w.Ancestors)-1] -} - -func (w *Walker) AncestorNameBytes() ast.ByteSlice { - if len(w.Ancestors) == 0 { - return nil - } - return w.document.NodeNameBytes(w.Ancestors[len(w.Ancestors)-1]) -} - -func (w *Walker) FieldDefinitionDirectiveArgumentValueByName(field int, directiveName, argumentName ast.ByteSlice) (ast.Value, bool) { - definition, exists := w.FieldDefinition(field) - if !exists { - return ast.Value{}, false - } - - directive, exists := w.definition.FieldDefinitionDirectiveByName(definition, directiveName) - if !exists { - return ast.Value{}, false - } - - return w.definition.DirectiveArgumentValueByName(directive, argumentName) -} diff --git a/pkg/astvisitor/visitor_test.go b/pkg/astvisitor/visitor_test.go deleted file mode 100644 index d57f2347c..000000000 --- a/pkg/astvisitor/visitor_test.go +++ /dev/null @@ -1,1083 +0,0 @@ -package astvisitor - -import ( - "bytes" - "fmt" - "io" - "os" - "testing" - - "github.com/jensneuse/diffview" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -var must = func(err error) { - if err != nil { - panic(err) - } -} - -func TestVisitOperation(t *testing.T) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(testOperation) - report := operationreport.Report{} - - walker := NewWalker(48) - buff := &bytes.Buffer{} - visitor := &printingVisitor{ - Walker: &walker, - out: buff, - operation: &operation, - definition: &definition, - } - - walker.RegisterAllNodesVisitor(visitor) - - walker.Walk(&operation, &definition, &report) - - out := buff.Bytes() - goldie.Assert(t, "visitor", out) - - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/visitor.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("introspection_lexed", fixture, out) - } -} - -func TestVisitWithTypeName(t *testing.T) { - operation := ` - query getApi($id: String!) { - api(id: $id) { - __typename - ... on Api { - __typename - id - name - } - ... on RequestResult { - __typename - status - message - } - } - }` - definition := ` - schema { - query: Query - } - type Query { - api(id: String): ApiResult - } - union ApiResult = Api | RequestResult - type Api { - id: String - name: String - } - type RequestResult { - status: String - message: String - } - scalar String - ` - - walker := NewWalker(8) - op := unsafeparser.ParseGraphqlDocumentString(operation) - def := unsafeparser.ParseGraphqlDocumentString(definition) - var report operationreport.Report - walker.Walk(&op, &def, &report) - if report.HasErrors() { - t.Fatal(report.Error()) - } -} - -func TestVisitSchemaDefinition(t *testing.T) { - - operation := unsafeparser.ParseGraphqlDocumentString(testDefinitions) - report := operationreport.Report{} - walker := NewWalker(48) - buff := &bytes.Buffer{} - visitor := &printingVisitor{ - Walker: &walker, - out: buff, - operation: &operation, - } - - walker.RegisterAllNodesVisitor(visitor) - - walker.Walk(&operation, nil, &report) - if report.HasErrors() { - t.Fatal(report.Error()) - } - - out := buff.Bytes() - goldie.Assert(t, "schema_visitor", out) - - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/schema_visitor.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("schema_visitor", fixture, out) - } -} - -func TestWalker_Path(t *testing.T) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(` - query { - posts { - id - description - user { - id - name - } - } - } - - query MyQuery { - posts { - id - description - user { - id - name - posts { - id - } - } - } - }`) - - walker := NewWalker(48) - buff := &bytes.Buffer{} - report := operationreport.Report{} - pathVisitor := pathVisitor{ - Walker: &walker, - out: buff, - } - - walker.RegisterEnterDocumentVisitor(&pathVisitor) - walker.RegisterEnterFieldVisitor(&pathVisitor) - - walker.Walk(&operation, &definition, &report) - - if report.HasErrors() { - t.Fatal(report.Error()) - } - - out := buff.Bytes() - goldie.Assert(t, "path", out) - - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/path.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("path", fixture, out) - } -} - -type pathVisitor struct { - *Walker - out *bytes.Buffer - op, def *ast.Document -} - -func (p *pathVisitor) EnterDocument(operation, definition *ast.Document) { - p.op, p.def = operation, definition -} - -func (p *pathVisitor) EnterField(ref int) { - p.out.Write([]byte(fmt.Sprintf("EnterField: %s, path: %s\n", p.op.FieldNameUnsafeString(ref), p.Path))) -} - -func TestVisitWithSkip(t *testing.T) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(` - query PostsUserQuery { - posts { - id - description - user { - id - name - } - } - }`) - - walker := NewWalker(48) - buff := &bytes.Buffer{} - visitor := &printingVisitor{ - Walker: &walker, - out: buff, - operation: &operation, - definition: &definition, - } - report := operationreport.Report{} - - skipUser := skipUserVisitor{ - Walker: &walker, - } - - walker.RegisterEnterDocumentVisitor(&skipUser) - walker.RegisterEnterFieldVisitor(&skipUser) - walker.RegisterAllNodesVisitor(visitor) - - walker.Walk(&operation, &definition, &report) - - out := buff.Bytes() - goldie.Assert(t, "visitor_skip", out) - - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/visitor_skip.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("introspection_lexed", fixture, out) - } -} - -type skipUserVisitor struct { - *Walker - operation, definition *ast.Document -} - -func (s *skipUserVisitor) EnterDocument(operation, definition *ast.Document) { - s.operation = operation - s.definition = definition -} - -func (s *skipUserVisitor) EnterField(ref int) { - if bytes.Equal(s.operation.FieldNameBytes(ref), []byte("user")) { - s.SkipNode() - } -} - -func BenchmarkVisitor(b *testing.B) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(testOperation) - - visitor := &dummyVisitor{} - - walker := NewWalker(48) - walker.RegisterAllNodesVisitor(visitor) - report := operationreport.Report{} - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - report.Reset() - walker.Walk(&operation, &definition, &report) - } -} - -func BenchmarkMinimalVisitor(b *testing.B) { - - definition := unsafeparser.ParseGraphqlDocumentString(testDefinition) - operation := unsafeparser.ParseGraphqlDocumentString(testOperation) - - visitor := &minimalVisitor{} - - walker := NewWalker(48) - walker.RegisterEnterFieldVisitor(visitor) - walker.SetVisitorFilter(visitor) - report := operationreport.Report{} - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - report.Reset() - walker.Walk(&operation, &definition, &report) - } -} - -type minimalVisitor struct { -} - -func (m *minimalVisitor) AllowVisitor(kind VisitorKind, ref int, visitor interface{}) bool { - return visitor == m -} - -func (m *minimalVisitor) EnterField(ref int) { - -} - -type dummyVisitor struct { -} - -func (d *dummyVisitor) EnterSchemaExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveSchemaExtension(ref int) { - -} - -func (d *dummyVisitor) EnterSchemaDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveSchemaDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterRootOperationTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveRootOperationTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveDirectiveLocation(location ast.DirectiveLocation) { - -} - -func (d *dummyVisitor) EnterDirectiveDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveDirectiveDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) { - -} - -func (d *dummyVisitor) EnterUnionMemberType(ref int) { - -} - -func (d *dummyVisitor) LeaveUnionMemberType(ref int) { - -} - -func (d *dummyVisitor) EnterObjectTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveObjectTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterObjectTypeExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveObjectTypeExtension(ref int) { - -} - -func (d *dummyVisitor) EnterFieldDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveFieldDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterInputValueDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveInputValueDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterInterfaceTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveInterfaceTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterInterfaceTypeExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveInterfaceTypeExtension(ref int) { - -} - -func (d *dummyVisitor) EnterScalarTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveScalarTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterScalarTypeExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveScalarTypeExtension(ref int) { - -} - -func (d *dummyVisitor) EnterUnionTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveUnionTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterUnionTypeExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveUnionTypeExtension(ref int) { - -} - -func (d *dummyVisitor) EnterEnumTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveEnumTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterEnumTypeExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveEnumTypeExtension(ref int) { - -} - -func (d *dummyVisitor) EnterEnumValueDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveEnumValueDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterInputObjectTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveInputObjectTypeDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterInputObjectTypeExtension(ref int) { - -} - -func (d *dummyVisitor) LeaveInputObjectTypeExtension(ref int) { - -} - -func (d *dummyVisitor) EnterDocument(operation, definition *ast.Document) { - -} - -func (d *dummyVisitor) LeaveDocument(operation, definition *ast.Document) { - -} - -func (d *dummyVisitor) EnterDirective(ref int) { - -} - -func (d *dummyVisitor) LeaveDirective(ref int) { - -} - -func (d *dummyVisitor) EnterVariableDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveVariableDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterOperationDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveOperationDefinition(ref int) { - -} - -func (d *dummyVisitor) EnterSelectionSet(ref int) { - -} - -func (d *dummyVisitor) LeaveSelectionSet(ref int) { - -} - -func (d *dummyVisitor) EnterField(ref int) { - -} - -func (d *dummyVisitor) LeaveField(ref int) { - -} - -func (d *dummyVisitor) EnterArgument(ref int) { - -} - -func (d *dummyVisitor) LeaveArgument(ref int) { - -} - -func (d *dummyVisitor) EnterFragmentSpread(ref int) { - -} - -func (d *dummyVisitor) LeaveFragmentSpread(ref int) { - -} - -func (d *dummyVisitor) EnterInlineFragment(ref int) { - -} - -func (d *dummyVisitor) LeaveInlineFragment(ref int) { - -} - -func (d *dummyVisitor) EnterFragmentDefinition(ref int) { - -} - -func (d *dummyVisitor) LeaveFragmentDefinition(ref int) { - -} - -type printingVisitor struct { - *Walker - out io.Writer - operation, definition *ast.Document - indentation int -} - -func (p *printingVisitor) must(_ int, err error) { - if err != nil { - panic(err) - } -} - -func (p *printingVisitor) printIndentation() { - for i := 0; i < p.indentation; i++ { - p.must(fmt.Fprintf(p.out, " ")) - } -} - -func (p *printingVisitor) enter() { - p.printIndentation() - p.indentation += 2 -} -func (p *printingVisitor) leave() { - p.indentation -= 2 - p.printIndentation() -} - -func (p *printingVisitor) EnterSchemaDefinition(ref int) { - p.enter() - p.must(fmt.Fprintf(p.out, "EnterSchemaDefinition: ref: %d\n", ref)) -} - -func (p *printingVisitor) LeaveSchemaDefinition(ref int) { - p.leave() - p.must(fmt.Fprintf(p.out, "LeaveSchemaDefinition: ref: %d\n\n", ref)) -} - -func (p *printingVisitor) EnterSchemaExtension(ref int) { - p.enter() - p.must(fmt.Fprintf(p.out, "EnterSchemaExtension: ref: %d\n", ref)) -} - -func (p *printingVisitor) LeaveSchemaExtension(ref int) { - p.leave() - p.must(fmt.Fprintf(p.out, "LeaveSchemaExtension: ref: %d\n\n", ref)) -} - -func (p *printingVisitor) EnterRootOperationTypeDefinition(ref int) { - p.enter() - name := p.operation.RootOperationTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterRootOperationTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveRootOperationTypeDefinition(ref int) { - p.leave() - name := p.operation.RootOperationTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveRootOperationTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) EnterDirectiveDefinition(ref int) { - p.enter() - name := p.operation.DirectiveDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterDirectiveDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveDirectiveDefinition(ref int) { - p.leave() - name := p.operation.DirectiveDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveDirectiveDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) { - p.enter() - p.must(fmt.Fprintf(p.out, "EnterDirectiveLocation(%s)\n", location)) -} - -func (p *printingVisitor) LeaveDirectiveLocation(location ast.DirectiveLocation) { - p.leave() - p.must(fmt.Fprintf(p.out, "LeaveDirectiveLocation(%s)\n", location)) -} - -func (p *printingVisitor) EnterObjectTypeDefinition(ref int) { - p.enter() - name := p.operation.ObjectTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterObjectTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveObjectTypeDefinition(ref int) { - p.leave() - name := p.operation.ObjectTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveObjectTypeDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterObjectTypeExtension(ref int) { - p.enter() - name := p.operation.ObjectTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterObjectTypeExtension(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveObjectTypeExtension(ref int) { - p.leave() - name := p.operation.ObjectTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveObjectTypeExtension(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterFieldDefinition(ref int) { - p.enter() - name := p.operation.FieldDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterFieldDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveFieldDefinition(ref int) { - p.leave() - name := p.operation.FieldDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveFieldDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) EnterInputValueDefinition(ref int) { - p.enter() - name := p.operation.InputValueDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterInputValueDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveInputValueDefinition(ref int) { - p.leave() - name := p.operation.InputValueDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveInputValueDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) EnterInterfaceTypeDefinition(ref int) { - p.enter() - name := p.operation.InterfaceTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterInterfaceTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveInterfaceTypeDefinition(ref int) { - p.leave() - name := p.operation.InterfaceTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveInterfaceTypeDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterInterfaceTypeExtension(ref int) { - p.enter() - name := p.operation.InterfaceTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterInterfaceTypeExtension(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveInterfaceTypeExtension(ref int) { - p.leave() - name := p.operation.InterfaceTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveInterfaceTypeExtension(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterScalarTypeDefinition(ref int) { - p.enter() - name := p.operation.ScalarTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterScalarTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveScalarTypeDefinition(ref int) { - p.leave() - name := p.operation.ScalarTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveScalarTypeDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterScalarTypeExtension(ref int) { - p.enter() - name := p.operation.ScalarTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterScalarTypeExtension(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveScalarTypeExtension(ref int) { - p.leave() - name := p.operation.ScalarTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveScalarTypeExtension(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterUnionTypeDefinition(ref int) { - p.enter() - name := p.operation.UnionTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterUnionTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveUnionTypeDefinition(ref int) { - p.leave() - name := p.operation.UnionTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveUnionTypeDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterUnionTypeExtension(ref int) { - p.enter() - name := p.operation.UnionTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterUnionTypeExtension(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveUnionTypeExtension(ref int) { - p.leave() - name := p.operation.UnionTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveUnionTypeExtension(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterUnionMemberType(ref int) { - p.enter() - name := p.operation.TypeNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterUnionMemberType(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveUnionMemberType(ref int) { - p.leave() - name := p.operation.TypeNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveUnionMemberType(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) EnterEnumTypeDefinition(ref int) { - p.enter() - name := p.operation.EnumTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterEnumTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveEnumTypeDefinition(ref int) { - p.leave() - name := p.operation.EnumTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveEnumTypeDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterEnumTypeExtension(ref int) { - p.enter() - name := p.operation.EnumTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterEnumTypeExtension(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveEnumTypeExtension(ref int) { - p.leave() - name := p.operation.EnumTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveEnumTypeExtension(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterEnumValueDefinition(ref int) { - p.enter() - name := p.operation.EnumValueDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterEnumValueDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveEnumValueDefinition(ref int) { - p.leave() - name := p.operation.EnumValueDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveEnumValueDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) EnterInputObjectTypeDefinition(ref int) { - p.enter() - name := p.operation.InputObjectTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterInputObjectTypeDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveInputObjectTypeDefinition(ref int) { - p.leave() - name := p.operation.InputObjectTypeDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveInputObjectTypeDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterInputObjectTypeExtension(ref int) { - p.enter() - name := p.operation.InputObjectTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterInputObjectTypeExtension(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveInputObjectTypeExtension(ref int) { - p.leave() - name := p.operation.InputObjectTypeExtensionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveInputObjectTypeExtension(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterDocument(operation, definition *ast.Document) { - p.operation, p.definition = operation, definition -} - -func (p *printingVisitor) LeaveDocument(operation, definition *ast.Document) { - -} - -func (p *printingVisitor) EnterDirective(ref int) { - p.enter() - name := p.operation.DirectiveNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterDirective(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveDirective(ref int) { - p.leave() - name := p.operation.DirectiveNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveDirective(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) EnterVariableDefinition(ref int) { - p.enter() - varName := string(p.operation.VariableValueNameBytes(p.operation.VariableDefinitions[ref].VariableValue.Ref)) - p.must(fmt.Fprintf(p.out, "EnterVariableDefinition(%s): ref: %d\n", varName, ref)) -} - -func (p *printingVisitor) LeaveVariableDefinition(ref int) { - p.leave() - varName := string(p.operation.VariableValueNameBytes(p.operation.VariableDefinitions[ref].VariableValue.Ref)) - p.must(fmt.Fprintf(p.out, "LeaveVariableDefinition(%s): ref: %d\n", varName, ref)) -} - -func (p *printingVisitor) EnterOperationDefinition(ref int) { - p.enter() - name := p.operation.Input.ByteSliceString(p.operation.OperationDefinitions[ref].Name) - if name == "" { - name = "anonymous!" - } - p.must(fmt.Fprintf(p.out, "EnterOperationDefinition (%s): ref: %d\n", name, ref)) - -} - -func (p *printingVisitor) LeaveOperationDefinition(ref int) { - p.leave() - name := p.operation.Input.ByteSliceString(p.operation.OperationDefinitions[ref].Name) - if name == "" { - name = "anonymous!" - } - p.must(fmt.Fprintf(p.out, "LeaveOperationDefinition(%s): ref: %d\n\n", name, ref)) -} - -func (p *printingVisitor) EnterSelectionSet(ref int) { - p.enter() - parentTypeName := p.definition.NodeNameUnsafeString(p.EnclosingTypeDefinition) - p.must(fmt.Fprintf(p.out, "EnterSelectionSet(%s): ref: %d\n", parentTypeName, ref)) -} - -func (p *printingVisitor) LeaveSelectionSet(ref int) { - p.leave() - parentTypeName := p.definition.NodeNameUnsafeString(p.EnclosingTypeDefinition) - p.must(fmt.Fprintf(p.out, "LeaveSelectionSet(%s): ref: %d\n", parentTypeName, ref)) -} - -func (p *printingVisitor) EnterField(ref int) { - p.enter() - fieldName := p.operation.FieldNameBytes(ref) - parentTypeName := p.definition.NodeNameUnsafeString(p.EnclosingTypeDefinition) - p.must(fmt.Fprintf(p.out, "EnterField(%s::%s): ref: %d\n", fieldName, parentTypeName, ref)) -} - -func (p *printingVisitor) LeaveField(ref int) { - p.leave() - fieldName := p.operation.FieldNameUnsafeString(ref) - parentTypeName := p.definition.NodeNameUnsafeString(p.EnclosingTypeDefinition) - p.must(fmt.Fprintf(p.out, "LeaveField(%s::%s): ref: %d\n", fieldName, parentTypeName, ref)) -} - -func (p *printingVisitor) EnterArgument(ref int) { - p.enter() - argName := p.operation.ArgumentNameString(ref) - parentTypeName := p.definition.NodeNameUnsafeString(p.EnclosingTypeDefinition) - p.must(fmt.Fprintf(p.out, "EnterArgument(%s::%s): ref: %d\n", argName, parentTypeName, ref)) -} - -func (p *printingVisitor) LeaveArgument(ref int) { - p.leave() - argName := p.operation.ArgumentNameString(ref) - parentTypeName := p.definition.NodeNameUnsafeString(p.EnclosingTypeDefinition) - p.must(fmt.Fprintf(p.out, "LeaveArgument(%s::%s): ref: %d\n", argName, parentTypeName, ref)) -} - -func (p *printingVisitor) EnterFragmentSpread(ref int) { - p.enter() - spreadName := p.operation.FragmentSpreadNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterFragmentSpread(%s): ref: %d\n", spreadName, ref)) -} - -func (p *printingVisitor) LeaveFragmentSpread(ref int) { - p.leave() - spreadName := p.operation.FragmentSpreadNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveFragmentSpread(%s): ref: %d\n", spreadName, ref)) -} - -func (p *printingVisitor) EnterInlineFragment(ref int) { - p.enter() - typeConditionName := p.operation.InlineFragmentTypeConditionNameString(ref) - if typeConditionName == "" { - typeConditionName = "anonymous!" - } - p.must(fmt.Fprintf(p.out, "EnterInlineFragment(%s): ref: %d\n", typeConditionName, ref)) -} - -func (p *printingVisitor) LeaveInlineFragment(ref int) { - p.leave() - typeConditionName := p.operation.InlineFragmentTypeConditionNameString(ref) - if typeConditionName == "" { - typeConditionName = "anonymous!" - } - p.must(fmt.Fprintf(p.out, "LeaveInlineFragment(%s): ref: %d\n", typeConditionName, ref)) -} - -func (p *printingVisitor) EnterFragmentDefinition(ref int) { - p.enter() - name := p.operation.FragmentDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "EnterFragmentDefinition(%s): ref: %d\n", name, ref)) -} - -func (p *printingVisitor) LeaveFragmentDefinition(ref int) { - p.leave() - name := p.operation.FragmentDefinitionNameString(ref) - p.must(fmt.Fprintf(p.out, "LeaveFragmentDefinition(%s): ref: %d\n\n", name, ref)) -} - -const testDefinitions = ` -directive @awesome on SCALAR | SCHEMA -type Foo { - field: String -} -type FooBar { - field: String -} -extend type Foo { - field2: Boolean -} -interface Bar { - field: String -} -extend interface Bar { - field2: Boolean -} -enum Bat { - BAR -} -extend enum Bat { - BAL -} -union Fooniun = Foo -extend union Fooniun = FooBar -input Bart { - field: String -} -extend input Bart { - field2: Boolean -} -scalar JSON -extend scalar JSON @awesome -schema { - query: Query - mutation: Mutation -} -extend schema @awesome {} -extend schema { - subscription: Subscription -} -` - -const testOperation = ` -query PostsUserQuery { - posts { - id - description - user { - id - name - } - } -} -fragment FirstFragment on Post { - id -} -query ArgsQuery { - foo(bar: "barValue", baz: true){ - fooField - } -} -query VariableQuery($bar: String, $baz: Boolean) { - foo(bar: $bar, baz: $baz){ - fooField - } -} -query VariableQuery { - posts { - id @include(if: true) - } -} -` - -const testDefinition = ` -directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -schema { - query: Query -} -type Query { - posts: [Post] - foo(bar: String!, baz: Boolean!): Foo -} -type User { - id: ID - name: String - posts: [Post] -} -type Post { - id: ID - description: String - user: User -} -type Foo { - fooField: String -} -scalar ID -scalar String -` diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go deleted file mode 100644 index d11304a50..000000000 --- a/pkg/codegen/codegen.go +++ /dev/null @@ -1,596 +0,0 @@ -// Package codegen generates code to make using this library easier -// You can currently use the code generator to generate go structs and Unmarshal methods for Directives and Input Objects type definitions -// This helps you interact very easily with configuration supplied by Directives which you can easily unmarshal into go structs -package codegen - -import ( - "fmt" - "io" - "strings" - - "github.com/dave/jennifer/jen" - "github.com/iancoleman/strcase" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type CodeGen struct { - doc *ast.Document - file *jen.File - walker *astvisitor.Walker - report *operationreport.Report - config Config -} - -type Config struct { - PackageName string - DirectiveStructSuffix string -} - -func New(doc *ast.Document, config Config) *CodeGen { - return &CodeGen{ - doc: doc, - config: config, - } -} - -func (c *CodeGen) Generate(w io.Writer) (int, error) { - c.file = jen.NewFile(c.config.PackageName) - c.file.PackageComment("Code generated by graphql-go-tools gen, DO NOT EDIT.") - c.report = &operationreport.Report{} - walker := astvisitor.NewWalker(48) - c.walker = &walker - - c.walker.RegisterAllNodesVisitor(&genVisitor{ - doc: c.doc, - Walker: c.walker, - file: c.file, - config: c.config, - }) - - c.report.Reset() - c.walker.Walk(c.doc, c.doc, c.report) - - return fmt.Fprintf(w, "%#v", c.file) -} - -type genVisitor struct { - doc *ast.Document - *astvisitor.Walker - file *jen.File - config Config -} - -func (g *genVisitor) renderType(stmt *jen.Statement, ref int, nullable bool) { - graphqlType := g.doc.Types[ref] - switch graphqlType.TypeKind { - case ast.TypeKindNamed: - if nullable { - stmt.Id("*") - } - typeName := g.doc.TypeNameString(ref) - switch typeName { - case "Boolean": - stmt.Bool() - case "String": - stmt.String() - case "Int": - stmt.Int64() - case "Float": - stmt.Float32() - default: - stmt.Id(typeName) - } - case ast.TypeKindNonNull: - g.renderType(stmt, graphqlType.OfType, false) - case ast.TypeKindList: - if nullable { - stmt.Id("*") - } - g.renderType(stmt.Id("[]"), graphqlType.OfType, true) - } -} - -func (g *genVisitor) renderUnmarshal(structName, graphqlObjectName string, ref ast.Node) { - - shortHandle := strings.ToLower(structName[0:1]) - - switch ref.Kind { - case ast.NodeKindDirectiveDefinition: - g.file.Func().Params(jen.Id(strings.ToLower(structName)[0:1]).Id("*").Id(structName)). - Id("Unmarshal").Params( - jen.Id("doc").Id("*").Qual("github.com/wundergraph/graphql-go-tools/pkg/ast", "Document"), - jen.Id("ref").Int()). - BlockFunc(func(group *jen.Group) { - for _, i := range g.doc.DirectiveDefinitions[ref.Ref].ArgumentsDefinition.Refs { - if !g.doc.InputValueDefinitionHasDefaultValue(i) { - continue - } - defaultValueKind := g.doc.InputValueDefinitionDefaultValue(i).Kind - argumentName := g.doc.InputValueDefinitionNameString(i) - directiveName := graphqlObjectName - fieldName := strcase.ToCamel(argumentName) - g.renderDirectiveDefinitionDefaultValueAssignment(group, defaultValueKind, shortHandle, fieldName, directiveName, argumentName) - } - group.For( - jen.Id("_").Op(",").Id("ii").Op(":=").Range().Id("doc").Dot("Directives").Index(jen.Id("ref")).Dot("Arguments").Dot("Refs"), - ).BlockFunc(func(group *jen.Group) { - group.Id("name").Op(":=").Id("doc").Dot("ArgumentNameString").Call(jen.Id("ii")) - group.Switch(jen.Id("name")).BlockFunc(func(group *jen.Group) { - for _, i := range g.doc.DirectiveDefinitions[ref.Ref].ArgumentsDefinition.Refs { - g.renderInputValueDefinitionSwitchCase(group, structName, i, "ArgumentValue") - } - }) - }) - }) - case ast.NodeKindInputObjectTypeDefinition: - g.file.Func().Params(jen.Id(strings.ToLower(structName)[0:1]).Id("*").Id(structName)). - Id("Unmarshal").Params( - jen.Id("doc").Id("*").Qual("github.com/wundergraph/graphql-go-tools/pkg/ast", "Document"), - jen.Id("ref").Int()). - BlockFunc(func(group *jen.Group) { - for _, i := range g.doc.InputObjectTypeDefinitions[ref.Ref].InputFieldsDefinition.Refs { - if !g.doc.InputValueDefinitionHasDefaultValue(i) { - continue - } - defaultValueKind := g.doc.InputValueDefinitionDefaultValue(i).Kind - argumentName := g.doc.InputValueDefinitionNameString(i) - inputObjectTypeDefinitionName := graphqlObjectName - fieldName := strcase.ToCamel(argumentName) - g.renderInputObjectTypeDefinitionDefaultValueAssignment(group, defaultValueKind, shortHandle, fieldName, inputObjectTypeDefinitionName, argumentName) - } - group.For( - jen.Id("_").Op(",").Id("ii").Op(":=").Range().Id("doc").Dot("ObjectValues").Index(jen.Id("ref")).Dot("Refs"), - ).BlockFunc(func(group *jen.Group) { - group.Id("name").Op(":=").String().Call(jen.Id("doc").Dot("ObjectFieldNameBytes").Call(jen.Id("ii"))) - group.Switch(jen.Id("name")).BlockFunc(func(group *jen.Group) { - for _, i := range g.doc.InputObjectTypeDefinitions[ref.Ref].InputFieldsDefinition.Refs { - g.renderInputValueDefinitionSwitchCase(group, structName, i, "ObjectFieldValue") - } - }) - }) - }) - } -} - -func (g *genVisitor) renderDirectiveDefinitionDefaultValueAssignment(group *jen.Group, defaultValueKind ast.ValueKind, shortHandle, fieldName, directiveName, argumentName string) { - var valueResolverName string - switch defaultValueKind { - case ast.ValueKindString: - valueResolverName = "DirectiveDefinitionArgumentDefaultValueString" - case ast.ValueKindBoolean: - valueResolverName = "DirectiveDefinitionArgumentDefaultValueBool" - case ast.ValueKindFloat: - valueResolverName = "DirectiveDefinitionArgumentDefaultValueFloat32" - case ast.ValueKindInteger: - valueResolverName = "DirectiveDefinitionArgumentDefaultValueInt64" - default: - return - } - group.Id(shortHandle).Dot(fieldName).Op("=").Id("doc").Dot(valueResolverName).Call(jen.Lit(directiveName), jen.Lit(argumentName)) -} - -func (g *genVisitor) renderInputObjectTypeDefinitionDefaultValueAssignment(group *jen.Group, defaultValueKind ast.ValueKind, shortHandle, fieldName, inputObjectTypeDefinitionName, argumentName string) { - var valueResolverName string - switch defaultValueKind { - case ast.ValueKindString: - valueResolverName = "InputObjectTypeDefinitionInputValueDefinitionDefaultValueString" - case ast.ValueKindBoolean: - valueResolverName = "InputObjectTypeDefinitionInputValueDefinitionDefaultValueBool" - case ast.ValueKindFloat: - valueResolverName = "InputObjectTypeDefinitionInputValueDefinitionDefaultValueFloat32" - case ast.ValueKindInteger: - valueResolverName = "InputObjectTypeDefinitionInputValueDefinitionDefaultValueInt64" - default: - return - } - group.Id(shortHandle).Dot(fieldName).Op("=").Id("doc").Dot(valueResolverName).Call(jen.Lit(inputObjectTypeDefinitionName), jen.Lit(argumentName)) -} - -func (g *genVisitor) renderInputValueDefinitionSwitchCase(group *jen.Group, structName string, ref int, valueSourceName string) { - valueName := g.doc.InputValueDefinitionNameString(ref) - fieldName := strcase.ToCamel(g.doc.InputValueDefinitionNameString(ref)) - valueTypeRef := g.doc.InputValueDefinitionType(ref) - hasDefaultValue := g.doc.InputValueDefinitionHasDefaultValue(ref) - g.renderInputValueDefinitionType(group, valueName, fieldName, structName, hasDefaultValue, valueTypeRef, valueSourceName, ast.TypeKindUnknown) -} - -func (g *genVisitor) renderInputValueDefinitionType(group *jen.Group, valueName, fieldName, structName string, hasDefaultValue bool, ref int, valueSourceName string, parentTypeKind ast.TypeKind) { - typeKind := g.doc.Types[ref].TypeKind - switch typeKind { - case ast.TypeKindNamed: - typeName := g.doc.TypeNameString(ref) - valueAssignment := g.valueAssingmentStatement(typeName, valueSourceName, false) - if valueAssignment == nil { - return - } - if hasDefaultValue || parentTypeKind == ast.TypeKindNonNull { - group.Case(jen.Lit(valueName)).Block( - valueAssignment, - jen.Id(strings.ToLower(structName[0:1])).Dot(fieldName).Op("=").Id("val"), - ) - } else { - group.Case(jen.Lit(valueName)).Block( - valueAssignment, - jen.Id(strings.ToLower(structName[0:1])).Dot(fieldName).Op("=").Id("&").Id("val"), - ) - } - case ast.TypeKindNonNull: - g.renderInputValueDefinitionType(group, valueName, fieldName, structName, hasDefaultValue, g.doc.Types[ref].OfType, valueSourceName, typeKind) - case ast.TypeKindList: - listType := &jen.Statement{} - g.renderType(listType, ref, false) - listDefinition := jen.Id("list").Op(":=").Make(listType, jen.Id("0"), jen.Len(jen.Id("doc").Dot("ListValues").Index(jen.Id("doc").Dot(valueSourceName).Call(jen.Id("ii")).Dot("Ref")).Dot("Refs"))) - switch parentTypeKind { - case ast.TypeKindNonNull: - switch g.doc.Types[g.doc.Types[ref].OfType].TypeKind { - case ast.TypeKindNonNull: - // non null list of non null type - typeName := g.doc.TypeNameString(g.doc.Types[g.doc.Types[ref].OfType].OfType) - group.Case(jen.Lit(valueName)).Block( - listDefinition, - jen.For(jen.Id("_").Op(",").Id("ii").Op(":=").Range().Id("doc").Dot("ListValues").Index(jen.Id("doc").Dot(valueSourceName).Call(jen.Id("ii")).Dot("Ref")).Dot("Refs")).Block( - g.valueAssingmentStatement(typeName, valueSourceName, true), - jen.Id("list").Op("=").Append(jen.Id("list").Op(",").Id("val")), - ), - jen.Id(strings.ToLower(structName[0:1])).Dot(fieldName).Op("=").Id("list"), - ) - case ast.TypeKindNamed: - // non null list of nullable type - typeName := g.doc.TypeNameString(g.doc.Types[ref].OfType) - group.Case(jen.Lit(valueName)).Block( - listDefinition, - jen.For(jen.Id("_").Op(",").Id("ii").Op(":=").Range().Id("doc").Dot("ListValues").Index(jen.Id("doc").Dot(valueSourceName).Call(jen.Id("ii")).Dot("Ref")).Dot("Refs")).Block( - g.valueAssingmentStatement(typeName, valueSourceName, true), - jen.Id("list").Op("=").Append(jen.Id("list").Op(",").Id("&").Id("val")), - ), - jen.Id(strings.ToLower(structName[0:1])).Dot(fieldName).Op("=").Id("list"), - ) - } - default: - switch g.doc.Types[g.doc.Types[ref].OfType].TypeKind { - case ast.TypeKindNonNull: - // nullable list of non null type - typeName := g.doc.TypeNameString(g.doc.Types[g.doc.Types[ref].OfType].OfType) - group.Case(jen.Lit(valueName)).Block( - listDefinition, - jen.For(jen.Id("_").Op(",").Id("ii").Op(":=").Range().Id("doc").Dot("ListValues").Index(jen.Id("doc").Dot(valueSourceName).Call(jen.Id("ii")).Dot("Ref")).Dot("Refs")).Block( - g.valueAssingmentStatement(typeName, valueSourceName, true), - jen.Id("list").Op("=").Append(jen.Id("list").Op(",").Id("val")), - ), - jen.Id(strings.ToLower(structName[0:1])).Dot(fieldName).Op("=").Id("&").Id("list"), - ) - default: - // nullable list of nullable type - typeName := g.doc.TypeNameString(g.doc.Types[ref].OfType) - group.Case(jen.Lit(valueName)).Block( - listDefinition, - jen.For(jen.Id("_").Op(",").Id("ii").Op(":=").Range().Id("doc").Dot("ListValues").Index(jen.Id("doc").Dot(valueSourceName).Call(jen.Id("ii")).Dot("Ref")).Dot("Refs")).Block( - g.valueAssingmentStatement(typeName, valueSourceName, true), - jen.Id("list").Op("=").Append(jen.Id("list").Op(",").Id("&").Id("val")), - ), - jen.Id(strings.ToLower(structName[0:1])).Dot(fieldName).Op("=").Id("&").Id("list"), - ) - } - } - } -} - -func (g *genVisitor) valueAssingmentStatement(scalarName, valueSourceName string, insideList bool) *jen.Statement { - - var caller *jen.Statement - if insideList { - caller = jen.Id("doc").Dot("Value").Call(jen.Id("ii")).Dot("Ref") - } else { - caller = jen.Id("doc").Dot(valueSourceName).Call(jen.Id("ii")).Dot("Ref") - } - - switch scalarName { - case "String": - return jen.Id("val").Op(":=").Id("doc").Dot("StringValueContentString").Call(caller) - case "Boolean": - return jen.Id("val").Op(":=").Id("bool").Call(jen.Id("doc").Dot("BooleanValue").Call(caller)) - case "Float": - return jen.Id("val").Op(":=").Id("doc").Dot("FloatValueAsFloat32").Call(caller) - case "Int": - return jen.Id("val").Op(":=").Id("doc").Dot("IntValueAsInt").Call(caller) - default: - def := jen.Var().Id("val").Id(scalarName).Line().Id("val").Dot("Unmarshal").Call(jen.Id("doc"), caller) - return def - } -} - -func (g *genVisitor) EnterDocument(operation, definition *ast.Document) { - -} - -func (g *genVisitor) LeaveDocument(operation, definition *ast.Document) { - -} - -func (g *genVisitor) EnterObjectTypeDefinition(ref int) { - -} - -func (g *genVisitor) LeaveObjectTypeDefinition(ref int) { - -} - -func (g *genVisitor) EnterObjectTypeExtension(ref int) { - -} - -func (g *genVisitor) LeaveObjectTypeExtension(ref int) { - -} - -func (g *genVisitor) EnterFieldDefinition(ref int) { - -} - -func (g *genVisitor) LeaveFieldDefinition(ref int) { - -} - -func (g *genVisitor) EnterInputValueDefinition(ref int) { - -} - -func (g *genVisitor) LeaveInputValueDefinition(ref int) { - -} - -func (g *genVisitor) EnterInterfaceTypeDefinition(ref int) { - -} - -func (g *genVisitor) LeaveInterfaceTypeDefinition(ref int) { - -} - -func (g *genVisitor) EnterInterfaceTypeExtension(ref int) { - -} - -func (g *genVisitor) LeaveInterfaceTypeExtension(ref int) { - -} - -func (g *genVisitor) EnterScalarTypeDefinition(ref int) { - -} - -func (g *genVisitor) LeaveScalarTypeDefinition(ref int) { - -} - -func (g *genVisitor) EnterScalarTypeExtension(ref int) { - -} - -func (g *genVisitor) LeaveScalarTypeExtension(ref int) { - -} - -func (g *genVisitor) EnterUnionTypeDefinition(ref int) { - -} - -func (g *genVisitor) LeaveUnionTypeDefinition(ref int) { - -} - -func (g *genVisitor) EnterUnionTypeExtension(ref int) { - -} - -func (g *genVisitor) LeaveUnionTypeExtension(ref int) { - -} - -func (g *genVisitor) EnterUnionMemberType(ref int) { - -} - -func (g *genVisitor) LeaveUnionMemberType(ref int) { - -} - -func (g *genVisitor) EnterEnumTypeDefinition(ref int) { - -} - -func (g *genVisitor) LeaveEnumTypeDefinition(ref int) { - name := g.doc.EnumTypeDefinitionNameString(ref) - shortHandle := strings.ToLower(name)[0:1] - g.file.Type().Id(name).Int() - refs := g.doc.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs - - g.file.Func().Params(jen.Id(shortHandle).Id("*").Id(name)).Id("Unmarshal").Params(jen.Id("doc").Id("*").Qual("github.com/wundergraph/graphql-go-tools/pkg/ast", "Document"), jen.Id("ref").Int()).Block( - jen.Switch(jen.Id("doc").Dot("EnumValueNameString").Call(jen.Id("ref"))).BlockFunc(func(group *jen.Group) { - for _, i := range refs { - valueName := g.doc.EnumValueDefinitionNameString(i) - group.Case(jen.Lit(valueName)).Block( - jen.Id("*").Id(shortHandle).Op("=").Id(name + "_" + valueName), - ) - } - }), - ) - - if len(refs) == 0 { - return - } - g.file.Const().DefsFunc(func(group *jen.Group) { - group.Id("UNDEFINED_" + name).Id(name).Op("=").Id("iota") - for _, i := range refs { - valueName := g.doc.EnumValueDefinitionNameString(i) - group.Id(name + "_" + valueName) - } - }) -} - -func (g *genVisitor) EnterEnumTypeExtension(ref int) { - -} - -func (g *genVisitor) LeaveEnumTypeExtension(ref int) { - -} - -func (g *genVisitor) EnterEnumValueDefinition(ref int) { - -} - -func (g *genVisitor) LeaveEnumValueDefinition(ref int) { - -} - -func (g *genVisitor) EnterInputObjectTypeDefinition(ref int) { - inputObjectTypeDefinitionName := g.doc.InputObjectTypeDefinitionNameString(ref) - structName := g.doc.InputObjectTypeDefinitionNameString(ref) - g.file.Type().Id(structName).StructFunc(func(group *jen.Group) { - for _, i := range g.doc.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs { - name := strcase.ToCamel(g.doc.InputValueDefinitionNameString(i)) - stmt := group.Id(name) - hasDefaultValue := g.doc.InputValueDefinitionHasDefaultValue(i) - g.renderType(stmt, g.doc.InputValueDefinitionType(i), !hasDefaultValue) - } - }) - g.renderUnmarshal(structName, inputObjectTypeDefinitionName, ast.Node{Kind: ast.NodeKindInputObjectTypeDefinition, Ref: ref}) -} - -func (g *genVisitor) LeaveInputObjectTypeDefinition(ref int) { - -} - -func (g *genVisitor) EnterInputObjectTypeExtension(ref int) { - -} - -func (g *genVisitor) LeaveInputObjectTypeExtension(ref int) { - -} - -func (g *genVisitor) EnterDirectiveDefinition(ref int) { - directiveName := g.doc.DirectiveDefinitionNameString(ref) - structName := strcase.ToCamel(directiveName) + g.config.DirectiveStructSuffix - g.file.Type().Id(structName).StructFunc(func(group *jen.Group) { - for _, i := range g.doc.DirectiveDefinitions[ref].ArgumentsDefinition.Refs { - name := strcase.ToCamel(g.doc.InputValueDefinitionNameString(i)) - stmt := group.Id(name) - hasDefaultValue := g.doc.InputValueDefinitionHasDefaultValue(i) - g.renderType(stmt, g.doc.InputValueDefinitionType(i), !hasDefaultValue) - } - }) - g.renderUnmarshal(structName, directiveName, ast.Node{Kind: ast.NodeKindDirectiveDefinition, Ref: ref}) -} - -func (g *genVisitor) LeaveDirectiveDefinition(ref int) { - -} - -func (g *genVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) { - -} - -func (g *genVisitor) LeaveDirectiveLocation(location ast.DirectiveLocation) { - -} - -func (g *genVisitor) EnterSchemaDefinition(ref int) { - -} - -func (g *genVisitor) LeaveSchemaDefinition(ref int) { - -} - -func (g *genVisitor) EnterSchemaExtension(ref int) { - -} - -func (g *genVisitor) LeaveSchemaExtension(ref int) { - -} - -func (g *genVisitor) EnterRootOperationTypeDefinition(ref int) { - -} - -func (g *genVisitor) LeaveRootOperationTypeDefinition(ref int) { - -} - -func (g *genVisitor) EnterOperationDefinition(ref int) { - -} - -func (g *genVisitor) LeaveOperationDefinition(ref int) { - -} - -func (g *genVisitor) EnterSelectionSet(ref int) { - -} - -func (g *genVisitor) LeaveSelectionSet(ref int) { - -} - -func (g *genVisitor) EnterField(ref int) { - -} - -func (g *genVisitor) LeaveField(ref int) { - -} - -func (g *genVisitor) EnterArgument(ref int) { - -} - -func (g *genVisitor) LeaveArgument(ref int) { - -} - -func (g *genVisitor) EnterFragmentSpread(ref int) { - -} - -func (g *genVisitor) LeaveFragmentSpread(ref int) { - -} - -func (g *genVisitor) EnterInlineFragment(ref int) { - -} - -func (g *genVisitor) LeaveInlineFragment(ref int) { - -} - -func (g *genVisitor) EnterFragmentDefinition(ref int) { - -} - -func (g *genVisitor) LeaveFragmentDefinition(ref int) { - -} - -func (g *genVisitor) EnterVariableDefinition(ref int) { - -} - -func (g *genVisitor) LeaveVariableDefinition(ref int) { - -} - -func (g *genVisitor) EnterDirective(ref int) { - -} - -func (g *genVisitor) LeaveDirective(ref int) { - -} diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go deleted file mode 100644 index 694658749..000000000 --- a/pkg/codegen/codegen_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package codegen - -import ( - "bytes" - "os" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestCodeGen_GenerateDirectiveDefinitionStruct(t *testing.T) { - - doc := unsafeparser.ParseGraphqlDocumentString(` - directive @DataSource ( - nonNullString: String! - nullableString: String - nonNullInt: Int! - nullableInt: Int - nonNullBoolean: Boolean! - nullableBoolean: Boolean - nonNullFloat: Float! - nullableFloat: Float - nullableListOfNullableString: [String] - nonNullListOfNullableString: [String]! - nonNullListOfNonNullString: [String!]! - nullableListOfNullableHeader: [Header] - nonNullListOfNullableHeader: [Header]! - nonNullListOfNonNullParameter: [Parameter!]! - methods: Methods! - nullableStringWithDefault: String = "defaultValue" - nonNullStringWithDefault: String! = "defaultValue" - intWithDefault: Int = 123 - floatWithDefault: Float = 1.23 - booleanWithDefault: Boolean = true - stringWithDefaultOverride: String = "foo" - inputWithDefaultChildField: InputWithDefault! - ) on FIELD_DEFINITION - - input InputWithDefault { - nullableString: String - stringWithDefault: String = "defaultValue" - intWithDefault: Int = 123 - booleanWithDefault: Boolean = true - floatWithDefault: Float = 1.23 - } - - input Methods { - list: [HTTP_METHOD!]! - } - - input Header { - key: String! - value: String! - } - - input Parameter { - name: String! - sourceKind: PARAMETER_SOURCE! - sourceName: String! - variableName: String! - } - - enum HTTP_METHOD { - GET - POST - UPDATE - DELETE - } - - enum PARAMETER_SOURCE { - CONTEXT_VARIABLE - OBJECT_VARIABLE_ARGUMENT - FIELD_ARGUMENTS - } - `) - - config := Config{ - PackageName: "codegen", - DirectiveStructSuffix: "Config", - } - - gen := New(&doc, config) - out := bytes.Buffer{} - _, err := gen.Generate(&out) - if err != nil { - t.Fatal(err) - } - - data := out.Bytes() - - goldie.Assert(t, "DataSource", data) - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/DataSource.golden") - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, string(data), string(fixture)) - } -} diff --git a/pkg/codegen/fixtures/DataSource.golden b/pkg/codegen/fixtures/DataSource.golden deleted file mode 100644 index 3999e5d62..000000000 --- a/pkg/codegen/fixtures/DataSource.golden +++ /dev/null @@ -1,283 +0,0 @@ -// Code generated by graphql-go-tools gen, DO NOT EDIT. -package codegen - -import ast "github.com/wundergraph/graphql-go-tools/pkg/ast" - -type DataSourceConfig struct { - NonNullString string - NullableString *string - NonNullInt int64 - NullableInt *int64 - NonNullBoolean bool - NullableBoolean *bool - NonNullFloat float32 - NullableFloat *float32 - NullableListOfNullableString *[]*string - NonNullListOfNullableString []*string - NonNullListOfNonNullString []string - NullableListOfNullableHeader *[]*Header - NonNullListOfNullableHeader []*Header - NonNullListOfNonNullParameter []Parameter - Methods Methods - NullableStringWithDefault string - NonNullStringWithDefault string - IntWithDefault int64 - FloatWithDefault float32 - BooleanWithDefault bool - StringWithDefaultOverride string - InputWithDefaultChildField InputWithDefault -} - -func (d *DataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - d.NullableStringWithDefault = doc.DirectiveDefinitionArgumentDefaultValueString("DataSource", "nullableStringWithDefault") - d.NonNullStringWithDefault = doc.DirectiveDefinitionArgumentDefaultValueString("DataSource", "nonNullStringWithDefault") - d.IntWithDefault = doc.DirectiveDefinitionArgumentDefaultValueInt64("DataSource", "intWithDefault") - d.FloatWithDefault = doc.DirectiveDefinitionArgumentDefaultValueFloat32("DataSource", "floatWithDefault") - d.BooleanWithDefault = doc.DirectiveDefinitionArgumentDefaultValueBool("DataSource", "booleanWithDefault") - d.StringWithDefaultOverride = doc.DirectiveDefinitionArgumentDefaultValueString("DataSource", "stringWithDefaultOverride") - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "nonNullString": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NonNullString = val - case "nullableString": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NullableString = &val - case "nonNullInt": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - d.NonNullInt = val - case "nullableInt": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - d.NullableInt = &val - case "nonNullBoolean": - val := bool(doc.BooleanValue(doc.ArgumentValue(ii).Ref)) - d.NonNullBoolean = val - case "nullableBoolean": - val := bool(doc.BooleanValue(doc.ArgumentValue(ii).Ref)) - d.NullableBoolean = &val - case "nonNullFloat": - val := doc.FloatValueAsFloat32(doc.ArgumentValue(ii).Ref) - d.NonNullFloat = val - case "nullableFloat": - val := doc.FloatValueAsFloat32(doc.ArgumentValue(ii).Ref) - d.NullableFloat = &val - case "nullableListOfNullableString": - list := make([]*string, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - val := doc.StringValueContentString(doc.Value(ii).Ref) - list = append(list, &val) - } - d.NullableListOfNullableString = &list - case "nonNullListOfNullableString": - list := make([]*string, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - val := doc.StringValueContentString(doc.Value(ii).Ref) - list = append(list, &val) - } - d.NonNullListOfNullableString = list - case "nonNullListOfNonNullString": - list := make([]string, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - val := doc.StringValueContentString(doc.Value(ii).Ref) - list = append(list, val) - } - d.NonNullListOfNonNullString = list - case "nullableListOfNullableHeader": - list := make([]*Header, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Header - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - d.NullableListOfNullableHeader = &list - case "nonNullListOfNullableHeader": - list := make([]*Header, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Header - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - d.NonNullListOfNullableHeader = list - case "nonNullListOfNonNullParameter": - list := make([]Parameter, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Parameter - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, val) - } - d.NonNullListOfNonNullParameter = list - case "methods": - var val Methods - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - d.Methods = val - case "nullableStringWithDefault": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NullableStringWithDefault = val - case "nonNullStringWithDefault": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NonNullStringWithDefault = val - case "intWithDefault": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - d.IntWithDefault = val - case "floatWithDefault": - val := doc.FloatValueAsFloat32(doc.ArgumentValue(ii).Ref) - d.FloatWithDefault = val - case "booleanWithDefault": - val := bool(doc.BooleanValue(doc.ArgumentValue(ii).Ref)) - d.BooleanWithDefault = val - case "stringWithDefaultOverride": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.StringWithDefaultOverride = val - case "inputWithDefaultChildField": - var val InputWithDefault - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - d.InputWithDefaultChildField = val - } - } -} - -type InputWithDefault struct { - NullableString *string - StringWithDefault string - IntWithDefault int64 - BooleanWithDefault bool - FloatWithDefault float32 -} - -func (i *InputWithDefault) Unmarshal(doc *ast.Document, ref int) { - i.StringWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueString("InputWithDefault", "stringWithDefault") - i.IntWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueInt64("InputWithDefault", "intWithDefault") - i.BooleanWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueBool("InputWithDefault", "booleanWithDefault") - i.FloatWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueFloat32("InputWithDefault", "floatWithDefault") - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "nullableString": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - i.NullableString = &val - case "stringWithDefault": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - i.StringWithDefault = val - case "intWithDefault": - val := doc.IntValueAsInt(doc.ObjectFieldValue(ii).Ref) - i.IntWithDefault = val - case "booleanWithDefault": - val := bool(doc.BooleanValue(doc.ObjectFieldValue(ii).Ref)) - i.BooleanWithDefault = val - case "floatWithDefault": - val := doc.FloatValueAsFloat32(doc.ObjectFieldValue(ii).Ref) - i.FloatWithDefault = val - } - } -} - -type Methods struct { - List []HTTP_METHOD -} - -func (m *Methods) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "list": - list := make([]HTTP_METHOD, 0, len(doc.ListValues[doc.ObjectFieldValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ObjectFieldValue(ii).Ref].Refs { - var val HTTP_METHOD - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, val) - } - m.List = list - } - } -} - -type Header struct { - Key string - Value string -} - -func (h *Header) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "key": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - h.Key = val - case "value": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - h.Value = val - } - } -} - -type Parameter struct { - Name string - SourceKind PARAMETER_SOURCE - SourceName string - VariableName string -} - -func (p *Parameter) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "name": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.Name = val - case "sourceKind": - var val PARAMETER_SOURCE - val.Unmarshal(doc, doc.ObjectFieldValue(ii).Ref) - p.SourceKind = val - case "sourceName": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.SourceName = val - case "variableName": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.VariableName = val - } - } -} - -type HTTP_METHOD int - -func (h *HTTP_METHOD) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "GET": - *h = HTTP_METHOD_GET - case "POST": - *h = HTTP_METHOD_POST - case "UPDATE": - *h = HTTP_METHOD_UPDATE - case "DELETE": - *h = HTTP_METHOD_DELETE - } -} - -const ( - UNDEFINED_HTTP_METHOD HTTP_METHOD = iota - HTTP_METHOD_GET - HTTP_METHOD_POST - HTTP_METHOD_UPDATE - HTTP_METHOD_DELETE -) - -type PARAMETER_SOURCE int - -func (p *PARAMETER_SOURCE) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "CONTEXT_VARIABLE": - *p = PARAMETER_SOURCE_CONTEXT_VARIABLE - case "OBJECT_VARIABLE_ARGUMENT": - *p = PARAMETER_SOURCE_OBJECT_VARIABLE_ARGUMENT - case "FIELD_ARGUMENTS": - *p = PARAMETER_SOURCE_FIELD_ARGUMENTS - } -} - -const ( - UNDEFINED_PARAMETER_SOURCE PARAMETER_SOURCE = iota - PARAMETER_SOURCE_CONTEXT_VARIABLE - PARAMETER_SOURCE_OBJECT_VARIABLE_ARGUMENT - PARAMETER_SOURCE_FIELD_ARGUMENTS -) diff --git a/pkg/codegen/manual.go b/pkg/codegen/manual.go deleted file mode 100644 index 2d1610dfc..000000000 --- a/pkg/codegen/manual.go +++ /dev/null @@ -1,282 +0,0 @@ -package codegen - -import "github.com/wundergraph/graphql-go-tools/pkg/ast" - -type DataSourceConfig struct { - NonNullString string - NullableString *string - NonNullInt int64 - NullableInt *int64 - NonNullBoolean bool - NullableBoolean *bool - NonNullFloat float32 - NullableFloat *float32 - NullableListOfNullableString *[]*string - NonNullListOfNullableString []*string - NonNullListOfNonNullString []string - NullableListOfNullableHeader *[]*Header - NonNullListOfNullableHeader []*Header - NonNullListOfNonNullParameter []Parameter - Methods Methods - NullableStringWithDefault string - NonNullStringWithDefault string - IntWithDefault int64 - FloatWithDefault float32 - BooleanWithDefault bool - StringWithDefaultOverride string - InputWithDefaultChildField InputWithDefault -} - -func (d *DataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - d.NullableStringWithDefault = doc.DirectiveDefinitionArgumentDefaultValueString("DataSource", "nullableStringWithDefault") - d.NonNullStringWithDefault = doc.DirectiveDefinitionArgumentDefaultValueString("DataSource", "nonNullStringWithDefault") - d.IntWithDefault = doc.DirectiveDefinitionArgumentDefaultValueInt64("DataSource", "intWithDefault") - d.FloatWithDefault = doc.DirectiveDefinitionArgumentDefaultValueFloat32("DataSource", "floatWithDefault") - d.BooleanWithDefault = doc.DirectiveDefinitionArgumentDefaultValueBool("DataSource", "booleanWithDefault") - d.StringWithDefaultOverride = doc.DirectiveDefinitionArgumentDefaultValueString("DataSource", "stringWithDefaultOverride") - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "nonNullString": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NonNullString = val - case "nullableString": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NullableString = &val - case "nonNullInt": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - d.NonNullInt = val - case "nullableInt": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - d.NullableInt = &val - case "nonNullBoolean": - val := bool(doc.BooleanValue(doc.ArgumentValue(ii).Ref)) - d.NonNullBoolean = val - case "nullableBoolean": - val := bool(doc.BooleanValue(doc.ArgumentValue(ii).Ref)) - d.NullableBoolean = &val - case "nonNullFloat": - val := doc.FloatValueAsFloat32(doc.ArgumentValue(ii).Ref) - d.NonNullFloat = val - case "nullableFloat": - val := doc.FloatValueAsFloat32(doc.ArgumentValue(ii).Ref) - d.NullableFloat = &val - case "nullableListOfNullableString": - list := make([]*string, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - val := doc.StringValueContentString(doc.Value(ii).Ref) - list = append(list, &val) - } - d.NullableListOfNullableString = &list - case "nonNullListOfNullableString": - list := make([]*string, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - val := doc.StringValueContentString(doc.Value(ii).Ref) - list = append(list, &val) - } - d.NonNullListOfNullableString = list - case "nonNullListOfNonNullString": - list := make([]string, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - val := doc.StringValueContentString(doc.Value(ii).Ref) - list = append(list, val) - } - d.NonNullListOfNonNullString = list - case "nullableListOfNullableHeader": - list := make([]*Header, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Header - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - d.NullableListOfNullableHeader = &list - case "nonNullListOfNullableHeader": - list := make([]*Header, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Header - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - d.NonNullListOfNullableHeader = list - case "nonNullListOfNonNullParameter": - list := make([]Parameter, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Parameter - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, val) - } - d.NonNullListOfNonNullParameter = list - case "methods": - var val Methods - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - d.Methods = val - case "nullableStringWithDefault": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NullableStringWithDefault = val - case "nonNullStringWithDefault": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.NonNullStringWithDefault = val - case "intWithDefault": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - d.IntWithDefault = val - case "floatWithDefault": - val := doc.FloatValueAsFloat32(doc.ArgumentValue(ii).Ref) - d.FloatWithDefault = val - case "booleanWithDefault": - val := bool(doc.BooleanValue(doc.ArgumentValue(ii).Ref)) - d.BooleanWithDefault = val - case "stringWithDefaultOverride": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - d.StringWithDefaultOverride = val - case "inputWithDefaultChildField": - var val InputWithDefault - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - d.InputWithDefaultChildField = val - } - } -} - -type InputWithDefault struct { - NullableString *string - StringWithDefault string - IntWithDefault int64 - BooleanWithDefault bool - FloatWithDefault float32 -} - -func (i *InputWithDefault) Unmarshal(doc *ast.Document, ref int) { - i.StringWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueString("InputWithDefault", "stringWithDefault") - i.IntWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueInt64("InputWithDefault", "intWithDefault") - i.BooleanWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueBool("InputWithDefault", "booleanWithDefault") - i.FloatWithDefault = doc.InputObjectTypeDefinitionInputValueDefinitionDefaultValueFloat32("InputWithDefault", "floatWithDefault") - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "nullableString": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - i.NullableString = &val - case "stringWithDefault": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - i.StringWithDefault = val - case "intWithDefault": - val := doc.IntValueAsInt(doc.ObjectFieldValue(ii).Ref) - i.IntWithDefault = val - case "booleanWithDefault": - val := bool(doc.BooleanValue(doc.ObjectFieldValue(ii).Ref)) - i.BooleanWithDefault = val - case "floatWithDefault": - val := doc.FloatValueAsFloat32(doc.ObjectFieldValue(ii).Ref) - i.FloatWithDefault = val - } - } -} - -type Methods struct { - List []HTTP_METHOD -} - -func (m *Methods) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "list": - list := make([]HTTP_METHOD, 0, len(doc.ListValues[doc.ObjectFieldValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ObjectFieldValue(ii).Ref].Refs { - var val HTTP_METHOD - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, val) - } - m.List = list - } - } -} - -type Header struct { - Key string - Value string -} - -func (h *Header) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "key": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - h.Key = val - case "value": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - h.Value = val - } - } -} - -type Parameter struct { - Name string - SourceKind PARAMETER_SOURCE - SourceName string - VariableName string -} - -func (p *Parameter) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "name": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.Name = val - case "sourceKind": - var val PARAMETER_SOURCE - val.Unmarshal(doc, doc.ObjectFieldValue(ii).Ref) - p.SourceKind = val - case "sourceName": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.SourceName = val - case "variableName": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.VariableName = val - } - } -} - -type HTTP_METHOD int - -func (h *HTTP_METHOD) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "GET": - *h = HTTP_METHOD_GET - case "POST": - *h = HTTP_METHOD_POST - case "UPDATE": - *h = HTTP_METHOD_UPDATE - case "DELETE": - *h = HTTP_METHOD_DELETE - } -} - -const ( - UNDEFINED_HTTP_METHOD HTTP_METHOD = iota - HTTP_METHOD_GET - HTTP_METHOD_POST - HTTP_METHOD_UPDATE - HTTP_METHOD_DELETE -) - -type PARAMETER_SOURCE int - -func (p *PARAMETER_SOURCE) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "CONTEXT_VARIABLE": - *p = PARAMETER_SOURCE_CONTEXT_VARIABLE - case "OBJECT_VARIABLE_ARGUMENT": - *p = PARAMETER_SOURCE_OBJECT_VARIABLE_ARGUMENT - case "FIELD_ARGUMENTS": - *p = PARAMETER_SOURCE_FIELD_ARGUMENTS - } -} - -const ( - UNDEFINED_PARAMETER_SOURCE PARAMETER_SOURCE = iota - PARAMETER_SOURCE_CONTEXT_VARIABLE - PARAMETER_SOURCE_OBJECT_VARIABLE_ARGUMENT - PARAMETER_SOURCE_FIELD_ARGUMENTS -) diff --git a/pkg/codegen/manual_test.go b/pkg/codegen/manual_test.go deleted file mode 100644 index 679f6ec74..000000000 --- a/pkg/codegen/manual_test.go +++ /dev/null @@ -1,240 +0,0 @@ -package codegen - -import ( - "testing" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func TestManual(t *testing.T) { - schema := ` -directive @DataSource ( - nonNullString: String! - nullableString: String - nonNullInt: Int! - nullableInt: Int - nonNullBoolean: Boolean! - nullableBoolean: Boolean - nonNullFloat: Float! - nullableFloat: Float - nullableListOfNullableString: [String] - nonNullListOfNullableString: [String]! - nonNullListOfNonNullString: [String!]! - nullableListOfNullableHeader: [Header] - nonNullListOfNullableHeader: [Header]! - nonNullListOfNonNullParameter: [Parameter!]! - methods: Methods! - nullableStringWithDefault: String = "defaultValue" - nonNullStringWithDefault: String! = "defaultValue" - intWithDefault: Int = 123 - floatWithDefault: Float = 1.23 - booleanWithDefault: Boolean = true - stringWithDefaultOverride: String = "foo" - inputWithDefaultChildField: InputWithDefault! - ) on FIELD_DEFINITION - - input InputWithDefault { - nullableString: String - stringWithDefault: String = "defaultValue" - intWithDefault: Int = 123 - booleanWithDefault: Boolean = true - floatWithDefault: Float = 1.23 - } - - input Methods { - list: [HTTP_METHOD!]! - } - - input Header { - key: String! - value: String! - } - - input Parameter { - name: String! - sourceKind: PARAMETER_SOURCE! - sourceName: String! - variableName: String! - } - - enum HTTP_METHOD { - GET - POST - UPDATE - DELETE - } - - enum PARAMETER_SOURCE { - CONTEXT_VARIABLE - OBJECT_VARIABLE_ARGUMENT - FIELD_ARGUMENTS - } - type Query { - rootField: String - @DataSource ( - nonNullString: "nonNullString" - nonNullInt: 2 - nullableInt: 1 - nonNullBoolean: true - nullableBoolean: true - nonNullFloat: 13.37 - nullableFloat: 13.37 - nullableListOfNullableString: ["foo","bar","baz"] - nonNullListOfNullableString: ["foo","bar","baz"] - nonNullListOfNonNullString: ["foo","bar","baz"] - nullableListOfNullableHeader: [ - { - key: "foo" - value: "bar" - }, - { - key: "baz" - value: "bal" - }, - ] - nonNullListOfNullableHeader: [] - nonNullListOfNonNullParameter: [ - { - name: "foo" - sourceKind: CONTEXT_VARIABLE - sourceName: "bar" - variableName: "baz" - } - ] - methods: { - list: [GET,POST] - } - stringWithDefaultOverride: "bar" - inputWithDefaultChildField: { - nullableString: "foo" - } - ) - } - ` - - doc := unsafeparser.ParseGraphqlDocumentString(schema) - - var d DataSourceConfig - d.Unmarshal(&doc, doc.FieldDefinitionDirectives(0)[0]) - - if d.NonNullString != "nonNullString" { - t.Fatalf("field: NonNullString want: nonNullString, got: %s\n", d.NonNullString) - } - if d.NullableString != nil { - t.Fatalf("field: NullableString want: nil\n") - } - if d.NonNullInt != 2 { - t.Fatalf("field: NonNullInt want: 2, got: %d\n", d.NonNullInt) - } - if *d.NullableInt != 1 { - t.Fatalf("field: NullableInt want: 1, got: %d\n", *d.NullableInt) - } - if d.NonNullBoolean != true { - t.Fatalf("field: NonNullBoolean want: true, got: %t\n", d.NonNullBoolean) - } - if *d.NullableBoolean != true { - t.Fatalf("field: NullableBoolean want: true, got: %t\n", *d.NullableBoolean) - } - if d.NonNullFloat != 13.37 { - t.Fatalf("field: NonNullFloat want: 13.37, got: %v\n", d.NonNullFloat) - } - if *d.NullableFloat != 13.37 { - t.Fatalf("field: NullableFloat want: 13.37, got: %v\n", *d.NullableFloat) - } - if *(*d.NullableListOfNullableString)[0] != "foo" { - t.Fatal("want foo") - } - if *(*d.NullableListOfNullableString)[1] != "bar" { - t.Fatal("want bar") - } - if *(*d.NullableListOfNullableString)[2] != "baz" { - t.Fatal("want baz") - } - if *d.NonNullListOfNullableString[0] != "foo" { - t.Fatal("want foo") - } - if *d.NonNullListOfNullableString[1] != "bar" { - t.Fatal("want bar") - } - if *d.NonNullListOfNullableString[2] != "baz" { - t.Fatal("want baz") - } - if d.NonNullListOfNonNullString[0] != "foo" { - t.Fatal("want foo") - } - if d.NonNullListOfNonNullString[1] != "bar" { - t.Fatal("want bar") - } - if d.NonNullListOfNonNullString[2] != "baz" { - t.Fatal("want baz") - } - if (*d.NullableListOfNullableHeader)[0].Key != "foo" { - t.Fatal("want foo") - } - if (*d.NullableListOfNullableHeader)[0].Value != "bar" { - t.Fatal("want bar") - } - if (*d.NullableListOfNullableHeader)[1].Key != "baz" { - t.Fatal("want baz") - } - if (*d.NullableListOfNullableHeader)[1].Value != "bal" { - t.Fatal("want bal") - } - if len(d.NonNullListOfNullableHeader) != 0 { - t.Fatal("want empty array") - } - if d.NonNullListOfNullableHeader == nil { - t.Fatal("want != nil") - } - if d.NonNullListOfNonNullParameter[0].Name != "foo" { - t.Fatal("want foo") - } - if d.NonNullListOfNonNullParameter[0].SourceKind != PARAMETER_SOURCE_CONTEXT_VARIABLE { - t.Fatal("want CONTEXT_VARIABLE") - } - if d.NonNullListOfNonNullParameter[0].SourceName != "bar" { - t.Fatal("want bar") - } - if d.NonNullListOfNonNullParameter[0].VariableName != "baz" { - t.Fatal("want baz") - } - if d.Methods.List[0] != HTTP_METHOD_GET { - t.Fatal("want HTTP_METHOD_GET") - } - if d.Methods.List[1] != HTTP_METHOD_POST { - t.Fatal("want HTTP_METHOD_POST") - } - if d.NonNullStringWithDefault != "defaultValue" { - t.Fatalf("want defaultValue, got: %s", d.NonNullStringWithDefault) - } - if d.NullableStringWithDefault != "defaultValue" { - t.Fatal("want defaultValue") - } - if d.IntWithDefault != 123 { - t.Fatalf("want 123, got: %d", d.IntWithDefault) - } - if d.FloatWithDefault != 1.23 { - t.Fatal("want 1.23") - } - if d.BooleanWithDefault != true { - t.Fatal("want true") - } - if d.StringWithDefaultOverride != "bar" { - t.Fatalf("want bar, got: %s", d.StringWithDefaultOverride) - } - if *d.InputWithDefaultChildField.NullableString != "foo" { - t.Fatal("want foo") - } - if d.InputWithDefaultChildField.StringWithDefault != "defaultValue" { - t.Fatal("want defaultValue") - } - if d.InputWithDefaultChildField.IntWithDefault != 123 { - t.Fatal("want 123") - } - if d.InputWithDefaultChildField.BooleanWithDefault != true { - t.Fatal("want true") - } - if d.InputWithDefaultChildField.FloatWithDefault != 1.23 { - t.Fatal("want 1.23") - } -} diff --git a/pkg/codegen/testdata/schema.graphql b/pkg/codegen/testdata/schema.graphql deleted file mode 100644 index 941c2ff2f..000000000 --- a/pkg/codegen/testdata/schema.graphql +++ /dev/null @@ -1,46 +0,0 @@ -directive @DataSource ( - nonNullString: String! - nullableString: String - nonNullInt: Int! - nullableInt: Int - nonNullBoolean: Boolean! - nullableBoolean: Boolean - nonNullFloat: Float! - nullableFloat: Float - nullableListOfNullableString: [String] - nonNullListOfNullableString: [String]! - nonNullListOfNonNullString: [String!]! - nullableListOfNullableHeader: [Header] - nonNullListOfNullableHeader: [Header]! - nonNullListOfNonNullParameter: [Parameter!]! - methods: Methods! -) on FIELD_DEFINITION - -input Methods { - list: [HTTP_METHOD!]! -} - -input Header { - key: String! - value: String! -} - -input Parameter { - name: String! - sourceKind: PARAMETER_SOURCE! - sourceName: String! - variableName: String! -} - -enum HTTP_METHOD { - GET - POST - UPDATE - DELETE -} - -enum PARAMETER_SOURCE { - CONTEXT_VARIABLE - OBJECT_VARIABLE_ARGUMENT - FIELD_ARGUMENTS -} \ No newline at end of file diff --git a/pkg/engine/datasource/graphql_datasource/batch.go b/pkg/engine/datasource/graphql_datasource/batch.go deleted file mode 100644 index b039b030c..000000000 --- a/pkg/engine/datasource/graphql_datasource/batch.go +++ /dev/null @@ -1,205 +0,0 @@ -package graphql_datasource - -import ( - "bytes" - "fmt" - - "github.com/buger/jsonparser" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/pool" -) - -var representationPath = []string{"body", "variables", "representations"} - -type Batch struct { - resultedInput *fastbuffer.FastBuffer - responseMappings []inputResponseBufferMappings - batchSize int -} - -// inputResponseBufferMappings defines the relationship between input containing an _entities Query -// and the output buffers, the response needs to be mapped to -type inputResponseBufferMappings struct { - // responseIndex is the array position of the response - responseIndex int - // originalInput is the original input of a response to allow comparing and deduplication - originalInput []byte - // assignedBufferIndices are the buffers to which the response needs to be assigned - assignedBufferIndices []int - - skip bool -} - -func NewBatchFactory() *BatchFactory { - return &BatchFactory{} -} - -type BatchFactory struct{} - -func (b *BatchFactory) CreateBatch(inputs [][]byte) (resolve.DataSourceBatch, error) { - if len(inputs) == 0 { - return nil, nil - } - - resultedInput := pool.FastBuffer.Get() - - responseMappings, batchSize, err := b.multiplexBatch(resultedInput, inputs) - if err != nil { - return nil, nil - } - - return &Batch{ - resultedInput: resultedInput, - responseMappings: responseMappings, - batchSize: batchSize, - }, nil -} - -func (b *Batch) Input() *fastbuffer.FastBuffer { - return b.resultedInput -} - -func (b *Batch) Demultiplex(responseBufPair *resolve.BufPair, bufPairs []*resolve.BufPair) (err error) { - defer pool.FastBuffer.Put(b.resultedInput) - - if b.batchSize != len(bufPairs) { - return fmt.Errorf("expected %d buf pairs", b.batchSize) - } - - if err = b.demultiplexBatch(responseBufPair, b.responseMappings, bufPairs); err != nil { - return err - } - - return -} - -func (b *BatchFactory) multiplexBatch(out *fastbuffer.FastBuffer, inputs [][]byte) (responseMappings []inputResponseBufferMappings, batchSize int, err error) { - var responseIdxMap = make(map[string]int, len(inputs)) - - if len(inputs) == 0 { - return nil, 0, nil - } - - variablesBuf := pool.FastBuffer.Get() - defer pool.FastBuffer.Put(variablesBuf) - - variablesBuf.WriteBytes(literal.LBRACK) - - var ( - variablesIdx int - skippedInputs int - firstRepresentationsStart int - firstRepresentationsEnd int - ) - - for i := range inputs { - if bytes.Equal(inputs[i], literal.NULL) { - responseMappings = append(responseMappings, inputResponseBufferMappings{ - responseIndex: i, - originalInput: inputs[i], - assignedBufferIndices: []int{i}, - skip: true, - }) - - if _, exists := responseIdxMap[string(inputs[i])]; !exists { - responseIdxMap[string(inputs[i])] = variablesIdx - } - - variablesIdx++ - skippedInputs++ - continue - } - inputVariables, _, representationsOffset, err := jsonparser.Get(inputs[i], representationPath...) - if err != nil { - return nil, 0, err - } - - if i == 0 { - firstRepresentationsStart = representationsOffset - len(inputVariables) - firstRepresentationsEnd = representationsOffset - } - - _, err = jsonparser.ArrayEach(inputVariables, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - responseIndex, exists := responseIdxMap[string(value)] - if exists { - responseMappings[responseIndex].assignedBufferIndices = append(responseMappings[responseIndex].assignedBufferIndices, i) - return - } - - if variablesBuf.Len() != 1 { - variablesBuf.WriteBytes(literal.COMMA) - } - variablesBuf.WriteBytes(value) - - responseMappings = append(responseMappings, inputResponseBufferMappings{ - responseIndex: variablesIdx, - originalInput: value, - assignedBufferIndices: []int{i}, - }) - - if _, exists := responseIdxMap[string(value)]; !exists { - responseIdxMap[string(value)] = variablesIdx - } - - variablesIdx++ - }) - if err != nil { - return nil, 0, err - } - } - - variablesBuf.WriteBytes(literal.RBRACK) - - representationJson := variablesBuf.Bytes() - representationJsonCopy := make([]byte, len(representationJson)) - copy(representationJsonCopy, representationJson) - - header := inputs[0][0:firstRepresentationsStart] - trailer := inputs[0][firstRepresentationsEnd:] - - out.WriteBytes(header) - out.WriteBytes(representationJsonCopy) - out.WriteBytes(trailer) - - return responseMappings, len(inputs), nil -} - -func (b *Batch) demultiplexBatch(responsePair *resolve.BufPair, responseMappings []inputResponseBufferMappings, resultBufPairs []*resolve.BufPair) (err error) { - var outPosition int - - if responsePair.HasData() { - _, err = jsonparser.ArrayEach(responsePair.Data.Bytes(), func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - if outPosition > len(responseMappings)+1 { - return - } - - mapping := responseMappings[outPosition] - for mapping.skip { - resultBufPairs[outPosition].Data.WriteBytes(literal.NULL) - outPosition++ - mapping = responseMappings[outPosition] - } - - for _, index := range mapping.assignedBufferIndices { - if resultBufPairs[index].Data.Len() != 0 { - resultBufPairs[index].Data.WriteBytes(literal.COMMA) - } - resultBufPairs[index].Data.WriteBytes(value) - } - - outPosition++ - }) - if err != nil { - return err - } - } - - if responsePair.HasErrors() { - resultBufPairs[0].Errors.WriteBytes(responsePair.Errors.Bytes()) - } - - return -} diff --git a/pkg/engine/datasource/graphql_datasource/batch_test.go b/pkg/engine/datasource/graphql_datasource/batch_test.go deleted file mode 100644 index abb0bdb6e..000000000 --- a/pkg/engine/datasource/graphql_datasource/batch_test.go +++ /dev/null @@ -1,288 +0,0 @@ -package graphql_datasource - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" -) - -func newBufPair(data string, err string) *resolve.BufPair { - bufPair := resolve.NewBufPair() - bufPair.Data.WriteString(data) - - if err != "" { - bufPair.Errors.WriteString(err) - } - - return bufPair -} - -func runTestBatch(t *testing.T, inputs []string, expectedInput string, mappings []inputResponseBufferMappings, batchSize int) { - expectedFastBuf := fastbuffer.New() - expectedFastBuf.WriteBytes([]byte(expectedInput)) - - expectedBatch := &Batch{ - resultedInput: expectedFastBuf, - batchSize: batchSize, - responseMappings: mappings, - } - - convertedInputs := make([][]byte, len(inputs)) - for i := range inputs { - convertedInputs[i] = []byte(inputs[i]) - } - - batchFactory := NewBatchFactory() - batch, err := batchFactory.CreateBatch(convertedInputs) - require.NoError(t, err) - assert.Equal(t, expectedBatch, batch) -} - -func runTestDemultiplex(t *testing.T, inputs []string, responseBufPair *resolve.BufPair, expectedBufPairs []*resolve.BufPair) { - convertedInputs := make([][]byte, len(inputs)) - for i := range inputs { - convertedInputs[i] = []byte(inputs[i]) - } - - batchFactory := NewBatchFactory() - batch, err := batchFactory.CreateBatch(convertedInputs) - require.NoError(t, err) - - gotBufPairs := make([]*resolve.BufPair, len(inputs)) - for i := range inputs { - gotBufPairs[i] = resolve.NewBufPair() - } - - require.NoError(t, batch.Demultiplex(responseBufPair, gotBufPairs)) - - assert.Equal(t, expectedBufPairs, gotBufPairs) -} - -func TestBatch(t *testing.T) { - t.Run("create batch with unique args", func(t *testing.T) { - runTestBatch( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - }, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - []inputResponseBufferMappings{ - { - responseIndex: 0, - originalInput: []byte(`{"upc":"top-1","__typename":"Product"}`), - assignedBufferIndices: []int{0}, - }, - { - responseIndex: 1, - originalInput: []byte(`{"upc":"top-2","__typename":"Product"}`), - assignedBufferIndices: []int{1}, - }, - }, - 2, - ) - }) - t.Run("deduplicate the same args", func(t *testing.T) { - runTestBatch( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - }, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - []inputResponseBufferMappings{ - { - responseIndex: 0, - originalInput: []byte(`{"upc":"top-2","__typename":"Product"}`), - assignedBufferIndices: []int{0, 1}, - }, - }, - 2, - ) - }) - t.Run("handle null variables", func(t *testing.T) { - runTestBatch( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - "null", - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-4","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-5","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-6","__typename":"Product"}]}}}`, - }, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"},{"upc":"top-4","__typename":"Product"},{"upc":"top-5","__typename":"Product"},{"upc":"top-6","__typename":"Product"}]}}}`, - []inputResponseBufferMappings{ - { - responseIndex: 0, - originalInput: []byte(`{"upc":"top-1","__typename":"Product"}`), - assignedBufferIndices: []int{0}, - }, - { - responseIndex: 1, - originalInput: []byte(`{"upc":"top-2","__typename":"Product"}`), - assignedBufferIndices: []int{1}, - }, - { - responseIndex: 2, - originalInput: []byte(`null`), - assignedBufferIndices: []int{2}, - skip: true, - }, - { - responseIndex: 3, - originalInput: []byte(`{"upc":"top-4","__typename":"Product"}`), - assignedBufferIndices: []int{3}, - }, - { - responseIndex: 4, - originalInput: []byte(`{"upc":"top-5","__typename":"Product"}`), - assignedBufferIndices: []int{4}, - }, - { - responseIndex: 5, - originalInput: []byte(`{"upc":"top-6","__typename":"Product"}`), - assignedBufferIndices: []int{5}, - }, - }, - 6, - ) - }) - t.Run("deduplicate the same args with overlaps", func(t *testing.T) { - runTestBatch( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"},{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"},{"upc":"top-3","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-3","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-3","__typename":"Product"},{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-3","__typename":"Product"}]}}}`, - }, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"},{"upc":"top-1","__typename":"Product"},{"upc":"top-3","__typename":"Product"}]}}}`, - []inputResponseBufferMappings{ - { - responseIndex: 0, - originalInput: []byte(`{"upc":"top-2","__typename":"Product"}`), - assignedBufferIndices: []int{0, 1, 2, 3, 5}, - }, - { - responseIndex: 1, - originalInput: []byte(`{"upc":"top-1","__typename":"Product"}`), - assignedBufferIndices: []int{0, 3, 4, 6}, - }, - { - responseIndex: 2, - originalInput: []byte(`{"upc":"top-3","__typename":"Product"}`), - assignedBufferIndices: []int{1, 2, 4, 7}, - }, - }, - 8, - ) - }) - t.Run("create batch with complex inputs", func(t *testing.T) { - runTestBatch( - t, - []string{ // Entity has multi key: category + name - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"category":"category-1", "name":"Top 1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"category":"category-2", "name":"Top 1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"category":"category-1", "name":"Top 1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"category":"category-2", "name":"Top 2","__typename":"Product"}]}}}`, - }, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"category":"category-1", "name":"Top 1","__typename":"Product"},{"category":"category-2", "name":"Top 1","__typename":"Product"},{"category":"category-2", "name":"Top 2","__typename":"Product"}]}}}`, - []inputResponseBufferMappings{ - { - responseIndex: 0, - originalInput: []byte(`{"category":"category-1", "name":"Top 1","__typename":"Product"}`), - assignedBufferIndices: []int{0, 2}, - }, - { - responseIndex: 1, - originalInput: []byte(`{"category":"category-2", "name":"Top 1","__typename":"Product"}`), - assignedBufferIndices: []int{1}, - }, - { - responseIndex: 2, - originalInput: []byte(`{"category":"category-2", "name":"Top 2","__typename":"Product"}`), - assignedBufferIndices: []int{3}, - }, - }, - 4, - ) - }) -} - -func TestBatch_Demultiplex(t *testing.T) { - t.Run("demultiplex uniq inputs", func(t *testing.T) { - runTestDemultiplex( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - }, - newBufPair(`[{"name":"Name 1", "price": 1.01, "__typename":"Product"},{"name":"Name 2", "price": 2.01, "__typename":"Product"}]`, ""), - []*resolve.BufPair{ - newBufPair(`{"name":"Name 1", "price": 1.01, "__typename":"Product"}`, ""), - newBufPair(`{"name":"Name 2", "price": 2.01, "__typename":"Product"}`, ""), - }, - ) - }) - t.Run("demultiplex deduplicated inputs", func(t *testing.T) { - runTestDemultiplex( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - }, - newBufPair(`[{"name":"Name 1", "price": 1.01, "__typename":"Product"},{"name":"Name 2", "price": 2.01, "__typename":"Product"}]`, ""), - []*resolve.BufPair{ - newBufPair(`{"name":"Name 1", "price": 1.01, "__typename":"Product"}`, ""), - newBufPair(`{"name":"Name 2", "price": 2.01, "__typename":"Product"}`, ""), - newBufPair(`{"name":"Name 1", "price": 1.01, "__typename":"Product"}`, ""), - }, - ) - }) - t.Run("demultiplex null inputs", func(t *testing.T) { - runTestDemultiplex( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - "null", - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-4","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-5","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-6","__typename":"Product"}]}}}`, - }, - newBufPair(`[{"name":"Name 1","price":1,"__typename":"Product"},{"name":"Name 2","price":2,"__typename":"Product"},{"name":"Name 4","price":4,"__typename":"Product"},{"name":"Name 5","price":5,"__typename":"Product"},{"name":"Name 6","price":6,"__typename":"Product"}]`, ""), - []*resolve.BufPair{ - newBufPair(`{"name":"Name 1","price":1,"__typename":"Product"}`, ""), - newBufPair(`{"name":"Name 2","price":2,"__typename":"Product"}`, ""), - newBufPair(`null`, ""), - newBufPair(`{"name":"Name 4","price":4,"__typename":"Product"}`, ""), - newBufPair(`{"name":"Name 5","price":5,"__typename":"Product"}`, ""), - newBufPair(`{"name":"Name 6","price":6,"__typename":"Product"}`, ""), - }, - ) - }) - t.Run("demultiplex response with error", func(t *testing.T) { - runTestDemultiplex( - t, - []string{ - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`, - `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name price}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`, - }, - newBufPair(`[null,{"name":"Name 2", "price": 2.01, "__typename":"Product"}]`, `{"message":"errorMessage"}`), - []*resolve.BufPair{ - newBufPair("null", `{"message":"errorMessage"}`), - newBufPair(`{"name":"Name 2", "price": 2.01, "__typename":"Product"}`, ""), - }, - ) - }) -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_datasource.go b/pkg/engine/datasource/graphql_datasource/graphql_datasource.go deleted file mode 100644 index 8900bbf47..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_datasource.go +++ /dev/null @@ -1,1456 +0,0 @@ -package graphql_datasource - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - - "github.com/buger/jsonparser" - "github.com/tidwall/sjson" - "golang.org/x/exp/slices" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/federation" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const removeNullVariablesDirectiveName = "removeNullVariables" - -type Planner struct { - visitor *plan.Visitor - dataSourceConfig plan.DataSourceConfiguration - config Configuration - upstreamOperation *ast.Document - upstreamVariables []byte - representationsJson []byte - nodes []ast.Node - variables resolve.Variables - lastFieldEnclosingTypeName string - disallowSingleFlight bool - hasFederationRoot bool - // federationDepth is the depth in the response tree where the federation root is located. - // this field allows us to dismiss all federated fields that belong to a different subgraph easily - federationDepth int - extractEntities bool - fetchClient *http.Client - subscriptionClient GraphQLSubscriptionClient - isNested bool // isNested - flags that datasource is nested e.g. field with datasource is not on a query type - rootTypeName string // rootTypeName - holds name of top level type - rootFieldName string // rootFieldName - holds name of root type field - rootFieldRef int // rootFieldRef - holds ref of root type field - argTypeRef int // argTypeRef - holds current argument type ref from the definition - batchFactory resolve.DataSourceBatchFactory - upstreamDefinition *ast.Document - currentVariableDefinition int - addDirectivesToVariableDefinitions map[int][]int - - insideCustomScalarField bool - customScalarFieldRef int - unnulVariables bool - - parentTypeNodes []ast.Node -} - -func (p *Planner) parentNodeIsAbstract() bool { - if len(p.parentTypeNodes) < 2 { - return false - } - parentTypeNode := p.parentTypeNodes[len(p.parentTypeNodes)-2] - return parentTypeNode.Kind.IsAbstractType() -} - -func (p *Planner) EnterVariableDefinition(ref int) { - p.currentVariableDefinition = ref -} - -func (p *Planner) LeaveVariableDefinition(_ int) { - p.currentVariableDefinition = -1 -} - -func (p *Planner) EnterDirective(ref int) { - parent := p.nodes[len(p.nodes)-1] - if parent.Kind == ast.NodeKindOperationDefinition && p.currentVariableDefinition != -1 { - p.addDirectivesToVariableDefinitions[p.currentVariableDefinition] = append(p.addDirectivesToVariableDefinitions[p.currentVariableDefinition], ref) - return - } - p.addDirectiveToNode(ref, parent) -} - -func (p *Planner) addDirectiveToNode(directiveRef int, node ast.Node) { - directiveName := p.visitor.Operation.DirectiveNameString(directiveRef) - operationType := ast.OperationTypeQuery - if !p.isNested { - operationType = p.visitor.Operation.OperationDefinitions[p.visitor.Walker.Ancestors[0].Ref].OperationType - } - if !p.visitor.Definition.DirectiveIsAllowedOnNodeKind(directiveName, node.Kind, operationType) { - return - } - upstreamDirectiveName := p.dataSourceConfig.Directives.RenameTypeNameOnMatchStr(directiveName) - if p.upstreamDefinition != nil && !p.upstreamDefinition.DirectiveIsAllowedOnNodeKind(upstreamDirectiveName, node.Kind, operationType) { - return - } - upstreamDirective := p.visitor.Importer.ImportDirectiveWithRename(directiveRef, upstreamDirectiveName, p.visitor.Operation, p.upstreamOperation) - p.upstreamOperation.AddDirectiveToNode(upstreamDirective, node) - - // The directive is allowed on the node, so we know it exists. - directive := p.visitor.Operation.Directives[directiveRef] - - var variables []ast.Value - - // Collect all the variable arguments. - if directive.HasArguments { - for _, argument := range directive.Arguments.Refs { - value := p.visitor.Operation.ArgumentValue(argument) - // TODO: also handle literal values that CONTAIN variables - if value.Kind == ast.ValueKindVariable { - variables = append(variables, value) - } - } - } - - // Process each variable, adding it to the upstream operation and - // variables, if it hasn't already been added. Note: instead of looking - // up the type of the corresponding argument on the directive definition, - // this code assumes the type of the variable as defined in the operation - // is correct and uses the same (possibly mapped) type for the upstream - // operation. - for _, value := range variables { - variableName := p.visitor.Operation.VariableValueNameBytes(value.Ref) - - for _, i := range p.visitor.Operation.OperationDefinitions[p.visitor.Walker.Ancestors[0].Ref].VariableDefinitions.Refs { - // Find the variable declaration in the downstream operation. - ref := p.visitor.Operation.VariableDefinitions[i].VariableValue.Ref - if !p.visitor.Operation.VariableValueNameBytes(ref).Equals(variableName) { - continue - } - - // Look up the variable type. - variableType := p.visitor.Operation.VariableDefinitions[i].Type - typeName := p.visitor.Operation.ResolveTypeNameString(variableType) - - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(p.visitor.Operation, p.visitor.Definition, variableType) - if err != nil { - continue - } - - contextVariable := &resolve.ContextVariable{ - Path: []string{string(variableName)}, - Renderer: renderer, - } - - // Try to add the variable to the set of upstream variables. - contextVariableName, exists := p.variables.AddVariable(contextVariable) - - // If the variable already exists, it also already exists in the - // upstream operation; there's nothing to add! - if exists { - continue - } - - // Add the variable to the upstream operation. Be sure to map the - // downstream type to the upstream type, if needed. - upstreamVariable := p.upstreamOperation.ImportVariableValue(variableName) - upstreamTypeName := p.visitor.Config.Types.RenameTypeNameOnMatchStr(typeName) - importedType := p.visitor.Importer.ImportTypeWithRename(p.visitor.Operation.VariableDefinitions[i].Type, p.visitor.Operation, p.upstreamOperation, upstreamTypeName) - p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, upstreamVariable, importedType) - - // Also copy any variable directives in the downstream operation to - // the upstream operation. - if add, ok := p.addDirectivesToVariableDefinitions[i]; ok { - for _, directive := range add { - p.addDirectiveToNode(directive, ast.Node{Kind: ast.NodeKindVariableDefinition, Ref: i}) - } - } - - // And finally add the variable to the upstream variables JSON. - p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, string(variableName), []byte(contextVariableName)) - } - } -} - -func (p *Planner) DownstreamResponseFieldAlias(downstreamFieldRef int) (alias string, exists bool) { - // If there's no alias but the downstream Query re-uses the same path on different root fields, - // we rewrite the downstream Query using an alias so that we can have an aliased Query to the upstream - // while keeping a non aliased Query to the downstream but with a path rewrite on an existing root field. - - fieldName := p.visitor.Operation.FieldNameUnsafeString(downstreamFieldRef) - - if p.visitor.Operation.FieldAliasIsDefined(downstreamFieldRef) { - return "", false - } - - typeName := p.visitor.Walker.EnclosingTypeDefinition.NameString(p.visitor.Definition) - for i := range p.visitor.Config.Fields { - if p.visitor.Config.Fields[i].TypeName == typeName && - p.visitor.Config.Fields[i].FieldName == fieldName && - len(p.visitor.Config.Fields[i].Path) == 1 { - - if p.visitor.Config.Fields[i].Path[0] != fieldName { - aliasBytes := p.visitor.Operation.FieldNameBytes(downstreamFieldRef) - return string(aliasBytes), true - } - break - } - } - return "", false -} - -func (p *Planner) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior { - return plan.DataSourcePlanningBehavior{ - MergeAliasedRootNodes: true, - OverrideFieldPathFromAlias: true, - IncludeTypeNameFields: true, - } -} - -type Configuration struct { - Fetch FetchConfiguration - Subscription SubscriptionConfiguration - Federation FederationConfiguration - UpstreamSchema string - CustomScalarTypeFields []SingleTypeField -} - -type SingleTypeField struct { - TypeName string - FieldName string -} - -func ConfigJson(config Configuration) json.RawMessage { - out, _ := json.Marshal(config) - return out -} - -type FederationConfiguration struct { - Enabled bool - ServiceSDL string -} - -type SubscriptionConfiguration struct { - URL string - UseSSE bool - SSEMethodPost bool -} - -type FetchConfiguration struct { - URL string - Method string - Header http.Header -} - -func (c *Configuration) ApplyDefaults() { - if c.Fetch.Method == "" { - c.Fetch.Method = "POST" - } -} - -func (p *Planner) Register(visitor *plan.Visitor, configuration plan.DataSourceConfiguration, isNested bool) error { - p.visitor = visitor - p.visitor.Walker.RegisterDocumentVisitor(p) - p.visitor.Walker.RegisterFieldVisitor(p) - p.visitor.Walker.RegisterOperationDefinitionVisitor(p) - p.visitor.Walker.RegisterSelectionSetVisitor(p) - p.visitor.Walker.RegisterEnterArgumentVisitor(p) - p.visitor.Walker.RegisterInlineFragmentVisitor(p) - p.visitor.Walker.RegisterEnterDirectiveVisitor(p) - p.visitor.Walker.RegisterVariableDefinitionVisitor(p) - - p.dataSourceConfig = configuration - err := json.Unmarshal(configuration.Custom, &p.config) - if err != nil { - return err - } - - p.config.ApplyDefaults() - p.isNested = isNested - - return nil -} - -func (p *Planner) ConfigureFetch() plan.FetchConfiguration { - var input []byte - input = httpclient.SetInputBodyWithPath(input, p.upstreamVariables, "variables") - input = httpclient.SetInputBodyWithPath(input, p.printOperation(), "query") - - if p.unnulVariables { - input = httpclient.SetInputFlag(input, httpclient.UNNULLVARIABLES) - } - - header, err := json.Marshal(p.config.Fetch.Header) - if err == nil && len(header) != 0 && !bytes.Equal(header, literal.NULL) { - input = httpclient.SetInputHeader(input, header) - } - - input = httpclient.SetInputURL(input, []byte(p.config.Fetch.URL)) - input = httpclient.SetInputMethod(input, []byte(p.config.Fetch.Method)) - - var batchConfig plan.BatchConfig - // Allow batch query for fetching entities. - if p.extractEntities && p.batchFactory != nil { - batchConfig = plan.BatchConfig{ - AllowBatch: p.extractEntities, // Allow batch query for fetching entities. - BatchFactory: p.batchFactory, - } - } - - return plan.FetchConfiguration{ - Input: string(input), - DataSource: &Source{ - httpClient: p.fetchClient, - }, - Variables: p.variables, - DisallowSingleFlight: p.disallowSingleFlight, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: p.extractEntities, - }, - BatchConfig: batchConfig, - SetTemplateOutputToNullOnVariableNull: batchConfig.AllowBatch, - } -} - -func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration { - input := httpclient.SetInputBodyWithPath(nil, p.upstreamVariables, "variables") - input = httpclient.SetInputBodyWithPath(input, p.printOperation(), "query") - input = httpclient.SetInputURL(input, []byte(p.config.Subscription.URL)) - if p.config.Subscription.UseSSE { - input = httpclient.SetInputFlag(input, httpclient.USESSE) - if p.config.Subscription.SSEMethodPost { - input = httpclient.SetInputFlag(input, httpclient.SSEMETHODPOST) - } - } - - header, err := json.Marshal(p.config.Fetch.Header) - if err == nil && len(header) != 0 && !bytes.Equal(header, literal.NULL) { - input = httpclient.SetInputHeader(input, header) - } - - return plan.SubscriptionConfiguration{ - Input: string(input), - DataSource: &SubscriptionSource{ - client: p.subscriptionClient, - }, - Variables: p.variables, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: false, - }, - } -} - -func (p *Planner) EnterOperationDefinition(ref int) { - if p.visitor.Operation.OperationDefinitions[ref].HasDirectives && - p.visitor.Operation.OperationDefinitions[ref].Directives.HasDirectiveByName(p.visitor.Operation, removeNullVariablesDirectiveName) { - p.unnulVariables = true - p.visitor.Operation.OperationDefinitions[ref].Directives.RemoveDirectiveByName(p.visitor.Operation, removeNullVariablesDirectiveName) - } - - operationType := p.visitor.Operation.OperationDefinitions[ref].OperationType - if p.isNested { - operationType = ast.OperationTypeQuery - } - definition := p.upstreamOperation.AddOperationDefinitionToRootNodes(ast.OperationDefinition{ - OperationType: operationType, - }) - p.disallowSingleFlight = operationType == ast.OperationTypeMutation - p.nodes = append(p.nodes, definition) -} - -func (p *Planner) LeaveOperationDefinition(_ int) { - p.nodes = p.nodes[:len(p.nodes)-1] -} - -func (p *Planner) EnterSelectionSet(ref int) { - p.parentTypeNodes = append(p.parentTypeNodes, p.visitor.Walker.EnclosingTypeDefinition) - if p.insideCustomScalarField { - return - } - - parent := p.nodes[len(p.nodes)-1] - set := p.upstreamOperation.AddSelectionSet() - switch parent.Kind { - case ast.NodeKindSelectionSet: - // this happens when we're inside the root of a nested abstract federated query - // we want to walk into and out of the selection set because the root field is abstract - // this allows us to walk out of the inline fragment in the root - // however, as a nested operation always starts with an Operation Definition and a Selection Set - // we don't want to add the selection set to the root nodes - return - case ast.NodeKindOperationDefinition: - p.upstreamOperation.OperationDefinitions[parent.Ref].HasSelections = true - p.upstreamOperation.OperationDefinitions[parent.Ref].SelectionSet = set.Ref - case ast.NodeKindField: - p.upstreamOperation.Fields[parent.Ref].HasSelections = true - p.upstreamOperation.Fields[parent.Ref].SelectionSet = set.Ref - case ast.NodeKindInlineFragment: - p.upstreamOperation.InlineFragments[parent.Ref].HasSelections = true - p.upstreamOperation.InlineFragments[parent.Ref].SelectionSet = set.Ref - } - p.nodes = append(p.nodes, set) - if p.visitor.Walker.EnclosingTypeDefinition.Kind.IsAbstractType() { - // Adding the typename to abstract (unions and interfaces) types is handled elsewhere - return - } - - for _, selectionRef := range p.visitor.Operation.SelectionSets[ref].SelectionRefs { - if p.visitor.Operation.Selections[selectionRef].Kind == ast.SelectionKindField { - if p.visitor.Operation.FieldNameUnsafeString(p.visitor.Operation.Selections[selectionRef].Ref) == "__typename" { - p.addTypenameToSelectionSet(set.Ref) - } - } - } -} - -func (p *Planner) addTypenameToSelectionSet(selectionSet int) { - field := p.upstreamOperation.AddField(ast.Field{ - Name: p.upstreamOperation.Input.AppendInputString("__typename"), - }) - p.upstreamOperation.AddSelection(selectionSet, ast.Selection{ - Ref: field.Ref, - Kind: ast.SelectionKindField, - }) -} - -func (p *Planner) LeaveSelectionSet(_ int) { - p.parentTypeNodes = p.parentTypeNodes[:len(p.parentTypeNodes)-1] - if p.insideCustomScalarField { - return - } - - lastIndex := len(p.nodes) - 1 - if p.nodes[lastIndex].Kind == ast.NodeKindSelectionSet { - p.nodes = p.nodes[:lastIndex] - } -} - -func (p *Planner) EnterInlineFragment(ref int) { - if p.insideCustomScalarField { - return - } - - if p.config.Federation.Enabled && !p.hasFederationRoot && p.isNestedRequest() { - // if we're inside the nested root of a federated abstract query, - // we're walking into the inline fragment as the root - // however, as we're already handling the inline fragment when we walk into the root field, - // we can skip this one - return - } - - typeCondition := p.visitor.Operation.InlineFragmentTypeConditionName(ref) - if typeCondition == nil && !p.visitor.Operation.InlineFragments[ref].HasDirectives { - return - } - - fragmentType := -1 - if typeCondition != nil { - fragmentType = p.upstreamOperation.AddNamedType(p.visitor.Config.Types.RenameTypeNameOnMatchBytes(typeCondition)) - } - - inlineFragment := p.upstreamOperation.AddInlineFragment(ast.InlineFragment{ - TypeCondition: ast.TypeCondition{ - Type: fragmentType, - }, - }) - - selection := ast.Selection{ - Kind: ast.SelectionKindInlineFragment, - Ref: inlineFragment, - } - - if typeCondition != nil { - // add __typename field to selection set which contains typeCondition - // so that the resolver can distinguish between the response types - p.addTypenameToSelectionSet(p.nodes[len(p.nodes)-1].Ref) - } - - p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, selection) - p.nodes = append(p.nodes, ast.Node{Kind: ast.NodeKindInlineFragment, Ref: inlineFragment}) -} - -func (p *Planner) LeaveInlineFragment(_ int) { - if p.insideCustomScalarField { - return - } - - lastIndex := len(p.nodes) - 1 - if p.nodes[lastIndex].Kind == ast.NodeKindInlineFragment { - p.nodes = p.nodes[:lastIndex] - } -} - -func (p *Planner) EnterField(ref int) { - if p.insideCustomScalarField { - return - } - - fieldName := p.visitor.Operation.FieldNameString(ref) - p.lastFieldEnclosingTypeName = p.visitor.Walker.EnclosingTypeDefinition.NameString(p.visitor.Definition) - fieldConfiguration := p.visitor.Config.Fields.ForTypeField(p.lastFieldEnclosingTypeName, fieldName) - - for i := range p.config.CustomScalarTypeFields { - if p.config.CustomScalarTypeFields[i].TypeName == p.lastFieldEnclosingTypeName && p.config.CustomScalarTypeFields[i].FieldName == fieldName { - p.insideCustomScalarField = true - p.customScalarFieldRef = ref - p.addFieldArguments(p.addCustomField(ref), ref, fieldConfiguration) - return - } - } - - // store root field name and ref - if p.rootFieldName == "" { - p.rootFieldName = fieldName - p.rootFieldRef = ref - } - // store root type name - if p.rootTypeName == "" { - p.rootTypeName = p.lastFieldEnclosingTypeName - } - - if fieldConfiguration == nil { - p.addField(ref) - return - } - - // Note: federated fields always have a field configuration because at - // least the federation key for the type the field lives on is required - // (and required fields are specified in the configuration). - p.handleFederation(fieldConfiguration) - p.addField(ref) - - upstreamFieldRef := p.nodes[len(p.nodes)-1].Ref - - p.addFieldArguments(upstreamFieldRef, ref, fieldConfiguration) -} - -func (p *Planner) addFieldArguments(upstreamFieldRef int, fieldRef int, fieldConfiguration *plan.FieldConfiguration) { - if fieldConfiguration != nil { - for i := range fieldConfiguration.Arguments { - argumentConfiguration := fieldConfiguration.Arguments[i] - p.configureArgument(upstreamFieldRef, fieldRef, *fieldConfiguration, argumentConfiguration) - } - } -} - -func (p *Planner) addCustomField(ref int) (upstreamFieldRef int) { - fieldName, alias := p.handleFieldAlias(ref) - fieldNode := p.upstreamOperation.AddField(ast.Field{ - Name: p.upstreamOperation.Input.AppendInputString(fieldName), - Alias: alias, - }) - selection := ast.Selection{ - Kind: ast.SelectionKindField, - Ref: fieldNode.Ref, - } - p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, selection) - return fieldNode.Ref -} - -func (p *Planner) LeaveField(ref int) { - if p.insideCustomScalarField { - if p.customScalarFieldRef == ref { - p.insideCustomScalarField = false - p.customScalarFieldRef = 0 - } - return - } - - p.nodes = p.nodes[:len(p.nodes)-1] -} - -func (p *Planner) EnterArgument(_ int) { - if p.insideCustomScalarField { - return - } -} - -func (p *Planner) EnterDocument(_, _ *ast.Document) { - if p.upstreamOperation == nil { - p.upstreamOperation = ast.NewDocument() - } else { - p.upstreamOperation.Reset() - } - p.nodes = p.nodes[:0] - p.parentTypeNodes = p.parentTypeNodes[:0] - p.upstreamVariables = nil - p.variables = p.variables[:0] - p.representationsJson = p.representationsJson[:0] - p.disallowSingleFlight = false - p.hasFederationRoot = false - p.extractEntities = false - - // reset information about root type - p.rootTypeName = "" - p.rootFieldName = "" - p.rootFieldRef = -1 - - // reset info about arg type - p.argTypeRef = -1 - - p.addDirectivesToVariableDefinitions = map[int][]int{} - - p.upstreamDefinition = nil - if p.config.UpstreamSchema != "" { - p.upstreamDefinition = ast.NewDocument() - p.upstreamDefinition.Input.ResetInputString(p.config.UpstreamSchema) - parser := astparser.NewParser() - var report operationreport.Report - parser.Parse(p.upstreamDefinition, &report) - if report.HasErrors() { - p.visitor.Walker.StopWithInternalErr(report) - return - } - err := asttransform.MergeDefinitionWithBaseSchema(p.upstreamDefinition) - if err != nil { - p.visitor.Walker.StopWithInternalErr(err) - return - } - } -} - -func (p *Planner) LeaveDocument(_, _ *ast.Document) { -} - -func (p *Planner) handleFederation(fieldConfig *plan.FieldConfiguration) { - if !p.config.Federation.Enabled { // federation must be enabled - return - } - // If there's no federation root and this isn't a nested request, this - // isn't a federated field and there's nothing to do. - if !p.hasFederationRoot && !p.isNestedRequest() { - return - } - // If a federated root is already present, the representations variable has - // already been added. Update it to include information for the additional - // field. NOTE: only the first federated field has isNestedRequest set to - // true. Subsequent fields use hasFederationRoot to determine federation - // status. - if p.hasFederationRoot { - // Ideally the "representations" variable could be set once in - // LeaveDocument, but ConfigureFetch is called before this visitor's - // LeaveDocument is called. (Updating the visitor logic to call - // LeaveDocument in reverse registration order would fix this issue.) - p.updateRepresentationsVariable(fieldConfig) - return - } - p.hasFederationRoot = true - p.federationDepth = p.visitor.Walker.Depth - // query($representations: [_Any!]!){_entities(representations: $representations){... on Product - p.addRepresentationsVariableDefinition() // $representations: [_Any!]! - p.addEntitiesSelectionSet() // {_entities(representations: $representations) - p.addOnTypeInlineFragment() // ... on Product - p.updateRepresentationsVariable(fieldConfig) // "variables\":{\"representations\":[{\"upc\":\"$$0$$\",\"__typename\":\"Product\"}]}} -} - -func (p *Planner) updateRepresentationsVariable(fieldConfig *plan.FieldConfiguration) { - if p.visitor.Walker.Depth != p.federationDepth { - // given that this field has a different depth than the federation root, we skip this field - // this is because we only have to handle federated fields that are part of the "current" federated request - // we're calling this func with the current field because it's both another federated subfield, - // but the current subgraph is also capable of resolving it - // in this case, we don't need to add the required fields to the variables because the context differs - return - } - - // "variables\":{\"representations\":[{\"upc\":\$$0$$\,\"__typename\":\"Product\"}]}} - parser := astparser.NewParser() - doc := ast.NewDocument() - doc.Input.ResetInputString(p.config.Federation.ServiceSDL) - report := &operationreport.Report{} - parser.Parse(doc, report) - if report.HasErrors() { - p.visitor.Walker.StopWithInternalErr(fmt.Errorf("GraphQL Planner: failed parsing Federation SDL")) - return - } - - // RequiresFields includes `@requires` fields as well as federation keys - // for the type containing the field currently being visited. - fields := fieldConfig.RequiresFields - if len(fields) == 0 { - return - } - - if len(p.representationsJson) == 0 { - // If the parent is an abstract type, i.e., an interface or union, - // the representation typename must come from a parent fetch response. - if p.parentNodeIsAbstract() { - objectVariable := &resolve.ObjectVariable{ - Path: []string{"__typename"}, - } - objectVariable.Renderer = resolve.NewJSONVariableRendererWithValidation(`{"type":"string"}`) - if variable, exists := p.variables.AddVariable(objectVariable); !exists { - p.representationsJson, _ = sjson.SetRawBytes(p.representationsJson, "__typename", []byte(variable)) - } - } else { // otherwise use the concrete typename - onTypeName := p.visitor.Config.Types.RenameTypeNameOnMatchStr(p.lastFieldEnclosingTypeName) - p.representationsJson, _ = sjson.SetRawBytes(nil, "__typename", []byte("\""+onTypeName+"\"")) - } - } - - for i := range fields { - objectVariable := &resolve.ObjectVariable{ - Path: []string{fields[i]}, - } - fieldDef := p.fieldDefinition(fields[i], p.lastFieldEnclosingTypeName) - if fieldDef == nil { - continue - } - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(p.visitor.Definition, p.visitor.Definition, fieldDef.Type) - if err != nil { - continue - } - objectVariable.Renderer = renderer - variable, exists := p.variables.AddVariable(objectVariable) - if exists { - continue - } - p.representationsJson, _ = sjson.SetRawBytes(p.representationsJson, fields[i], []byte(variable)) - } - representationsJson := append([]byte("["), append(p.representationsJson, []byte("]")...)...) - p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, "representations", representationsJson) - p.extractEntities = true -} - -func (p *Planner) fieldDefinition(fieldName, typeName string) *ast.FieldDefinition { - node, ok := p.visitor.Definition.Index.FirstNodeByNameStr(typeName) - if !ok { - return nil - } - definition, ok := p.visitor.Definition.NodeFieldDefinitionByName(node, []byte(fieldName)) - if !ok { - return nil - } - return &p.visitor.Definition.FieldDefinitions[definition] -} - -func (p *Planner) addOnTypeInlineFragment() { - selectionSet := p.upstreamOperation.AddSelectionSet() - p.addTypenameToSelectionSet(p.nodes[len(p.nodes)-1].Ref) - onTypeName := p.visitor.Config.Types.RenameTypeNameOnMatchBytes([]byte(p.lastFieldEnclosingTypeName)) - typeRef := p.upstreamOperation.AddNamedType(onTypeName) - inlineFragment := p.upstreamOperation.AddInlineFragment(ast.InlineFragment{ - HasSelections: true, - SelectionSet: selectionSet.Ref, - TypeCondition: ast.TypeCondition{ - Type: typeRef, - }, - }) - p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, ast.Selection{ - Kind: ast.SelectionKindInlineFragment, - Ref: inlineFragment, - }) - p.nodes = append(p.nodes, selectionSet) -} - -func (p *Planner) addEntitiesSelectionSet() { - // $representations - representationsLiteral := p.upstreamOperation.Input.AppendInputString("representations") - representationsVariable := p.upstreamOperation.AddVariableValue(ast.VariableValue{ - Name: representationsLiteral, - }) - representationsArgument := p.upstreamOperation.AddArgument(ast.Argument{ - Name: representationsLiteral, - Value: ast.Value{ - Kind: ast.ValueKindVariable, - Ref: representationsVariable, - }, - }) - - // _entities - entitiesSelectionSet := p.upstreamOperation.AddSelectionSet() - entitiesField := p.upstreamOperation.AddField(ast.Field{ - Name: p.upstreamOperation.Input.AppendInputString("_entities"), - HasSelections: true, - HasArguments: true, - Arguments: ast.ArgumentList{ - Refs: []int{representationsArgument}, - }, - SelectionSet: entitiesSelectionSet.Ref, - }) - p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, ast.Selection{ - Kind: ast.SelectionKindField, - Ref: entitiesField.Ref, - }) - p.nodes = append(p.nodes, entitiesField, entitiesSelectionSet) -} - -func (p *Planner) addRepresentationsVariableDefinition() { - anyType := p.upstreamOperation.AddNamedType([]byte("_Any")) - nonNullAnyType := p.upstreamOperation.AddNonNullType(anyType) - listOfNonNullAnyType := p.upstreamOperation.AddListType(nonNullAnyType) - nonNullListOfNonNullAnyType := p.upstreamOperation.AddNonNullType(listOfNonNullAnyType) - - representationsVariable := p.upstreamOperation.ImportVariableValue([]byte("representations")) - p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, representationsVariable, nonNullListOfNonNullAnyType) -} - -func (p *Planner) isNestedRequest() bool { - for i := range p.nodes { - if p.nodes[i].Kind == ast.NodeKindField { - return false - } - } - selectionSetAncestors := 0 - for i := range p.visitor.Walker.Ancestors { - if p.visitor.Walker.Ancestors[i].Kind == ast.NodeKindSelectionSet { - selectionSetAncestors++ - if selectionSetAncestors == 2 { - return true - } - } - } - return false -} - -func (p *Planner) storeArgType(typeName, fieldName, argName string) { - typeNode, _ := p.visitor.Definition.Index.FirstNodeByNameStr(typeName) - - for _, fieldDefRef := range p.visitor.Definition.ObjectTypeDefinitions[typeNode.Ref].FieldsDefinition.Refs { - if bytes.Equal(p.visitor.Definition.FieldDefinitionNameBytes(fieldDefRef), []byte(fieldName)) { - for _, argDefRef := range p.visitor.Definition.FieldDefinitions[fieldDefRef].ArgumentsDefinition.Refs { - if bytes.Equal(p.visitor.Definition.InputValueDefinitionNameBytes(argDefRef), []byte(argName)) { - p.argTypeRef = p.visitor.Definition.ResolveListOrNameType(p.visitor.Definition.InputValueDefinitions[argDefRef].Type) - return - } - } - } - } -} - -func (p *Planner) configureArgument(upstreamFieldRef, downstreamFieldRef int, fieldConfig plan.FieldConfiguration, argumentConfiguration plan.ArgumentConfiguration) { - p.storeArgType(fieldConfig.TypeName, fieldConfig.FieldName, argumentConfiguration.Name) - - switch argumentConfiguration.SourceType { - case plan.FieldArgumentSource: - p.configureFieldArgumentSource(upstreamFieldRef, downstreamFieldRef, argumentConfiguration) - case plan.ObjectFieldSource: - p.configureObjectFieldSource(upstreamFieldRef, downstreamFieldRef, fieldConfig, argumentConfiguration) - } - - p.argTypeRef = -1 -} - -// configureFieldArgumentSource - creates variables for a plain argument types, in case object or list types goes deep and calls applyInlineFieldArgument -func (p *Planner) configureFieldArgumentSource(upstreamFieldRef, downstreamFieldRef int, argumentConfiguration plan.ArgumentConfiguration) { - fieldArgument, ok := p.visitor.Operation.FieldArgument(downstreamFieldRef, []byte(argumentConfiguration.Name)) - if !ok { - return - } - value := p.visitor.Operation.ArgumentValue(fieldArgument) - if value.Kind != ast.ValueKindVariable { - p.applyInlineFieldArgument(upstreamFieldRef, downstreamFieldRef, argumentConfiguration.Name, argumentConfiguration.SourcePath) - return - } - variableName := p.visitor.Operation.VariableValueNameBytes(value.Ref) - variableNameStr := p.visitor.Operation.VariableValueNameString(value.Ref) - - fieldName := p.visitor.Operation.FieldNameBytes(downstreamFieldRef) - argumentDefinition := p.visitor.Definition.NodeFieldDefinitionArgumentDefinitionByName(p.visitor.Walker.EnclosingTypeDefinition, fieldName, []byte(argumentConfiguration.Name)) - - if argumentDefinition == -1 { - return - } - - argumentType := p.visitor.Definition.InputValueDefinitionType(argumentDefinition) - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(p.visitor.Definition, p.visitor.Definition, argumentType) - if err != nil { - return - } - - contextVariable := &resolve.ContextVariable{ - Path: []string{variableNameStr}, - Renderer: renderer, - } - - contextVariableName, exists := p.variables.AddVariable(contextVariable) - variableValueRef, argRef := p.upstreamOperation.AddVariableValueArgument([]byte(argumentConfiguration.Name), variableName) // add the argument to the field, but don't redefine it - p.upstreamOperation.AddArgumentToField(upstreamFieldRef, argRef) - - if exists { // if the variable exists we don't have to put it onto the variables declaration again, skip - return - } - - for _, i := range p.visitor.Operation.OperationDefinitions[p.visitor.Walker.Ancestors[0].Ref].VariableDefinitions.Refs { - ref := p.visitor.Operation.VariableDefinitions[i].VariableValue.Ref - if !p.visitor.Operation.VariableValueNameBytes(ref).Equals(variableName) { - continue - } - typeName := p.visitor.Operation.ResolveTypeNameString(p.visitor.Operation.VariableDefinitions[i].Type) - typeName = p.visitor.Config.Types.RenameTypeNameOnMatchStr(typeName) - if argumentConfiguration.RenameTypeTo != "" { - typeName = argumentConfiguration.RenameTypeTo - } - importedType := p.visitor.Importer.ImportTypeWithRename(p.visitor.Operation.VariableDefinitions[i].Type, p.visitor.Operation, p.upstreamOperation, typeName) - p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, variableValueRef, importedType) - - if add, ok := p.addDirectivesToVariableDefinitions[i]; ok { - for _, directive := range add { - p.addDirectiveToNode(directive, ast.Node{Kind: ast.NodeKindVariableDefinition, Ref: i}) - } - } - } - - p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, variableNameStr, []byte(contextVariableName)) -} - -// applyInlineFieldArgument - configures arguments for a complex argument of a list or input object type -func (p *Planner) applyInlineFieldArgument(upstreamField, downstreamField int, argumentName string, sourcePath []string) { - fieldArgument, ok := p.visitor.Operation.FieldArgument(downstreamField, []byte(argumentName)) - if !ok { - return - } - value := p.visitor.Operation.ArgumentValue(fieldArgument) - importedValue := p.visitor.Importer.ImportValue(value, p.visitor.Operation, p.upstreamOperation) - argRef := p.upstreamOperation.AddArgument(ast.Argument{ - Name: p.upstreamOperation.Input.AppendInputString(argumentName), - Value: importedValue, - }) - p.upstreamOperation.AddArgumentToField(upstreamField, argRef) - - p.addVariableDefinitionsRecursively(value, sourcePath, nil) -} - -// resolveNestedArgumentType - extracts type of nested field or array element of argument -// fieldName - exists only for ast.ValueKindObject type of argument -func (p *Planner) resolveNestedArgumentType(fieldName []byte) (fieldTypeRef int) { - if fieldName == nil { - return p.visitor.Definition.ResolveListOrNameType(p.argTypeRef) - } - - argTypeName := p.visitor.Definition.ResolveTypeNameString(p.argTypeRef) - argTypeNode, _ := p.visitor.Definition.Index.FirstNodeByNameStr(argTypeName) - - for _, inputFieldDefRef := range p.visitor.Definition.InputObjectTypeDefinitions[argTypeNode.Ref].InputFieldsDefinition.Refs { - if bytes.Equal(p.visitor.Definition.InputValueDefinitionNameBytes(inputFieldDefRef), fieldName) { - return p.visitor.Definition.InputValueDefinitions[inputFieldDefRef].Type - } - } - - return -1 -} - -// addVariableDefinitionsRecursively - recursively configures variables inside a list or an input type -func (p *Planner) addVariableDefinitionsRecursively(value ast.Value, sourcePath []string, fieldName []byte) { - switch value.Kind { - case ast.ValueKindObject: - prevArgTypeRef := p.argTypeRef - p.argTypeRef = p.resolveNestedArgumentType(fieldName) - for _, objectFieldRef := range p.visitor.Operation.ObjectValues[value.Ref].Refs { - p.addVariableDefinitionsRecursively(p.visitor.Operation.ObjectFields[objectFieldRef].Value, sourcePath, p.visitor.Operation.ObjectFieldNameBytes(objectFieldRef)) - } - p.argTypeRef = prevArgTypeRef - return - case ast.ValueKindList: - for _, i := range p.visitor.Operation.ListValues[value.Ref].Refs { - p.addVariableDefinitionsRecursively(p.visitor.Operation.Values[i], sourcePath, nil) - } - return - case ast.ValueKindVariable: - // continue after switch - default: - return - } - - variableName := p.visitor.Operation.VariableValueNameBytes(value.Ref) - variableNameStr := p.visitor.Operation.VariableValueNameString(value.Ref) - variableDefinition, exists := p.visitor.Operation.VariableDefinitionByNameAndOperation(p.visitor.Walker.Ancestors[0].Ref, variableName) - if !exists { - return - } - - variableDefinitionTypeRef := p.visitor.Operation.VariableDefinitions[variableDefinition].Type - variableDefinitionTypeName := p.visitor.Operation.ResolveTypeNameString(variableDefinitionTypeRef) - variableDefinitionTypeName = p.visitor.Config.Types.RenameTypeNameOnMatchStr(variableDefinitionTypeName) - - contextVariable := &resolve.ContextVariable{ - Path: append(sourcePath, variableNameStr), - } - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(p.visitor.Operation, p.visitor.Definition, variableDefinitionTypeRef) - if err != nil { - return - } - contextVariable.Renderer = renderer - contextVariableName, variableExists := p.variables.AddVariable(contextVariable) - if variableExists { - return - } - - importedVariableDefinition := p.visitor.Importer.ImportVariableDefinitionWithRename(variableDefinition, p.visitor.Operation, p.upstreamOperation, variableDefinitionTypeName) - p.upstreamOperation.AddImportedVariableDefinitionToOperationDefinition(p.nodes[0].Ref, importedVariableDefinition) - - p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, variableNameStr, []byte(contextVariableName)) -} - -// configureObjectFieldSource - configures source of a field when it has variables coming from current object -func (p *Planner) configureObjectFieldSource(upstreamFieldRef, downstreamFieldRef int, fieldConfiguration plan.FieldConfiguration, argumentConfiguration plan.ArgumentConfiguration) { - if len(argumentConfiguration.SourcePath) < 1 { - return - } - - fieldName := p.visitor.Operation.FieldNameUnsafeString(downstreamFieldRef) - - if len(fieldConfiguration.Path) == 1 { - fieldName = fieldConfiguration.Path[0] - } - - queryTypeDefinition, exists := p.visitor.Definition.Index.FirstNodeByNameBytes(p.visitor.Definition.Index.QueryTypeName) - if !exists { - return - } - argumentDefinition := p.visitor.Definition.NodeFieldDefinitionArgumentDefinitionByName(queryTypeDefinition, []byte(fieldName), []byte(argumentConfiguration.Name)) - if argumentDefinition == -1 { - return - } - - argumentType := p.visitor.Definition.InputValueDefinitionType(argumentDefinition) - variableName := p.upstreamOperation.GenerateUnusedVariableDefinitionName(p.nodes[0].Ref) - variableValue, argument := p.upstreamOperation.AddVariableValueArgument([]byte(argumentConfiguration.Name), variableName) - p.upstreamOperation.AddArgumentToField(upstreamFieldRef, argument) - - typeName := p.visitor.Operation.ResolveTypeNameString(argumentType) - typeName = p.visitor.Config.Types.RenameTypeNameOnMatchStr(typeName) - if argumentConfiguration.RenameTypeTo != "" { - typeName = argumentConfiguration.RenameTypeTo - } - - importedType := p.visitor.Importer.ImportTypeWithRename(argumentType, p.visitor.Definition, p.upstreamOperation, typeName) - p.upstreamOperation.AddVariableDefinitionToOperationDefinition(p.nodes[0].Ref, variableValue, importedType) - - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(p.visitor.Definition, p.visitor.Definition, argumentType) - if err != nil { - return - } - - variable := &resolve.ObjectVariable{ - Path: argumentConfiguration.SourcePath, - Renderer: renderer, - } - - objectVariableName, exists := p.variables.AddVariable(variable) - if !exists { - p.upstreamVariables, _ = sjson.SetRawBytes(p.upstreamVariables, string(variableName), []byte(objectVariableName)) - } -} - -const ( - normalizationFailedErrMsg = "printOperation: normalization failed" - parseDocumentFailedErrMsg = "printOperation: parse %s failed" -) - -// printOperation - prints normalized upstream operation -func (p *Planner) printOperation() []byte { - buf := &bytes.Buffer{} - - err := astprinter.Print(p.upstreamOperation, nil, buf) - if err != nil { - return nil - } - - rawQuery := buf.Bytes() - - // create empty operation and definition documents - operation := ast.NewDocument() - definition := ast.NewDocument() - report := &operationreport.Report{} - operationParser := astparser.NewParser() - definitionParser := astparser.NewParser() - - operation.Input.ResetInputBytes(rawQuery) - operationParser.Parse(operation, report) - if report.HasErrors() { - p.stopWithError(parseDocumentFailedErrMsg, "operation") - return nil - } - - if p.config.UpstreamSchema == "" { - p.config.UpstreamSchema, err = astprinter.PrintString(p.visitor.Definition, nil) - if err != nil { - p.visitor.Walker.StopWithInternalErr(err) - return nil - } - } - - if p.config.Federation.Enabled { - federationSchema, err := federation.BuildFederationSchema(p.config.UpstreamSchema, p.config.Federation.ServiceSDL) - if err != nil { - p.visitor.Walker.StopWithInternalErr(err) - return nil - } - definition.Input.ResetInputString(federationSchema) - definitionParser.Parse(definition, report) - if report.HasErrors() { - p.stopWithError(parseDocumentFailedErrMsg, "definition") - return nil - } - } else { - definition.Input.ResetInputString(p.config.UpstreamSchema) - definitionParser.Parse(definition, report) - if report.HasErrors() { - p.stopWithError("unable to parse upstream schema") - return nil - } - - if err := asttransform.MergeDefinitionWithBaseSchema(definition); err != nil { - p.stopWithError("unable to merge upstream schema with base schema") - return nil - } - } - - // When datasource is nested and definition query type do not contain operation field - // we have to replace a query type with a current root type - p.replaceQueryType(definition) - - // normalize upstream operation - if !p.normalizeOperation(operation, definition, report) { - p.stopWithError(normalizationFailedErrMsg) - return nil - } - - validator := astvalidation.DefaultOperationValidator() - validator.Validate(operation, definition, report) - if report.HasErrors() { - p.stopWithError("validation failed: %s", report.Error()) - return nil - } - - buf.Reset() - - // print upstream operation - err = astprinter.Print(operation, p.visitor.Definition, buf) - if err != nil { - p.stopWithError(normalizationFailedErrMsg) - return nil - } - - return buf.Bytes() -} - -func (p *Planner) stopWithError(msg string, args ...interface{}) { - p.visitor.Walker.StopWithInternalErr(fmt.Errorf(msg, args...)) -} - -/* -replaceQueryType - sets definition query type to a current root type. -Helps to do a normalization of the upstream query for a nested datasource. -Skips replace when: -1. datasource is not nested; -2. federation is enabled; -3. query type contains an operation field; - -Example transformation: -Original schema definition: - - type Query { - serviceOne(serviceOneArg: String): ServiceOneResponse - serviceTwo(serviceTwoArg: Boolean): ServiceTwoResponse - } - - type ServiceOneResponse { - fieldOne: String! - countries: [Country!]! # nested datasource without explicit field path - } - - type ServiceTwoResponse { - fieldTwo: String - serviceOneField: String - serviceOneResponse: ServiceOneResponse # nested datasource with implicit field path "serviceOne" - } - - type Country { - name: String! - } - -`serviceOneResponse` field of a `ServiceTwoResponse` is nested but has a field path that exists on the Query type -- In this case definition will not be modified - -`countries` field of a `ServiceOneResponse` is nested and not present on the Query type -- In this case query type of definition will be replaced with a `ServiceOneResponse` - -Modified schema definition: - - schema { - query: ServiceOneResponse - } - - type ServiceOneResponse { - fieldOne: String! - countries: [Country!]! - } - - type ServiceTwoResponse { - fieldTwo: String - serviceOneField: String - serviceOneResponse: ServiceOneResponse - } - - type Country { - name: String! - } - -Refer to pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go:632 -Case name: TestGraphQLDataSource/nested_graphql_engines - -If we didn't do this transformation, the normalization would fail because it's not possible -to traverse the AST as there's a mismatch between the upstream Operation and the schema. - -If the nested Query can be rewritten so that it's a valid Query against the existing schema, fine. -However, when rewriting the nested Query onto the schema's Query type, -it might be the case that no FieldDefinition exists for the rewritten root field. -In that case, we transform the schema so that normalization and printing of the upstream Query succeeds. -*/ -func (p *Planner) replaceQueryType(definition *ast.Document) { - if !p.isNested || p.config.Federation.Enabled { - return - } - - queryTypeName := definition.Index.QueryTypeName - queryNode, exists := definition.Index.FirstNodeByNameBytes(queryTypeName) - if !exists || queryNode.Kind != ast.NodeKindObjectTypeDefinition { - return - } - - // check that query type has rootFieldName within its fields - hasField := definition.FieldDefinitionsContainField(definition.ObjectTypeDefinitions[queryNode.Ref].FieldsDefinition.Refs, []byte(p.rootFieldName)) - if hasField { - return - } - - definition.RemoveObjectTypeDefinition(definition.Index.QueryTypeName) - definition.ReplaceRootOperationTypeDefinition(p.rootTypeName, ast.OperationTypeQuery) -} - -// normalizeOperation - normalizes operation against definition. -func (p *Planner) normalizeOperation(operation, definition *ast.Document, report *operationreport.Report) (ok bool) { - report.Reset() - normalizer := astnormalization.NewWithOpts( - astnormalization.WithExtractVariables(), - astnormalization.WithRemoveFragmentDefinitions(), - astnormalization.WithRemoveUnusedVariables(), - ) - normalizer.NormalizeOperation(operation, definition, report) - - return !report.HasErrors() -} - -func (p *Planner) handleFieldAlias(ref int) (newFieldName string, alias ast.Alias) { - fieldName := p.visitor.Operation.FieldNameString(ref) - alias = ast.Alias{ - IsDefined: p.visitor.Operation.FieldAliasIsDefined(ref), - } - - if alias.IsDefined { - aliasBytes := p.visitor.Operation.FieldAliasBytes(ref) - alias.Name = p.upstreamOperation.Input.AppendInputBytes(aliasBytes) - } - - typeName := p.visitor.Walker.EnclosingTypeDefinition.NameString(p.visitor.Definition) - for i := range p.visitor.Config.Fields { - isDesiredField := p.visitor.Config.Fields[i].TypeName == typeName && - p.visitor.Config.Fields[i].FieldName == fieldName - - // check that we are on a desired field and field path contains a single element - mapping is plain - if isDesiredField && len(p.visitor.Config.Fields[i].Path) == 1 { - // define alias when mapping path differs from fieldName and no alias has been defined - if p.visitor.Config.Fields[i].Path[0] != fieldName && !alias.IsDefined { - alias.IsDefined = true - aliasBytes := p.visitor.Operation.FieldNameBytes(ref) - alias.Name = p.upstreamOperation.Input.AppendInputBytes(aliasBytes) - } - - // override fieldName with mapping path value - fieldName = p.visitor.Config.Fields[i].Path[0] - - // when provided field is a root type field save new field name - if ref == p.rootFieldRef { - p.rootFieldName = fieldName - } - - break - } - } - return fieldName, alias -} - -// addField - add a field to an upstream operation -func (p *Planner) addField(ref int) { - fieldName, alias := p.handleFieldAlias(ref) - - field := p.upstreamOperation.AddField(ast.Field{ - Name: p.upstreamOperation.Input.AppendInputString(fieldName), - Alias: alias, - }) - - selection := ast.Selection{ - Kind: ast.SelectionKindField, - Ref: field.Ref, - } - - p.upstreamOperation.AddSelection(p.nodes[len(p.nodes)-1].Ref, selection) - p.nodes = append(p.nodes, field) -} - -type OnWsConnectionInitCallback func(ctx context.Context, url string, header http.Header) (json.RawMessage, error) - -type Factory struct { - BatchFactory resolve.DataSourceBatchFactory - HTTPClient *http.Client - StreamingClient *http.Client - OnWsConnectionInitCallback *OnWsConnectionInitCallback - SubscriptionClient *SubscriptionClient -} - -func (f *Factory) Planner(ctx context.Context) plan.DataSourcePlanner { - if f.SubscriptionClient == nil { - opts := make([]Options, 0) - if f.OnWsConnectionInitCallback != nil { - opts = append(opts, WithOnWsConnectionInitCallback(f.OnWsConnectionInitCallback)) - } - - f.SubscriptionClient = NewGraphQLSubscriptionClient(f.HTTPClient, f.StreamingClient, ctx, opts...) - } else if f.SubscriptionClient.engineCtx == nil { - f.SubscriptionClient.engineCtx = ctx - } - return &Planner{ - batchFactory: f.BatchFactory, - fetchClient: f.HTTPClient, - subscriptionClient: f.SubscriptionClient, - } -} - -type Source struct { - httpClient *http.Client -} - -func (s *Source) compactAndUnNullVariables(input []byte) []byte { - undefinedVariables := httpclient.UndefinedVariables(input) - variables, _, _, err := jsonparser.Get(input, "body", "variables") - if err != nil { - return input - } - if bytes.Equal(variables, []byte("null")) || bytes.Equal(variables, []byte("{}")) { - return input - } - if bytes.ContainsAny(variables, " \t\n\r") { - buf := bytes.NewBuffer(make([]byte, 0, len(variables))) - if err := json.Compact(buf, variables); err != nil { - panic(fmt.Errorf("compacting variables: %w", err)) - } - variables = buf.Bytes() - } - - removeNullVariables := httpclient.IsInputFlagSet(input, httpclient.UNNULLVARIABLES) - variables = s.cleanupVariables(variables, removeNullVariables, undefinedVariables) - - input, _ = jsonparser.Set(input, variables, "body", "variables") - return input -} - -// cleanupVariables removes null variables and empty objects from the input if removeNullVariables is true -// otherwise returns the input as is -func (s *Source) cleanupVariables(variables []byte, removeNullVariables bool, undefinedVariables []string) []byte { - cp := make([]byte, len(variables)) - copy(cp, variables) - - // remove null variables from JSON: {"a":null,"b":1} -> {"b":1} - err := jsonparser.ObjectEach(variables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { - if dataType == jsonparser.Null { - stringKey := unsafebytes.BytesToString(key) - if removeNullVariables || slices.Contains(undefinedVariables, stringKey) { - cp = jsonparser.Delete(cp, stringKey) - } - } - return nil - }) - if err != nil { - return variables - } - - // remove empty objects - if removeNullVariables { - cp = s.removeEmptyObjects(cp) - } - - return cp -} - -// removeEmptyObjects removes empty objects from JSON: {"b": "b", "c": {}} -> {"b": "b"} -func (s *Source) removeEmptyObjects(variables []byte) []byte { - var changed bool - for { - variables, changed = s.replaceEmptyObject(variables) - if !changed { - break - } - } - return variables -} - -func (s *Source) replaceEmptyObject(variables []byte) ([]byte, bool) { - if i := bytes.Index(variables, []byte(":{}")); i != -1 { - end := i + 3 - hasTrailingComma := false - if variables[end] == ',' { - end++ - hasTrailingComma = true - } - startQuote := bytes.LastIndex(variables[:i-2], []byte("\"")) - if !hasTrailingComma && variables[startQuote-1] == ',' { - startQuote-- - } - return append(variables[:startQuote], variables[end:]...), true - } - - return variables, false -} - -func (s *Source) Load(ctx context.Context, input []byte, writer io.Writer) (err error) { - input = s.compactAndUnNullVariables(input) - return httpclient.Do(s.httpClient, ctx, input, writer) -} - -type GraphQLSubscriptionClient interface { - Subscribe(ctx context.Context, options GraphQLSubscriptionOptions, next chan<- []byte) error -} - -type GraphQLSubscriptionOptions struct { - URL string `json:"url"` - Body GraphQLBody `json:"body"` - Header http.Header `json:"header"` - UseSSE bool `json:"use_sse"` - SSEMethodPost bool `json:"sse_method_post"` -} - -type GraphQLBody struct { - Query string `json:"query,omitempty"` - OperationName string `json:"operationName,omitempty"` - Variables json.RawMessage `json:"variables,omitempty"` - Extensions json.RawMessage `json:"extensions,omitempty"` -} - -type SubscriptionSource struct { - client GraphQLSubscriptionClient -} - -func (s *SubscriptionSource) Start(ctx context.Context, input []byte, next chan<- []byte) error { - var options GraphQLSubscriptionOptions - err := json.Unmarshal(input, &options) - if err != nil { - return err - } - if options.Body.Query == "" { - return resolve.ErrUnableToResolve - } - return s.client.Subscribe(ctx, options, next) -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go b/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go deleted file mode 100644 index b4bbb6a1e..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_datasource_test.go +++ /dev/null @@ -1,10193 +0,0 @@ -package graphql_datasource - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "net/http/httptest" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - . "github.com/wundergraph/graphql-go-tools/pkg/engine/datasourcetesting" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/testing/subscriptiontesting" -) - -func TestGraphQLDataSource(t *testing.T) { - // XXX: Directive needs to be explicitly declared - t.Run("@removeNullVariables directive", RunTest(` - directive @removeNullVariables on QUERY | MUTATION - - schema { - query: Query - } - - type Query { - hero(a: String): String - }`, ` - query MyQuery($a: String) @removeNullVariables { - hero(a: $a) - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","unnull_variables":true,"body":{"query":"query($a: String){hero(a: $a)}","variables":{"a":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("hero"), - Value: &resolve.String{ - Path: []string{"hero"}, - Nullable: true, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"hero"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "a", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("simple named Query", RunTest(starWarsSchema, ` - query MyQuery($id: ID!) { - droid(id: $id){ - name - aliased: name - friends { - name - } - primaryFunction - } - hero { - name - } - stringList - nestedStringList - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","header":{"Authorization":["$$1$$"],"Invalid-Template":["{{ request.headers.Authorization }}"]},"body":{"query":"query($id: ID!){droid(id: $id){name aliased: name friends {name} primaryFunction} hero {name} stringList nestedStringList}","variables":{"id":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("droid"), - Value: &resolve.Object{ - Path: []string{"droid"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("aliased"), - Value: &resolve.String{ - Path: []string{"aliased"}, - }, - }, - { - Name: []byte("friends"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"friends"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("stringList"), - Value: &resolve.Array{ - Nullable: true, - Item: &resolve.String{ - Nullable: true, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nestedStringList"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"nestedStringList"}, - Item: &resolve.String{ - Nullable: true, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid", "hero", "stringList", "nestedStringList"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name", "friends"}, - }, - { - TypeName: "Human", - FieldNames: []string{"name", "height", "friends"}, - }, - { - TypeName: "Droid", - FieldNames: []string{"name", "primaryFunction", "friends"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - Header: http.Header{ - "Authorization": []string{"{{ .request.headers.Authorization }}"}, - "Invalid-Template": []string{"{{ request.headers.Authorization }}"}, - }, - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "stringList", - DisableDefaultMapping: true, - }, - { - TypeName: "Query", - FieldName: "nestedStringList", - Path: []string{"nestedStringList"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("selections on interface type", RunTest(interfaceSelectionSchema, ` - query MyQuery { - user { - id - displayName - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"{user {id displayName}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("skip directive with variable", RunTest(interfaceSelectionSchema, ` - query MyQuery ($skip: Boolean!) { - user { - id - displayName @skip(if: $skip) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($skip: Boolean!){user {id displayName @skip(if: $skip)}}","variables":{"skip":$$0$$}}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"skip"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - ), - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("skip directive on __typename", RunTest(interfaceSelectionSchema, ` - query MyQuery ($skip: Boolean!) { - user { - id - displayName - __typename @skip(if: $skip) - tn2: __typename @include(if: $skip) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($skip: Boolean!){user {id displayName __typename @skip(if: $skip)}}","variables":{"skip":$$0$$}}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - Variables: resolve.NewVariables(&resolve.ContextVariable{ - Path: []string{"skip"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - }, - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - IsTypeName: true, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - { - Name: []byte("tn2"), - Value: &resolve.String{ - Path: []string{"__typename"}, - IsTypeName: true, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("skip directive on an inline fragment", RunTest(interfaceSelectionSchema, ` - query MyQuery ($skip: Boolean!) { - user { - ... @skip(if: $skip) { - id - displayName - } - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($skip: Boolean!){user {... @skip(if: $skip){id displayName}}}","variables":{"skip":$$0$$}}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"skip"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - ), - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - OnTypeNames: [][]byte{[]byte("RegisteredUser")}, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - OnTypeNames: [][]byte{[]byte("RegisteredUser")}, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("include directive on an inline fragment", RunTest(interfaceSelectionSchema, ` - query MyQuery ($include: Boolean!) { - user { - ... @include(if: $include) { - id - displayName - } - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($include: Boolean!){user {... @include(if: $include){id displayName}}}","variables":{"include":$$0$$}}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"include"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - ), - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - OnTypeNames: [][]byte{[]byte("RegisteredUser")}, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - OnTypeNames: [][]byte{[]byte("RegisteredUser")}, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("skip directive with inline value true", RunTest(interfaceSelectionSchema, ` - query MyQuery { - user { - id - displayName @skip(if: true) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"{user {id}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("skip directive with inline value false", RunTest(interfaceSelectionSchema, ` - query MyQuery { - user { - id - displayName @skip(if: false) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"{user {id displayName}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("include directive with variable", RunTest(interfaceSelectionSchema, ` - query MyQuery ($include: Boolean!) { - user { - id - displayName @include(if: $include) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($include: Boolean!){user {id displayName @include(if: $include)}}","variables":{"include":$$0$$}}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"include"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - ), - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("include directive with inline value true", RunTest(interfaceSelectionSchema, ` - query MyQuery { - user { - id - displayName @include(if: true) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"{user {id displayName}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - t.Run("include directive with inline value false", RunTest(interfaceSelectionSchema, ` - query MyQuery { - user { - id - displayName @include(if: false) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"{user {id}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("selections on interface type with object type interface", RunTest(interfaceSelectionSchema, ` - query MyQuery { - user { - id - displayName - ... on RegisteredUser { - hasVerifiedEmail - } - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"{user {id displayName __typename ... on RegisteredUser {hasVerifiedEmail}}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("displayName"), - Value: &resolve.String{ - Path: []string{"displayName"}, - }, - }, - { - Name: []byte("hasVerifiedEmail"), - Value: &resolve.Boolean{ - Path: []string{"hasVerifiedEmail"}, - }, - OnTypeNames: [][]byte{[]byte("RegisteredUser")}, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "displayName", "isLoggedIn"}, - }, - { - TypeName: "RegisteredUser", - FieldNames: []string{"id", "displayName", "isLoggedIn", "hasVerifiedEmail"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{}, - DisableResolveFieldPositions: true, - })) - - t.Run("variable at top level and recursively", RunTest(variableSchema, ` - query MyQuery($name: String!){ - user(name: $name){ - normalized(data: {name: $name}) - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($name: String!){user(name: $name){normalized(data: {name: $name})}}","variables":{"name":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"name"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("normalized"), - Value: &resolve.String{ - Path: []string{"normalized"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"normalized"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - UpstreamSchema: variableSchema, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "user", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "User", - FieldName: "normalized", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "data", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("exported ID scalar field", RunTest(starWarsSchemaWithExportDirective, ` - query MyQuery($heroId: ID!){ - droid(id: $heroId){ - name - } - hero { - id @export(as: "heroId") - } - } - `, "MyQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($heroId: ID!){droid(id: $heroId){name} hero {id}}","variables":{"heroId":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"heroId"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("droid"), - Value: &resolve.Object{ - Path: []string{"droid"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - Export: &resolve.FieldExport{ - Path: []string{"heroId"}, - AsString: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid", "hero"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"id"}, - }, - { - TypeName: "Droid", - FieldNames: []string{"name"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - }, - UpstreamSchema: starWarsSchema, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("exported string field", RunTest(starWarsSchemaWithExportDirective, ` - query MyQuery($id: ID! $heroName: String!){ - droid(id: $id){ - name - aliased: name - friends { - name - } - primaryFunction - } - hero { - name @export(as: "heroName") - } - search(name: $heroName) { - ... on Droid { - primaryFunction - } - } - stringList - nestedStringList - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","header":{"Authorization":["$$2$$"],"Invalid-Template":["{{ request.headers.Authorization }}"]},"body":{"query":"query($id: ID!, $heroName: String!){droid(id: $id){name aliased: name friends {name} primaryFunction} hero {name} search(name: $heroName){__typename ... on Droid {primaryFunction}} stringList nestedStringList}","variables":{"heroName":$$1$$,"id":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"heroName"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("droid"), - Value: &resolve.Object{ - Path: []string{"droid"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("aliased"), - Value: &resolve.String{ - Path: []string{"aliased"}, - }, - }, - { - Name: []byte("friends"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"friends"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Export: &resolve.FieldExport{ - Path: []string{"heroName"}, - AsString: true, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("search"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"search"}, - Fields: []*resolve.Field{ - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - OnTypeNames: [][]byte{[]byte("Droid")}, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("stringList"), - Value: &resolve.Array{ - Nullable: true, - Item: &resolve.String{ - Nullable: true, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nestedStringList"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"nestedStringList"}, - Item: &resolve.String{ - Nullable: true, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid", "hero", "stringList", "nestedStringList", "search"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name", "friends"}, - }, - { - TypeName: "Human", - FieldNames: []string{"name", "height", "friends"}, - }, - { - TypeName: "Droid", - FieldNames: []string{"name", "primaryFunction", "friends"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - Header: http.Header{ - "Authorization": []string{"{{ .request.headers.Authorization }}"}, - "Invalid-Template": []string{"{{ request.headers.Authorization }}"}, - }, - }, - UpstreamSchema: starWarsSchema, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "stringList", - DisableDefaultMapping: true, - }, - { - TypeName: "Query", - FieldName: "nestedStringList", - Path: []string{"nestedStringList"}, - }, - { - TypeName: "Query", - FieldName: "search", - Path: []string{"search"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("Query with renamed root fields", RunTest(renamedStarWarsSchema, ` - query MyQuery($id: ID! $input: SearchInput_api! @api_onVariable $options: JSON_api) @otherapi_undefined @api_onOperation { - api_droid(id: $id){ - name @api_format - aliased: name - friends { - name - } - primaryFunction - } - api_hero { - name - ... on Human_api { - height - } - } - api_stringList - renamed: api_nestedStringList - api_search(name: "r2d2") { - ... on Droid_api { - primaryFunction - } - } - api_searchWithInput(input: $input) { - ... on Droid_api { - primaryFunction - } - } - withOptions: api_searchWithInput(input: { - options: $options - }) { - ... on Droid_api { - primaryFunction - } - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","header":{"Authorization":["$$4$$"],"Invalid-Template":["{{ request.headers.Authorization }}"]},"body":{"query":"query($id: ID!, $a: String! @onVariable, $input: SearchInput!, $options: JSON)@onOperation {api_droid: droid(id: $id){name @format aliased: name friends {name} primaryFunction} api_hero: hero {name __typename ... on Human {height}} api_stringList: stringList renamed: nestedStringList api_search: search(name: $a){__typename ... on Droid {primaryFunction}} api_searchWithInput: searchWithInput(input: $input){__typename ... on Droid {primaryFunction}} withOptions: searchWithInput(input: {options: $options}){__typename ... on Droid {primaryFunction}}}","variables":{"options":$$3$$,"input":$$2$$,"a":$$1$$,"id":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"input"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["object"],"properties":{"name":{"type":["string","null"]},"options":{}},"additionalProperties":false}`), - }, - &resolve.ContextVariable{ - Path: []string{"options"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{}`), - }, - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("api_droid"), - Value: &resolve.Object{ - Path: []string{"api_droid"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("aliased"), - Value: &resolve.String{ - Path: []string{"aliased"}, - }, - }, - { - Name: []byte("friends"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"friends"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("api_hero"), - Value: &resolve.Object{ - Path: []string{"api_hero"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("height"), - Value: &resolve.String{ - Path: []string{"height"}, - }, - OnTypeNames: [][]byte{[]byte("Human")}, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("api_stringList"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"api_stringList"}, - Item: &resolve.String{ - Nullable: true, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("renamed"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"renamed"}, - Item: &resolve.String{ - Nullable: true, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("api_search"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"api_search"}, - Fields: []*resolve.Field{ - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - OnTypeNames: [][]byte{[]byte("Droid")}, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("api_searchWithInput"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"api_searchWithInput"}, - Fields: []*resolve.Field{ - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - OnTypeNames: [][]byte{[]byte("Droid")}, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("withOptions"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"withOptions"}, - Fields: []*resolve.Field{ - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - OnTypeNames: [][]byte{[]byte("Droid")}, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"api_droid", "api_hero", "api_stringList", "api_nestedStringList", "api_search", "api_searchWithInput"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character_api", - FieldNames: []string{"name", "friends"}, - }, - { - TypeName: "Human_api", - FieldNames: []string{"name", "height", "friends"}, - }, - { - TypeName: "Droid_api", - FieldNames: []string{"name", "primaryFunction", "friends"}, - }, - { - TypeName: "SearchResult_api", - FieldNames: []string{"name", "height", "primaryFunction", "friends"}, - }, - }, - Directives: []plan.DirectiveConfiguration{ - { - DirectiveName: "api_format", - RenameTo: "format", - }, - { - DirectiveName: "api_onOperation", - RenameTo: "onOperation", - }, - { - DirectiveName: "api_onVariable", - RenameTo: "onVariable", - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - Header: http.Header{ - "Authorization": []string{"{{ .request.headers.Authorization }}"}, - "Invalid-Template": []string{"{{ request.headers.Authorization }}"}, - }, - }, - UpstreamSchema: starWarsSchema, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "api_droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - Path: []string{"droid"}, - }, - { - TypeName: "Query", - FieldName: "api_hero", - Path: []string{"hero"}, - }, - { - TypeName: "Query", - FieldName: "api_stringList", - Path: []string{"stringList"}, - }, - { - TypeName: "Query", - FieldName: "api_nestedStringList", - Path: []string{"nestedStringList"}, - }, - { - TypeName: "Query", - FieldName: "api_search", - Path: []string{"search"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - SourcePath: []string{"name"}, - RenderConfig: plan.RenderArgumentAsGraphQLValue, - }, - }, - }, - { - TypeName: "Query", - FieldName: "api_searchWithInput", - Path: []string{"searchWithInput"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "input", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - Types: []plan.TypeConfiguration{ - { - TypeName: "Human_api", - RenameTo: "Human", - }, - { - TypeName: "Droid_api", - RenameTo: "Droid", - }, - { - TypeName: "SearchResult_api", - RenameTo: "SearchResult", - }, - { - TypeName: "SearchInput_api", - RenameTo: "SearchInput", - }, - { - TypeName: "JSON_api", - RenameTo: "JSON", - }, - }, - DisableResolveFieldPositions: true, - })) - t.Run("Query with array input", RunTest(subgraphTestSchema, ` - query($representations: [_Any!]!) { - _entities(representations: $representations){ - ... on Product { - reviews { - body - author { - username - id - } - } - } - } - } - `, "", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://subgraph-reviews/query","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on Product {reviews {body author {username id}}}}}","variables":{"representations":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"representations"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["array"],"items":{"type":["object"],"additionalProperties":true}}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("_entities"), - Value: &resolve.Array{ - Path: []string{"_entities"}, - Nullable: false, - Item: &resolve.Object{ - Nullable: true, - Path: nil, - Fields: []*resolve.Field{ - { - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - ResolveAsynchronous: false, - Item: &resolve.Object{ - Nullable: true, - Path: nil, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - Nullable: false, - }, - }, - { - Name: []byte("author"), - Value: &resolve.Object{ - Nullable: false, - Path: []string{"author"}, - Fields: []*resolve.Field{ - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - Nullable: false, - }, - }, - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - Nullable: false, - }, - }, - }, - }, - }, - }, - }, - }, - OnTypeNames: [][]byte{[]byte("Product")}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"_entities", "_service"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "_Service", - FieldNames: []string{"sdl"}, - }, - { - TypeName: "Entity", - FieldNames: []string{"findProductByUpc", "findUserByID"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc", "reviews"}, - }, - { - TypeName: "Review", - FieldNames: []string{"body", "author", "product"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username", "reviews"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://subgraph-reviews/query", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "_entities", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "representations", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Entity", - FieldName: "findProductByUpc", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "upc", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Entity", - FieldName: "findUserByID", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("Query with ID array input", runTestOnTestDefinition(` - query Droids($droidIDs: [ID!]!) { - droids(ids: $droidIDs) { - name - primaryFunction - } - }`, "Droids", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($droidIDs: [ID!]!){droids(ids: $droidIDs){name primaryFunction}}","variables":{"droidIDs":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"droidIDs"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["array"],"items":{"type":["string","integer"]}}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - Name: []byte("droids"), - Value: &resolve.Array{ - Path: []string{"droids"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Path: nil, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: false, - }, - }, - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - Nullable: false, - }, - }, - }, - }, - Stream: resolve.Stream{}, - }, - HasBuffer: true, - BufferID: 0, - }, - }, - }, - }, - })) - - t.Run("Query with ID input", runTestOnTestDefinition(` - query Droid($droidID: ID!) { - droid(id: $droidID) { - name - primaryFunction - } - }`, "Droid", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($droidID: ID!){droid(id: $droidID){name primaryFunction}}","variables":{"droidID":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"droidID"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - Name: []byte("droid"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"droid"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: false, - }, - }, - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - Nullable: false, - }, - }, - }, - }, - HasBuffer: true, - BufferID: 0, - }, - }, - }, - }, - })) - - t.Run("Query with Date input aka scalar", runTestOnTestDefinition(` - query HeroByBirthdate($birthdate: Date!) { - heroByBirthdate(birthdate: $birthdate) { - name - } - }`, "HeroByBirthdate", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","body":{"query":"query($birthdate: Date!){heroByBirthdate(birthdate: $birthdate){name}}","variables":{"birthdate":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"birthdate"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - Name: []byte("heroByBirthdate"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"heroByBirthdate"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: false, - }, - }, - }, - }, - HasBuffer: true, - BufferID: 0, - }, - }, - }, - }, - })) - - t.Run("simple mutation", RunTest(` - type Mutation { - addFriend(name: String!):Friend! - } - type Friend { - id: ID! - name: String! - } - `, - `mutation AddFriend($name: String!){ addFriend(name: $name){ id name } }`, - "AddFriend", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://service.one","body":{"query":"mutation($name: String!){addFriend(name: $name){id name}}","variables":{"name":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"name"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DisallowSingleFlight: true, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("addFriend"), - Value: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{"addFriend"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Friend", - FieldNames: []string{"id", "name"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://service.one", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "addFriend", - DisableDefaultMapping: true, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("nested resolvers of same upstream", RunTest(` - type Query { - foo(bar: String):Baz - } - type Baz { - bar(bal: String):String - } - `, - ` - query NestedQuery { - foo(bar: "baz") { - bar(bal: "bat") - } - } - `, - "NestedQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://foo.service","body":{"query":"query($a: String, $b: String){foo(bar: $a){bar(bal: $b)}}","variables":{"b":$$1$$,"a":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"b"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DisallowSingleFlight: false, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("foo"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"foo"}, - Fields: []*resolve.Field{ - { - Name: []byte("bar"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"bar"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"foo"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Baz", - FieldNames: []string{"bar"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://foo.service", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "foo", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "bar", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Baz", - FieldName: "bar", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "bal", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("same upstream with alias in query", RunTest( - countriesSchema, - ` - query QueryWithAlias { - country(code: "AD") { - name - } - alias: country(code: "AE") { - name - } - } - `, - "QueryWithAlias", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://countries.service","body":{"query":"query($a: ID!, $b: ID!){country(code: $a){name} alias: country(code: $b){name}}","variables":{"b":$$1$$,"a":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"b"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DisallowSingleFlight: false, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("country"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"country"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Nullable: false, - Path: []string{"name"}, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("alias"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"alias"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Nullable: false, - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"country", "countryAlias"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Country", - FieldNames: []string{"name", "code"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://countries.service", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "country", - Path: []string{"country"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "code", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "countryAlias", - Path: []string{"country"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "code", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("same upstream with alias in schema", RunTest( - countriesSchema, - ` - query QueryWithSchemaAlias { - country(code: "AD") { - name - } - countryAlias(code: "AE") { - name - } - } - `, - "QueryWithSchemaAlias", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://countries.service","body":{"query":"query($a: ID!, $b: ID!){country(code: $a){name} countryAlias: country(code: $b){name}}","variables":{"b":$$1$$,"a":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"b"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DisallowSingleFlight: false, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("country"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"country"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Nullable: false, - Path: []string{"name"}, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("countryAlias"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"countryAlias"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Nullable: false, - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"country", "countryAlias"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Country", - FieldNames: []string{"name", "code"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://countries.service", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "country", - Path: []string{"country"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "code", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "countryAlias", - Path: []string{"country"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "code", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - nestedGraphQLEngineFactory := &Factory{} - t.Run("nested graphql engines", RunTest(` - type Query { - serviceOne(serviceOneArg: String): ServiceOneResponse - anotherServiceOne(anotherServiceOneArg: Int): ServiceOneResponse - reusingServiceOne(reusingServiceOneArg: String): ServiceOneResponse - serviceTwo(serviceTwoArg: Boolean): ServiceTwoResponse - secondServiceTwo(secondServiceTwoArg: Float): ServiceTwoResponse - } - type ServiceOneResponse { - fieldOne: String! - countries: [Country!]! - } - type ServiceTwoResponse { - fieldTwo: String - serviceOneField: String - serviceOneResponse: ServiceOneResponse - } - type Country { - name: String! - } - `, ` - query NestedQuery ($firstArg: String, $secondArg: Boolean, $thirdArg: Int, $fourthArg: Float){ - serviceOne(serviceOneArg: $firstArg) { - fieldOne - countries { - name - } - } - serviceTwo(serviceTwoArg: $secondArg){ - fieldTwo - serviceOneResponse { - fieldOne - } - } - anotherServiceOne(anotherServiceOneArg: $thirdArg){ - fieldOne - } - secondServiceTwo(secondServiceTwoArg: $fourthArg){ - fieldTwo - serviceOneField - } - reusingServiceOne(reusingServiceOneArg: $firstArg){ - fieldOne - } - } - `, "NestedQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://service.one","body":{"query":"query($firstArg: String, $thirdArg: Int){serviceOne(serviceOneArg: $firstArg){fieldOne} anotherServiceOne(anotherServiceOneArg: $thirdArg){fieldOne} reusingServiceOne(reusingServiceOneArg: $firstArg){fieldOne}}","variables":{"thirdArg":$$1$$,"firstArg":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"firstArg"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"thirdArg"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["integer","null"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - &resolve.SingleFetch{ - BufferId: 2, - Input: `{"method":"POST","url":"https://service.two","body":{"query":"query($secondArg: Boolean, $fourthArg: Float){serviceTwo(serviceTwoArg: $secondArg){fieldTwo serviceOneField} secondServiceTwo(secondServiceTwoArg: $fourthArg){fieldTwo serviceOneField}}","variables":{"fourthArg":$$1$$,"secondArg":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"secondArg"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean","null"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"fourthArg"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["number","null"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - }, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("serviceOne"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"serviceOne"}, - - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: &Source{}, - Input: `{"method":"POST","url":"https://country.service","body":{"query":"{countries {name}}"}}`, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - - Fields: []*resolve.Field{ - { - Name: []byte("fieldOne"), - Value: &resolve.String{ - Path: []string{"fieldOne"}, - }, - }, - { - Name: []byte("countries"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Array{ - Path: []string{"countries"}, - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("serviceTwo"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"serviceTwo"}, - Fetch: &resolve.SingleFetch{ - BufferId: 3, - DataSource: &Source{}, - Input: `{"method":"POST","url":"https://service.one","body":{"query":"query($a: String){serviceOneResponse: serviceOne(serviceOneArg: $a){fieldOne}}","variables":{"a":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"serviceOneField"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - Name: []byte("fieldTwo"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"fieldTwo"}, - }, - }, - { - HasBuffer: true, - BufferID: 3, - Name: []byte("serviceOneResponse"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"serviceOneResponse"}, - Fields: []*resolve.Field{ - { - Name: []byte("fieldOne"), - Value: &resolve.String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("anotherServiceOne"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"anotherServiceOne"}, - Fields: []*resolve.Field{ - { - Name: []byte("fieldOne"), - Value: &resolve.String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - { - BufferID: 2, - HasBuffer: true, - Name: []byte("secondServiceTwo"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"secondServiceTwo"}, - Fields: []*resolve.Field{ - { - Name: []byte("fieldTwo"), - Value: &resolve.String{ - Path: []string{"fieldTwo"}, - Nullable: true, - }, - }, - { - Name: []byte("serviceOneField"), - Value: &resolve.String{ - Path: []string{"serviceOneField"}, - Nullable: true, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("reusingServiceOne"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"reusingServiceOne"}, - Fields: []*resolve.Field{ - { - Name: []byte("fieldOne"), - Value: &resolve.String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"serviceOne", "anotherServiceOne", "reusingServiceOne"}, - }, - { - TypeName: "ServiceTwoResponse", - FieldNames: []string{"serviceOneResponse"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "ServiceOneResponse", - FieldNames: []string{"fieldOne"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://service.one", - }, - }), - Factory: nestedGraphQLEngineFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"serviceTwo", "secondServiceTwo"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "ServiceTwoResponse", - FieldNames: []string{"fieldTwo", "serviceOneField"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://service.two", - }, - }), - Factory: nestedGraphQLEngineFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "ServiceOneResponse", - FieldNames: []string{"countries"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Country", - FieldNames: []string{"name"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://country.service", - }, - }), - Factory: nestedGraphQLEngineFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "ServiceTwoResponse", - FieldName: "serviceOneResponse", - Path: []string{"serviceOne"}, - RequiresFields: []string{"serviceOneField"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "serviceOneArg", - SourceType: plan.ObjectFieldSource, - SourcePath: []string{"serviceOneField"}, - }, - }, - }, - { - TypeName: "Query", - FieldName: "serviceTwo", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "serviceTwoArg", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "secondServiceTwo", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "secondServiceTwoArg", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "serviceOne", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "serviceOneArg", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "reusingServiceOne", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "reusingServiceOneArg", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "anotherServiceOne", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "anotherServiceOneArg", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("mutation with variables in array object argument", RunTest( - todoSchema, - `mutation AddTask($title: String!, $completed: Boolean!, $name: String! @fromClaim(name: "sub")) { - addTask(input: [{titleSets: [[$title]], completed: $completed, user: {name: $name}}]){ - task { - id - title - completed - } - } - }`, - "AddTask", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://graphql.service","body":{"query":"mutation($title: String!, $completed: Boolean!, $name: String!){addTask(input: [{titleSets: [[$title]],completed: $completed,user: {name: $name}}]){task {id title completed}}}","variables":{"name":$$2$$,"completed":$$1$$,"title":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"title"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"completed"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"name"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DisallowSingleFlight: true, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("addTask"), - Value: &resolve.Object{ - Path: []string{"addTask"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("task"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"task"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("completed"), - Value: &resolve.Boolean{ - Path: []string{"completed"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{"addTask"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "AddTaskPayload", - FieldNames: []string{"task"}, - }, - { - TypeName: "Task", - FieldNames: []string{"id", "title", "completed"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://graphql.service", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "addTask", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "input", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("inline object value with arguments", RunTest(` - schema { - mutation: Mutation - } - type Mutation { - createUser(input: CreateUserInput!): CreateUser - } - input CreateUserInput { - user: UserInput - } - input UserInput { - id: String - username: String - } - type CreateUser { - user: User - } - type User { - id: String - username: String - createdDate: String - } - directive @fromClaim(name: String) on VARIABLE_DEFINITION - `, ` - mutation Register($name: String $id: String @fromClaim(name: "sub")) { - createUser(input: {user: {id: $id username: $name}}){ - user { - id - username - createdDate - } - } - }`, - "Register", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"https://user.service","body":{"query":"mutation($id: String, $name: String){createUser(input: {user: {id: $id,username: $name}}){user {id username createdDate}}}","variables":{"name":$$1$$,"id":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"name"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DisallowSingleFlight: true, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("createUser"), - Value: &resolve.Object{ - Nullable: true, - Path: []string{"createUser"}, - Fields: []*resolve.Field{ - { - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - Nullable: true, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - Nullable: true, - }, - }, - { - Name: []byte("createdDate"), - Value: &resolve.String{ - Path: []string{"createdDate"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{"createUser"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "CreateUser", - FieldNames: []string{"user"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username", "createdDate"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://user.service", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "createUser", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "input", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("mutation with union response", RunTest(wgSchema, ` - mutation CreateNamespace($name: String! $personal: Boolean!) { - __typename - namespaceCreate(input: {name: $name, personal: $personal}){ - __typename - ... on NamespaceCreated { - namespace { - id - name - } - } - ... on Error { - code - message - } - } - }`, "CreateNamespace", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://api.com","body":{"query":"mutation($name: String!, $personal: Boolean!){__typename namespaceCreate(input: {name: $name,personal: $personal}){__typename ... on NamespaceCreated {namespace {id name}} ... on Error {code message}}}","variables":{"personal":$$1$$,"name":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"name"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"personal"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - ), - DisallowSingleFlight: true, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("namespaceCreate"), - HasBuffer: true, - BufferID: 0, - Value: &resolve.Object{ - Path: []string{"namespaceCreate"}, - Fields: []*resolve.Field{ - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - OnTypeNames: [][]byte{[]byte("NamespaceCreated")}, - Name: []byte("namespace"), - Value: &resolve.Object{ - Path: []string{"namespace"}, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - Nullable: false, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: false, - }, - }, - }, - }, - }, - { - OnTypeNames: [][]byte{[]byte("Error")}, - Name: []byte("code"), - Value: &resolve.String{ - Path: []string{"code"}, - }, - }, - { - OnTypeNames: [][]byte{[]byte("Error")}, - Name: []byte("message"), - Value: &resolve.String{ - Path: []string{"message"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{ - "namespaceCreate", - }, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "NamespaceCreated", - FieldNames: []string{ - "namespace", - }, - }, - { - TypeName: "Namespace", - FieldNames: []string{"id", "name"}, - }, - { - TypeName: "Error", - FieldNames: []string{"code", "message"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://api.com", - Method: "POST", - }, - Subscription: SubscriptionConfiguration{ - URL: "ws://api.com", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "namespaceCreate", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "input", - SourceType: plan.FieldArgumentSource, - }, - }, - DisableDefaultMapping: false, - Path: []string{}, - }, - }, - DisableResolveFieldPositions: true, - DefaultFlushIntervalMillis: 500, - })) - - t.Run("mutation with single __typename field on union", RunTest(wgSchema, ` - mutation CreateNamespace($name: String! $personal: Boolean!) { - namespaceCreate(input: {name: $name, personal: $personal}){ - __typename - } - }`, "CreateNamespace", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://api.com","body":{"query":"mutation($name: String!, $personal: Boolean!){namespaceCreate(input: {name: $name,personal: $personal}){__typename}}","variables":{"personal":$$1$$,"name":$$0$$}}}`, - DataSource: &Source{}, - DisallowSingleFlight: true, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"name"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"personal"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - Name: []byte("namespaceCreate"), - HasBuffer: true, - BufferID: 0, - Value: &resolve.Object{ - Path: []string{"namespaceCreate"}, - Fields: []*resolve.Field{ - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - }}}, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{ - "namespaceCreate", - }, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "NamespaceCreated", - FieldNames: []string{ - "namespace", - }, - }, - { - TypeName: "Namespace", - FieldNames: []string{"id", "name"}, - }, - { - TypeName: "Error", - FieldNames: []string{"code", "message"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://api.com", - Method: "POST", - }, - Subscription: SubscriptionConfiguration{ - URL: "ws://api.com", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "namespaceCreate", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "input", - SourceType: plan.FieldArgumentSource, - }, - }, - DisableDefaultMapping: false, - Path: []string{}, - }, - }, - DisableResolveFieldPositions: true, - DefaultFlushIntervalMillis: 500, - })) - - factory := &Factory{ - HTTPClient: http.DefaultClient, - } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - t.Run("Subscription", runTestOnTestDefinition(` - subscription RemainingJedis { - remainingJedis - } - `, "RemainingJedis", &plan.SubscriptionResponsePlan{ - Response: &resolve.GraphQLSubscription{ - Trigger: resolve.GraphQLSubscriptionTrigger{ - Input: []byte(`{"url":"wss://swapi.com/graphql","body":{"query":"subscription{remainingJedis}"}}`), - Source: &SubscriptionSource{ - NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, ctx), - }, - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("remainingJedis"), - Value: &resolve.Integer{ - Path: []string{"remainingJedis"}, - Nullable: false, - }, - }, - }, - }, - }, - }, - }, testWithFactory(factory))) - - t.Run("Subscription with variables", RunTest(` - type Subscription { - foo(bar: String): Int! - } -`, ` - subscription SubscriptionWithVariables { - foo(bar: "baz") - } - `, "SubscriptionWithVariables", &plan.SubscriptionResponsePlan{ - Response: &resolve.GraphQLSubscription{ - Trigger: resolve.GraphQLSubscriptionTrigger{ - Input: []byte(`{"url":"wss://swapi.com/graphql","body":{"query":"subscription($a: String){foo(bar: $a)}","variables":{"a":$$0$$}}}`), - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - Source: &SubscriptionSource{ - client: NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, ctx), - }, - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("foo"), - Value: &resolve.Integer{ - Path: []string{"foo"}, - Nullable: false, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Subscription", - FieldNames: []string{"foo"}, - }, - }, - Custom: ConfigJson(Configuration{ - Subscription: SubscriptionConfiguration{ - URL: "wss://swapi.com/graphql", - }, - }), - Factory: factory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Subscription", - FieldName: "foo", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "bar", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - batchFactory := NewBatchFactory() - federationFactory := &Factory{BatchFactory: batchFactory} - t.Run("federation", RunTest(federationTestSchema, - ` query MyReviews { - me { - id - username - reviews { - body - author { - id - username - } - product { - name - price - reviews { - body - author { - id - username - } - } - } - } - } - }`, - "MyReviews", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{me {id username}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {reviews {body author {id username} product {upc}}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("author"), - Value: &resolve.Object{ - Path: []string{"author"}, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - }, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 2, - Input: `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on Product {name price}}}","variables":{"representations":[{"upc":$$0$$,"__typename":"Product"}]}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"upc"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 3, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on Product {reviews {body author {id username}}}}}","variables":{"representations":[{"upc":$$0$$,"__typename":"Product"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"upc"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("price"), - Value: &resolve.Integer{ - Path: []string{"price"}, - }, - }, - { - HasBuffer: true, - BufferID: 3, - Name: []byte("reviews"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"reviews"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("author"), - Value: &resolve.Object{ - Path: []string{"author"}, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {me: User} type User @key(fields: \"id\"){ id: ID! username: String!}", - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"topProducts"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"updatedPrice"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://product.service", - }, - Subscription: SubscriptionConfiguration{ - URL: "ws://product.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {topProducts(first: Int = 5): [Product]} type Product @key(fields: \"upc\") {upc: String! price: Int!}", - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - { - TypeName: "Product", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"body", "author", "product"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "type Review { body: String! author: User! @provides(fields: \"username\") product: Product! } extend type User @key(fields: \"id\") { id: ID! @external reviews: [Review] } extend type Product @key(fields: \"upc\") { upc: String! @external reviews: [Review] }", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "topProducts", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "first", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Product", - FieldName: "name", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product", - FieldName: "price", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product", - FieldName: "reviews", - RequiresFields: []string{"upc"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("complex nested federation", RunTest(complexFederationSchema, - ` query User { - user(id: "2") { - id - name { - first - last - } - username - birthDate - vehicle { - id - description - price - __typename - } - account { - ... on PasswordAccount { - email - } - ... on SMSAccount { - number - } - } - metadata { - name - address - description - } - ssn - } - }`, - "User", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"query($a: ID!){user(id: $a){id name {first last} username birthDate __typename account {__typename ... on PasswordAccount {email} ... on SMSAccount {number}} metadata {name address description} ssn}}","variables":{"a":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {vehicle {id description price}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.Object{ - Path: []string{"name"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("first"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"first"}, - }, - }, - { - Name: []byte("last"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"last"}, - }, - }, - }, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - Nullable: true, - }, - }, - { - Name: []byte("birthDate"), - Value: &resolve.String{ - Path: []string{"birthDate"}, - Nullable: true, - }, - }, - { - Name: []byte("vehicle"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Object{ - Path: []string{"vehicle"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("description"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"description"}, - }, - }, - { - Name: []byte("price"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"price"}, - }, - }, - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - IsTypeName: true, - }, - }, - }, - }, - }, - { - Name: []byte("account"), - Value: &resolve.Object{ - Path: []string{"account"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("email"), - Value: &resolve.String{ - Path: []string{"email"}, - }, - OnTypeNames: [][]byte{[]byte("PasswordAccount")}, - }, - { - Name: []byte("number"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"number"}, - }, - OnTypeNames: [][]byte{[]byte("SMSAccount")}, - }, - }, - }, - }, - { - Name: []byte("metadata"), - Value: &resolve.Array{ - Path: []string{"metadata"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"name"}, - }, - }, - { - Name: []byte("address"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"address"}, - }, - }, - { - Name: []byte("description"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"description"}, - }, - }, - }, - }, - }, - }, - { - Name: []byte("ssn"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"ssn"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "username", "birthDate", "metadata", "ssn"}, - }, - { - TypeName: "UserMetadata", - FieldNames: []string{"name", "address", "description"}, - }, - { - TypeName: "Name", - FieldNames: []string{"first", "last"}, - }, - { - TypeName: "PasswordAccount", - FieldNames: []string{"email"}, - }, - { - TypeName: "SMSAccount", - FieldNames: []string{"number"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query { me: User user(id: ID!): User} extend type Mutation { login( username: String! password: String! ): User} type User @key(fields: \"id\") { id: ID! name: Name username: String birthDate(locale: String): String account: AccountType metadata: [UserMetadata] ssn: String} type Name { first: String last: String } type PasswordAccount @key(fields: \"email\") { email: String! } type SMSAccount @key(fields: \"number\") { number: String } union AccountType = PasswordAccount | SMSAccounttype UserMetadata { name: String address: String description: String }", - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"vehicle"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Vehicle", - FieldNames: []string{"id", "name", "description", "price"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://product.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query { product(upc: String!): Product vehicle(id: String!): Vehicle topProducts(first: Int = 5): [Product] topCars(first: Int = 5): [Car]} extend type Subscription { updatedPrice: Product! updateProductPrice(upc: String!): Product! stock: [Product!]} type Ikea { asile: Int} type Amazon { referrer: String } union Brand = Ikea | Amazon interface Product { upc: String! sku: String! name: String price: String details: ProductDetails inStock: Int! } interface ProductDetails { country: String} type ProductDetailsFurniture implements ProductDetails { country: String color: String} type ProductDetailsBook implements ProductDetails { country: String pages: Int } type Furniture implements Product @key(fields: \"upc\") @key(fields: \"sku\") { upc: String! sku: String! name: String price: String brand: Brand metadata: [MetadataOrError] details: ProductDetailsFurniture inStock: Int!} interface Vehicle { id: String! description: String price: String } type Car implements Vehicle @key(fields: \"id\") { id: String! description: String price: String} type Van implements Vehicle @key(fields: \"id\") { id: String! description: String price: String } union Thing = Car | Ikea extend type User @key(fields: \"id\") { id: ID! @external vehicle: Vehicle thing: Thing} type KeyValue { key: String! value: String! } type Error { code: Int message: String} union MetadataOrError = KeyValue | Error", - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "user", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "User", - FieldName: "vehicle", - RequiresFields: []string{"id"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("complex nested federation different order", RunTest(complexFederationSchema, - ` query User { - user(id: "2") { - id - name { - first - last - } - username - birthDate - account { - ... on PasswordAccount { - email - } - ... on SMSAccount { - number - } - } - metadata { - name - address - description - } - vehicle { - id - description - price - __typename - } - ssn - } - }`, - "User", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"query($a: ID!){user(id: $a){id name {first last} username birthDate account {__typename ... on PasswordAccount {email} ... on SMSAccount {number}} metadata {name address description} __typename ssn}}","variables":{"a":$$0$$}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {vehicle {id description price}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.Object{ - Path: []string{"name"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("first"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"first"}, - }, - }, - { - Name: []byte("last"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"last"}, - }, - }, - }, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - Nullable: true, - }, - }, - { - Name: []byte("birthDate"), - Value: &resolve.String{ - Path: []string{"birthDate"}, - Nullable: true, - }, - }, - { - Name: []byte("account"), - Value: &resolve.Object{ - Path: []string{"account"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("email"), - Value: &resolve.String{ - Path: []string{"email"}, - }, - OnTypeNames: [][]byte{[]byte("PasswordAccount")}, - }, - { - Name: []byte("number"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"number"}, - }, - OnTypeNames: [][]byte{[]byte("SMSAccount")}, - }, - }, - }, - }, - { - Name: []byte("metadata"), - Value: &resolve.Array{ - Path: []string{"metadata"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"name"}, - }, - }, - { - Name: []byte("address"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"address"}, - }, - }, - { - Name: []byte("description"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"description"}, - }, - }, - }, - }, - }, - }, - { - Name: []byte("vehicle"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Object{ - Path: []string{"vehicle"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("description"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"description"}, - }, - }, - { - Name: []byte("price"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"price"}, - }, - }, - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - IsTypeName: true, - }, - }, - }, - }, - }, - { - Name: []byte("ssn"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"ssn"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "username", "birthDate", "metadata", "ssn"}, - }, - { - TypeName: "UserMetadata", - FieldNames: []string{"name", "address", "description"}, - }, - { - TypeName: "Name", - FieldNames: []string{"first", "last"}, - }, - { - TypeName: "PasswordAccount", - FieldNames: []string{"email"}, - }, - { - TypeName: "SMSAccount", - FieldNames: []string{"number"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query { me: User user(id: ID!): User} extend type Mutation { login( username: String! password: String! ): User} type User @key(fields: \"id\") { id: ID! name: Name username: String birthDate(locale: String): String account: AccountType metadata: [UserMetadata] ssn: String} type Name { first: String last: String } type PasswordAccount @key(fields: \"email\") { email: String! } type SMSAccount @key(fields: \"number\") { number: String } union AccountType = PasswordAccount | SMSAccounttype UserMetadata { name: String address: String description: String }", - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"vehicle"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Vehicle", - FieldNames: []string{"id", "name", "description", "price"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://product.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query { product(upc: String!): Product vehicle(id: String!): Vehicle topProducts(first: Int = 5): [Product] topCars(first: Int = 5): [Car]} extend type Subscription { updatedPrice: Product! updateProductPrice(upc: String!): Product! stock: [Product!]} type Ikea { asile: Int} type Amazon { referrer: String } union Brand = Ikea | Amazon interface Product { upc: String! sku: String! name: String price: String details: ProductDetails inStock: Int! } interface ProductDetails { country: String} type ProductDetailsFurniture implements ProductDetails { country: String color: String} type ProductDetailsBook implements ProductDetails { country: String pages: Int } type Furniture implements Product @key(fields: \"upc\") @key(fields: \"sku\") { upc: String! sku: String! name: String price: String brand: Brand metadata: [MetadataOrError] details: ProductDetailsFurniture inStock: Int!} interface Vehicle { id: String! description: String price: String } type Car implements Vehicle @key(fields: \"id\") { id: String! description: String price: String} type Van implements Vehicle @key(fields: \"id\") { id: String! description: String price: String } union Thing = Car | Ikea extend type User @key(fields: \"id\") { id: ID! @external vehicle: Vehicle thing: Thing} type KeyValue { key: String! value: String! } type Error { code: Int message: String} union MetadataOrError = KeyValue | Error", - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "user", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - Path: []string{"user"}, - }, - { - TypeName: "User", - FieldName: "vehicle", - Path: []string{"vehicle"}, - RequiresFields: []string{"id"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("federation with variables", RunTest(federationTestSchema, - ` query MyReviews($publicOnly: Boolean!, $someSkipCondition: Boolean!) { - me { - reviews { - body - notes @skip(if: $someSkipCondition) - likes(filterToPublicOnly: $publicOnly) - } - } - }`, - "MyReviews", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{me {id}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!, $someSkipCondition: Boolean!, $publicOnly: Boolean!){_entities(representations: $representations){__typename ... on User {reviews {body notes @skip(if: $someSkipCondition) likes(filterToPublicOnly: $publicOnly)}}}}","variables":{"publicOnly":$$2$$,"someSkipCondition":$$1$$,"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"someSkipCondition"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"publicOnly"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean","null"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("notes"), - Value: &resolve.String{ - Path: []string{"notes"}, - Nullable: true, - }, - SkipDirectiveDefined: true, - SkipVariableName: "someSkipCondition", - }, - { - Name: []byte("likes"), - Value: &resolve.String{ - Path: []string{"likes"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {me: User} type User @key(fields: \"id\"){ id: ID! }", - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"body", "notes", "likes"}, - }, - { - TypeName: "User", - FieldNames: []string{"id"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "type Review { body: String! notes: String likes(filterToPublicOnly: Boolean): Int! } extend type User @key(fields: \"id\") { id: ID! @external reviews: [Review] }", - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Review", - FieldName: "likes", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "filterToPublicOnly", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("federation with variables and renamed types", RunTest(federationTestSchema, - ` query MyReviews($publicOnly: Boolean!, $someSkipCondition: Boolean!) { - me { - reviews { - body - notes @skip(if: $someSkipCondition) - likes(filterToPublicOnly: $publicOnly) - } - } - }`, - "MyReviews", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{me {id}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!, $someSkipCondition: Boolean!, $publicOnly: XBoolean!){_entities(representations: $representations){__typename ... on User {reviews {body notes @skip(if: $someSkipCondition) likes(filterToPublicOnly: $publicOnly)}}}}","variables":{"publicOnly":$$2$$,"someSkipCondition":$$1$$,"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"someSkipCondition"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"publicOnly"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["boolean","null"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("notes"), - Value: &resolve.String{ - Path: []string{"notes"}, - Nullable: true, - }, - SkipDirectiveDefined: true, - SkipVariableName: "someSkipCondition", - }, - { - Name: []byte("likes"), - Value: &resolve.String{ - Path: []string{"likes"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {me: User} type User @key(fields: \"id\"){ id: ID! }", - }, - UpstreamSchema: federationTestSchemaWithRename, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"body", "notes", "likes"}, - }, - { - TypeName: "User", - FieldNames: []string{"id"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "scalar XBoolean type Review { body: String! notes: String likes(filterToPublicOnly: XBoolean!): Int! } extend type User @key(fields: \"id\") { id: ID! @external reviews: [Review] }", - }, - UpstreamSchema: federationTestSchemaWithRename, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Review", - FieldName: "likes", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "filterToPublicOnly", - SourceType: plan.FieldArgumentSource, - RenameTypeTo: "XBoolean", - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("federated entity with requires", RunTest(requiredFieldTestSchema, - ` query QueryWithRequiredFields { - serviceOne { - serviceTwoFieldOne # @requires(fields: "serviceOneFieldOne") - serviceTwoFieldTwo # @requires(fields: "serviceOneFieldTwo") - } - }`, - "QueryWithRequiredFields", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - // Should fetch the federation key as well as all the required fields. - Input: `{"method":"POST","url":"http://one.service","body":{"query":"{serviceOne {id serviceOneFieldOne serviceOneFieldTwo}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("serviceOne"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - // The required fields are present in the representations. - Input: `{"method":"POST","url":"http://two.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on ServiceOneType {serviceTwoFieldOne serviceTwoFieldTwo}}}","variables":{"representations":[{"serviceOneFieldTwo":$$2$$,"serviceOneFieldOne":$$1$$,"id":$$0$$,"__typename":"ServiceOneType"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ObjectVariable{ - Path: []string{"serviceOneFieldOne"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ObjectVariable{ - Path: []string{"serviceOneFieldTwo"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"serviceOne"}, - Nullable: true, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 1, - Name: []byte("serviceTwoFieldOne"), - Value: &resolve.String{ - Path: []string{"serviceTwoFieldOne"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("serviceTwoFieldTwo"), - Value: &resolve.String{ - Path: []string{"serviceTwoFieldTwo"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"serviceOne"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "ServiceOneType", - FieldNames: []string{"id", "serviceOneFieldOne", "serviceOneFieldTwo"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://one.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {serviceOne: ServiceOneType} type ServiceOneType @key(fields: \"id\"){ id: ID! serviceOneFieldOne: String! serviceOneFieldTwo: String!}", - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "ServiceOneType", - FieldNames: []string{"serviceTwoFieldOne", "serviceTwoFieldTwo"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "ServiceOneType", - FieldNames: []string{"id", "serviceOneFieldOne", "serviceOneFieldTwo"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://two.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type ServiceOneType @key(fields: \"id\") { id: ID! @external serviceOneFieldOne: String! @external serviceOneFieldTwo: String! @external serviceTwoFieldOne: String! @requires(fields: \"serviceOneFieldOne\") serviceTwoFieldTwo: String! @requires(fields: \"serviceOneFieldTwo\")}", - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "ServiceOneType", - FieldName: "serviceTwoFieldOne", - RequiresFields: []string{"id", "serviceOneFieldOne"}, - }, - { - TypeName: "ServiceOneType", - FieldName: "serviceTwoFieldTwo", - RequiresFields: []string{"id", "serviceOneFieldTwo"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("federation with renamed schema", RunTest(renamedFederationTestSchema, - ` query MyReviews { - api_me { - id - username - reviews { - body - author { - id - username - } - product { - name - price - reviews { - body - author { - id - username - } - } - } - } - } - }`, - "MyReviews", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{api_me: me {id username}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("api_me"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {reviews {body author {id username} product {upc}}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"api_me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("author"), - Value: &resolve.Object{ - Path: []string{"author"}, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - }, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 2, - Input: `{"method":"POST","url":"http://product.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on Product {name price}}}","variables":{"representations":[{"upc":$$0$$,"__typename":"Product"}]}}}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"upc"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 3, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on Product {reviews {body author {id username}}}}}","variables":{"representations":[{"upc":$$0$$,"__typename":"Product"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"upc"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("price"), - Value: &resolve.Integer{ - Path: []string{"price"}, - }, - }, - { - HasBuffer: true, - BufferID: 3, - Name: []byte("reviews"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"reviews"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("author"), - Value: &resolve.Object{ - Path: []string{"author"}, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"api_me"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User_api", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {me: User} type User @key(fields: \"id\"){ id: ID! username: String!}", - }, - UpstreamSchema: federationTestSchema, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"api_topProducts"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"api_updatedPrice"}, - }, - { - TypeName: "Product_api", - FieldNames: []string{"upc", "name", "price"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Product_api", - FieldNames: []string{"upc", "name", "price"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://product.service", - }, - Subscription: SubscriptionConfiguration{ - URL: "ws://product.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "extend type Query {topProducts(first: Int = 5): [Product]} type Product @key(fields: \"upc\") {upc: String! price: Int!}", - }, - UpstreamSchema: federationTestSchema, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User_api", - FieldNames: []string{"reviews"}, - }, - { - TypeName: "Product_api", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review_api", - FieldNames: []string{"body", "author", "product"}, - }, - { - TypeName: "User_api", - FieldNames: []string{"id", "username"}, - }, - { - TypeName: "Product_api", - FieldNames: []string{"upc"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: "type Review { body: String! author: User! @provides(fields: \"username\") product: Product! } extend type User @key(fields: \"id\") { id: ID! @external reviews: [Review] } extend type Product @key(fields: \"upc\") { upc: String! @external reviews: [Review] }", - }, - UpstreamSchema: federationTestSchema, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "topProducts_api", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "first", - SourceType: plan.FieldArgumentSource, - }, - }, - Path: []string{"topProducts"}, - }, - { - TypeName: "Query", - FieldName: "api_me", - Path: []string{"me"}, - }, - { - TypeName: "User_api", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Product_api", - FieldName: "name", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product_api", - FieldName: "price", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product_api", - FieldName: "reviews", - RequiresFields: []string{"upc"}, - }, - }, - DisableResolveFieldPositions: true, - Types: []plan.TypeConfiguration{ - { - TypeName: "User_api", - RenameTo: "User", - }, - { - TypeName: "Product_api", - RenameTo: "Product", - }, - { - TypeName: "Review_api", - RenameTo: "Review", - }, - }, - })) - - t.Run("federation with object query and inline fragment", RunTest(federatedSchemaWithInterfaceQuery, - ` - query ObjectQuery { - me { - id - __typename - ... on User { - uid: id - username - reviews { - body - } - } - } - }`, - "ObjectQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{me {__typename id uid: id username}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {reviews {body id}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("uid"), - Value: &resolve.String{ - Path: []string{"uid"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "self"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Identity", - FieldNames: []string{"id"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: userSDLWithInterface, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"id", "body", "author"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: reviewSDL, - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Review", - FieldName: "body", - RequiresFields: []string{"id"}, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("federation with interface query", RunTest(federatedSchemaWithInterfaceQuery, - ` - query InterfaceQuery { - self { - id - __typename - ... on User { - uid: id - username - reviews { - body - } - } - } - }`, - "InterfaceQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{self {id __typename ... on User {uid: id username}}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("self"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {reviews {body id}}}}","variables":{"representations":[{"id":$$1$$,"__typename":$$0$$}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"__typename"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"self"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("__typename"), - Value: &resolve.String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("uid"), - Value: &resolve.String{ - Path: []string{"uid"}, - }, - OnTypeNames: [][]byte{[]byte("User")}, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - OnTypeNames: [][]byte{[]byte("User")}, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - OnTypeNames: [][]byte{[]byte("User")}, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "self"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Identity", - FieldNames: []string{"id"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: userSDLWithInterface, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"id", "body", "author"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: reviewSDL, - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Review", - FieldName: "body", - RequiresFields: []string{"id"}, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - t.Run("Federation with query returning interface that features nested interfaces", RunTest(federatedSchemaWithInterfaceQuery, - ` - query InterfaceQuery { - self { - ... on User { - reviews { - body - attachment { - ... on Image { - extension - } - ... on Video { - length - } - } - } - } - } - }`, - "InterfaceQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{self {__typename ... on User {id}}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("self"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://review.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {reviews {body attachment {__typename ... on Image {extension} ... on Video {length}} id}}}}","variables":{"representations":[{"id":$$1$$,"__typename":$$0$$}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"__typename"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"self"}, - Nullable: true, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("attachment"), - Value: &resolve.Object{ - Path: []string{"attachment"}, - Fields: []*resolve.Field{ - { - Name: []byte("extension"), - Value: &resolve.String{ - Path: []string{"extension"}, - }, - OnTypeNames: [][]byte{[]byte("Image")}, - }, - { - Name: []byte("length"), - Value: &resolve.String{ - Path: []string{"length"}, - }, - OnTypeNames: [][]byte{[]byte("Video")}, - }, - }, - }, - }, - }, - }, - }, - OnTypeNames: [][]byte{[]byte("User")}, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"self"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: userSDLWithInterface, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - { - TypeName: "Image", - FieldNames: []string{"extension"}, - }, - { - TypeName: "Video", - FieldNames: []string{"length"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"id", "body", "attachment"}, - }, - { - TypeName: "User", - FieldNames: []string{"username"}, - }, - { - TypeName: "Image", - FieldNames: []string{"extension"}, - }, - { - TypeName: "Video", - FieldNames: []string{"length"}, - }, - }, - Factory: federationFactory, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://review.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: reviewSDL, - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Review", - FieldName: "body", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Review", - FieldName: "attachment", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Image", - FieldName: "extension", - }, - { - TypeName: "Video", - FieldName: "extension", - }, - }, - DisableResolveFieldPositions: true, - }, - )) - - // When user is an entity, the "pets" field can be both declared and resolved only in the pet subgraph - // This separation of concerns is recommended: https://www.apollographql.com/docs/federation/v1/#separation-of-concerns - t.Run("Federation with interface field query (defined on pet subgraph)", func(t *testing.T) { - t.Run("featuring consecutive inline fragments (shared selection at top)", RunTest( - federatedSchemaWithComplexNestedFragments, - ` - query TestQuery { - user { - username - pets { - name - ... on Cat { - catField - details { - age - } - } - ... on Dog { - dogField - species - } - details { - hasOwner - } - } - } - } - `, - "TestQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{user {username}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://pet.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {pets {name __typename ... on Cat {catField details {age}} ... on Dog {dogField species} details {hasOwner}}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - Name: []byte("pets"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Array{ - Path: []string{"pets"}, - Nullable: false, - Item: &resolve.Object{ - Nullable: false, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("catField"), - Value: &resolve.String{ - Path: []string{"catField"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("details"), - Value: &resolve.Object{ - Path: []string{"details"}, - Fields: []*resolve.Field{ - { - Name: []byte("age"), - Value: &resolve.Integer{ - Path: []string{"age"}, - }, - }, - }, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("dogField"), - Value: &resolve.String{ - Path: []string{"dogField"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("species"), - Value: &resolve.String{ - Path: []string{"species"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("details"), - Value: &resolve.Object{ - Path: []string{"details"}, - Fields: []*resolve.Field{ - { - Name: []byte("hasOwner"), - Value: &resolve.Boolean{ - Path: []string{"hasOwner"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: simpleUserSchema, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"pets"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Details", - FieldNames: []string{"age", "hasOwner"}, - }, - { - TypeName: "Pet", - FieldNames: []string{"name", "species", "details"}, - }, - { - TypeName: "Cat", - FieldNames: []string{"catField", "details"}, - }, - { - TypeName: "Dog", - FieldNames: []string{"dogField", "species"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://pet.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: petSchema, - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "pets", - Path: []string{"pets"}, - RequiresFields: []string{"id"}, - }, - { - TypeName: "Cat", - FieldName: "name", - }, - { - TypeName: "Cat", - FieldName: "catField", - }, - { - TypeName: "Cat", - FieldName: "details", - }, - { - TypeName: "Dog", - FieldName: "name", - }, - { - TypeName: "Dog", - FieldName: "dogField", - }, - { - TypeName: "Dog", - FieldName: "species", - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("featuring consecutive inline fragments (shared selection in middle)", RunTest( - federatedSchemaWithComplexNestedFragments, - ` - query TestQuery { - user { - username - pets { - ... on Cat { - catField - details { - age - } - } - name - ... on Dog { - dogField - species - } - details { - hasOwner - } - } - } - } - `, - "TestQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{user {username}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://pet.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {pets {__typename ... on Cat {catField details {age}} name ... on Dog {dogField species} details {hasOwner}}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - Name: []byte("pets"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Array{ - Path: []string{"pets"}, - Nullable: false, - Item: &resolve.Object{ - Nullable: false, - Fields: []*resolve.Field{ - { - Name: []byte("catField"), - Value: &resolve.String{ - Path: []string{"catField"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("details"), - Value: &resolve.Object{ - Path: []string{"details"}, - Fields: []*resolve.Field{ - { - Name: []byte("age"), - Value: &resolve.Integer{ - Path: []string{"age"}, - }, - }, - }, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("dogField"), - Value: &resolve.String{ - Path: []string{"dogField"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("species"), - Value: &resolve.String{ - Path: []string{"species"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("details"), - Value: &resolve.Object{ - Path: []string{"details"}, - Fields: []*resolve.Field{ - { - Name: []byte("hasOwner"), - Value: &resolve.Boolean{ - Path: []string{"hasOwner"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: simpleUserSchema, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"pets"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Details", - FieldNames: []string{"age", "hasOwner"}, - }, - { - TypeName: "Pet", - FieldNames: []string{"name", "species", "details"}, - }, - { - TypeName: "Cat", - FieldNames: []string{"catField", "details"}, - }, - { - TypeName: "Dog", - FieldNames: []string{"dogField", "species"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://pet.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: petSchema, - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "pets", - Path: []string{"pets"}, - RequiresFields: []string{"id"}, - }, - { - TypeName: "Cat", - FieldName: "name", - }, - { - TypeName: "Cat", - FieldName: "catField", - }, - { - TypeName: "Cat", - FieldName: "details", - }, - { - TypeName: "Dog", - FieldName: "name", - }, - { - TypeName: "Dog", - FieldName: "dogField", - }, - { - TypeName: "Dog", - FieldName: "species", - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("featuring consecutive inline fragments (shared selection at bottom)", RunTest( - federatedSchemaWithComplexNestedFragments, - ` - query TestQuery { - user { - username - pets { - ... on Cat { - catField - details { - age - } - } - ... on Dog { - dogField - species - } - details { - hasOwner - } - name - } - } - } - `, - "TestQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{user {username}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - // Note: __typename is included in the Cat and Dog inline fragments - // because the field were originally themselves in inline fragments - // that were inlined. The additional __typename selections are - // harmless. - Input: `{"method":"POST","url":"http://pet.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {pets {__typename ... on Cat {catField details {age}} ... on Dog {dogField species} details {hasOwner} name}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - Name: []byte("pets"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Array{ - Path: []string{"pets"}, - Nullable: false, - Item: &resolve.Object{ - Nullable: false, - Fields: []*resolve.Field{ - { - Name: []byte("catField"), - Value: &resolve.String{ - Path: []string{"catField"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("details"), - Value: &resolve.Object{ - Path: []string{"details"}, - Fields: []*resolve.Field{ - { - Name: []byte("age"), - Value: &resolve.Integer{ - Path: []string{"age"}, - }, - }, - }, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("dogField"), - Value: &resolve.String{ - Path: []string{"dogField"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("species"), - Value: &resolve.String{ - Path: []string{"species"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("details"), - Value: &resolve.Object{ - Path: []string{"details"}, - Fields: []*resolve.Field{ - { - Name: []byte("hasOwner"), - Value: &resolve.Boolean{ - Path: []string{"hasOwner"}, - }, - }, - }, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: simpleUserSchema, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"pets"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Details", - FieldNames: []string{"age", "hasOwner"}, - }, - { - TypeName: "Pet", - FieldNames: []string{"name", "species", "details"}, - }, - { - TypeName: "Cat", - FieldNames: []string{"catField", "details"}, - }, - { - TypeName: "Dog", - FieldNames: []string{"dogField", "species"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://pet.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: petSchema, - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "pets", - Path: []string{"pets"}, - RequiresFields: []string{"id"}, - }, - { - TypeName: "Cat", - FieldName: "name", - }, - { - TypeName: "Cat", - FieldName: "catField", - }, - { - TypeName: "Cat", - FieldName: "details", - }, - { - TypeName: "Dog", - FieldName: "name", - }, - { - TypeName: "Dog", - FieldName: "dogField", - }, - { - TypeName: "Dog", - FieldName: "species", - }, - }, - DisableResolveFieldPositions: true, - })) - }) - - t.Run("Federation with field query (defined in pet subgraph) featuring consecutive inline union fragments", RunTest( - ` - type Query { - user: User - } - type User { - id: ID! - username: String! - pets: [CatOrDog!]! - } - type Cat { - name: String! - catField: String! - } - type Dog { - name: String! - dogField: String! - } - union CatOrDog = Cat | Dog - `, - ` - query TestQuery { - user { - username - pets { - ... on Cat { - name - catField - } - ... on Dog { - name - dogField - } - } - } - } - `, - "TestQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{user {username id}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://pet.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on User {pets {__typename ... on Cat {name catField} ... on Dog {name dogField}}}}}","variables":{"representations":[{"id":$$0$$,"__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - Name: []byte("pets"), - HasBuffer: true, - BufferID: 1, - Value: &resolve.Array{ - Path: []string{"pets"}, - Nullable: false, - Item: &resolve.Object{ - Nullable: false, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("catField"), - Value: &resolve.String{ - Path: []string{"catField"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - Name: []byte("dogField"), - Value: &resolve.String{ - Path: []string{"dogField"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: simpleUserSchema, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"pets"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Cat", - FieldNames: []string{"name", "catField"}, - }, - { - TypeName: "Dog", - FieldNames: []string{"name", "dogField"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://pet.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: ` - union CatOrDog = Cat | Dog - type Cat { - name: String! - catField: String! - } - type Dog { - name: String! - dogField: String! - } - extend type User @key(fields: "id") { - id: ID! @external - pets: [CatOrDog!]! - } - `, - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "User", - FieldName: "pets", - Path: []string{"pets"}, - RequiresFields: []string{"id"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("Federation with field query (defined in user subgraph) featuring consecutive inline union fragments", RunTest( - ` - type Query { - user: User - } - type User { - username: String! - pets: [CatOrDog!]! - } - type Cat { - id: ID! - name: String! - catField: String! - } - type Dog { - id: ID! - name: String! - dogField: String! - } - union CatOrDog = Cat | Dog - `, - ` - query TestQuery { - user { - username - pets { - ... on Cat { - name - catField - } - ... on Dog { - name - dogField - } - } - } - } - `, - "TestQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://user.service","body":{"query":"{user {username pets {__typename ... on Cat {id} ... on Dog {id}}}}"}}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("user"), - Value: &resolve.Object{ - Path: []string{"user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - Name: []byte("pets"), - Value: &resolve.Array{ - Path: []string{"pets"}, - Nullable: false, - Item: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://pet.service","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){__typename ... on Cat {name catField} ... on Dog {name dogField}}}","variables":{"representations":[{"id":$$1$$,"__typename":$$0$$}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"__typename"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - &resolve.ObjectVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSource: &Source{}, - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - BatchFactory: batchFactory, - }, - Nullable: false, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 1, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("catField"), - Value: &resolve.String{ - Path: []string{"catField"}, - }, - OnTypeNames: [][]byte{[]byte("Cat")}, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("dogField"), - Value: &resolve.String{ - Path: []string{"dogField"}, - }, - OnTypeNames: [][]byte{[]byte("Dog")}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"username", "pets"}, - }, - { - TypeName: "Cat", - FieldNames: []string{"id"}, - }, - { - TypeName: "Dog", - FieldNames: []string{"id"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://user.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: ` - extend type Query { - user: User - } - type User { - username: String! - pets: [CatOrDog!]! - } - extend union CatOrDog = Cat | Dog - extend type Cat @key(fields: "id") { - id: ID! @external - } - extend type Dog @key(fields: "id") { - id: ID! @external - } - `, - }, - }), - Factory: federationFactory, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Cat", - FieldNames: []string{"id", "name", "catField"}, - }, - { - TypeName: "Dog", - FieldNames: []string{"id", "name", "dogField"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://pet.service", - }, - Federation: FederationConfiguration{ - Enabled: true, - ServiceSDL: ` - union CatOrDog = Cat | Dog - type Cat @key(fields: "id") { - id: ID! - name: String! - catField: String! - } - type Dog @key(fields: "id") { - id: ID! - name: String! - dogField: String! - } - `, - }, - }), - Factory: federationFactory, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Cat", - FieldName: "name", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Cat", - FieldName: "catField", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Dog", - FieldName: "name", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Dog", - FieldName: "dogField", - RequiresFields: []string{"id"}, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("custom scalar replacement query", RunTest(starWarsSchema, ` - query MyQuery($droidId: ID!, $reviewId: ID!){ - droid(id: $droidId){ - name - aliased: name - friends { - name - } - primaryFunction - } - review(id: $reviewId){ - stars - } - } - `, "MyQuery", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"https://swapi.com/graphql","header":{"Authorization":["$$2$$"],"Invalid-Template":["{{ request.headers.Authorization }}"]},"body":{"query":"query($droidId: ID!, $reviewId: ReviewID!){droid(id: $droidId){name aliased: name friends {name} primaryFunction} review(id: $reviewId){stars}}","variables":{"reviewId":$$1$$,"droidId":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"droidId"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"reviewId"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("droid"), - Value: &resolve.Object{ - Path: []string{"droid"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("aliased"), - Value: &resolve.String{ - Path: []string{"aliased"}, - }, - }, - { - Name: []byte("friends"), - Value: &resolve.Array{ - Nullable: true, - Path: []string{"friends"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - { - Name: []byte("primaryFunction"), - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("review"), - Value: &resolve.Object{ - Path: []string{"review"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("stars"), - Value: &resolve.Integer{ - Path: []string{"stars"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid", "review", "hero", "stringList", "nestedStringList"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name", "friends"}, - }, - { - TypeName: "Human", - FieldNames: []string{"name", "height", "friends"}, - }, - { - TypeName: "Droid", - FieldNames: []string{"name", "primaryFunction", "friends"}, - }, - { - TypeName: "Review", - FieldNames: []string{"id", "stars", "commentary"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - Header: http.Header{ - "Authorization": []string{"{{ .request.headers.Authorization }}"}, - "Invalid-Template": []string{"{{ request.headers.Authorization }}"}, - }, - }, - UpstreamSchema: starWarsSchemaWithRenamedArgument, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "review", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - RenameTypeTo: "ReviewID", - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) - - t.Run("custom scalar type fields", RunTest(customUserSchema, ` - query Custom($id: ID!) { - custom_user(id: $id) { - id - name - tier - meta { - foo - } - } - } - `, "Custom", &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: &Source{}, - BufferId: 0, - Input: `{"method":"POST","url":"http://localhost:8084/query","body":{"query":"query($id: ID!){custom_user: user(id: $id){id name tier meta}}","variables":{"id":$$0$$}}}`, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - ), - DataSourceIdentifier: []byte("graphql_datasource.Source"), - ProcessResponseConfig: resolve.ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("custom_user"), - Value: &resolve.Object{ - Path: []string{"custom_user"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("tier"), - Value: &resolve.String{ - Nullable: true, - Path: []string{"tier"}, - }, - }, - { - Name: []byte("meta"), - Value: &resolve.Object{ - Path: []string{"meta"}, - Fields: []*resolve.Field{ - { - Name: []byte("foo"), - Value: &resolve.String{ - Path: []string{"foo"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"custom_user"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "custom_User", - FieldNames: []string{"id", "name", "tier", "meta"}, - }, - { - TypeName: "custom_Meta", - FieldNames: []string{"foo"}, - }, - }, - Factory: &Factory{}, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "http://localhost:8084/query", - }, - UpstreamSchema: userSchema, - CustomScalarTypeFields: []SingleTypeField{ - { - TypeName: "custom_User", - FieldName: "meta", - }, - }, - }), - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "custom_user", - Path: []string{"user"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - })) -} - -var errSubscriptionClientFail = errors.New("subscription client fail error") - -type FailingSubscriptionClient struct{} - -func (f FailingSubscriptionClient) Subscribe(_ context.Context, _ GraphQLSubscriptionOptions, _ chan<- []byte) error { - return errSubscriptionClientFail -} - -func TestSubscriptionSource_Start(t *testing.T) { - chatServer := httptest.NewServer(subscriptiontesting.ChatGraphQLEndpointHandler()) - defer chatServer.Close() - - sendChatMessage := func(t *testing.T, username, message string) { - time.Sleep(200 * time.Millisecond) - httpClient := http.Client{} - req, err := http.NewRequest( - http.MethodPost, - chatServer.URL, - bytes.NewBufferString(fmt.Sprintf(`{"variables": {}, "operationName": "SendMessage", "query": "mutation SendMessage { post(roomName: \"#test\", username: \"%s\", text: \"%s\") { id } }"}`, username, message)), - ) - require.NoError(t, err) - - req.Header.Set("Content-Type", "application/json") - resp, err := httpClient.Do(req) - require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) - } - - chatServerSubscriptionOptions := func(t *testing.T, body string) []byte { - var gqlBody GraphQLBody - _ = json.Unmarshal([]byte(body), &gqlBody) - options := GraphQLSubscriptionOptions{ - URL: chatServer.URL, - Body: gqlBody, - Header: nil, - } - - optionsBytes, err := json.Marshal(options) - require.NoError(t, err) - - return optionsBytes - } - - newSubscriptionSource := func(ctx context.Context) SubscriptionSource { - httpClient := http.Client{} - subscriptionSource := SubscriptionSource{client: NewGraphQLSubscriptionClient(&httpClient, http.DefaultClient, ctx)} - return subscriptionSource - } - - t.Run("should return error when input is invalid", func(t *testing.T) { - source := SubscriptionSource{client: FailingSubscriptionClient{}} - err := source.Start(context.Background(), []byte(`{"url": "", "body": "", "header": null}`), nil) - assert.Error(t, err) - }) - - t.Run("should return error when subscription client returns an error", func(t *testing.T) { - source := SubscriptionSource{client: FailingSubscriptionClient{}} - err := source.Start(context.Background(), []byte(`{"url": "", "body": {}, "header": null}`), nil) - assert.Error(t, err) - assert.Equal(t, resolve.ErrUnableToResolve, err) - }) - - t.Run("invalid json: should stop before sending to upstream", func(t *testing.T) { - next := make(chan []byte) - ctx := resolve.NewContext(context.Background()) - defer ctx.Context().Done() - - source := newSubscriptionSource(ctx.Context()) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomName: "#test") { text createdBy } }"}`) - err := source.Start(ctx.Context(), chatSubscriptionOptions, next) - require.ErrorIs(t, err, resolve.ErrUnableToResolve) - }) - - t.Run("invalid syntax (roomNam)", func(t *testing.T) { - next := make(chan []byte) - ctx := resolve.NewContext(context.Background()) - defer ctx.Context().Done() - - source := newSubscriptionSource(ctx.Context()) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomNam: \"#test\") { text createdBy } }"}`) - err := source.Start(ctx.Context(), chatSubscriptionOptions, next) - require.NoError(t, err) - - msg, ok := <-next - assert.True(t, ok) - assert.Equal(t, `{"errors":[{"message":"Unknown argument \"roomNam\" on field \"Subscription.messageAdded\". Did you mean \"roomName\"?","locations":[{"line":1,"column":29}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}},{"message":"Field \"messageAdded\" argument \"roomName\" of type \"String!\" is required, but it was not provided.","locations":[{"line":1,"column":29}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}]}`, string(msg)) - _, ok = <-next - assert.False(t, ok) - }) - - t.Run("should close connection on stop message", func(t *testing.T) { - next := make(chan []byte) - subscriptionLifecycle, cancelSubscription := context.WithCancel(context.Background()) - resolverLifecycle, cancelResolver := context.WithCancel(context.Background()) - defer cancelResolver() - - source := newSubscriptionSource(resolverLifecycle) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomName: \"#test\") { text createdBy } }"}`) - err := source.Start(subscriptionLifecycle, chatSubscriptionOptions, next) - require.NoError(t, err) - - username := "myuser" - message := "hello world!" - go sendChatMessage(t, username, message) - - nextBytes := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"hello world!","createdBy":"myuser"}}}`, string(nextBytes)) - cancelSubscription() - _, ok := <-next - assert.False(t, ok) - }) - - t.Run("should successfully subscribe with chat example", func(t *testing.T) { - next := make(chan []byte) - ctx := resolve.NewContext(context.Background()) - defer ctx.Context().Done() - - source := newSubscriptionSource(ctx.Context()) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomName: \"#test\") { text createdBy } }"}`) - err := source.Start(ctx.Context(), chatSubscriptionOptions, next) - require.NoError(t, err) - - username := "myuser" - message := "hello world!" - go sendChatMessage(t, username, message) - - nextBytes := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"hello world!","createdBy":"myuser"}}}`, string(nextBytes)) - }) -} - -func TestSubscription_GTWS_SubProtocol(t *testing.T) { - chatServer := httptest.NewServer(subscriptiontesting.ChatGraphQLEndpointHandler()) - defer chatServer.Close() - - sendChatMessage := func(t *testing.T, username, message string) { - time.Sleep(200 * time.Millisecond) - httpClient := http.Client{} - req, err := http.NewRequest( - http.MethodPost, - chatServer.URL, - bytes.NewBufferString(fmt.Sprintf(`{"variables": {}, "operationName": "SendMessage", "query": "mutation SendMessage { post(roomName: \"#test\", username: \"%s\", text: \"%s\") { id } }"}`, username, message)), - ) - require.NoError(t, err) - - req.Header.Set("Content-Type", "application/json") - resp, err := httpClient.Do(req) - require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) - } - - chatServerSubscriptionOptions := func(t *testing.T, body string) []byte { - var gqlBody GraphQLBody - _ = json.Unmarshal([]byte(body), &gqlBody) - options := GraphQLSubscriptionOptions{ - URL: chatServer.URL, - Body: gqlBody, - Header: nil, - } - - optionsBytes, err := json.Marshal(options) - require.NoError(t, err) - - return optionsBytes - } - - newSubscriptionSource := func(ctx context.Context) SubscriptionSource { - httpClient := http.Client{} - subscriptionSource := SubscriptionSource{ - client: NewGraphQLSubscriptionClient(&httpClient, http.DefaultClient, ctx, WithWSSubProtocol(ProtocolGraphQLTWS)), - } - return subscriptionSource - } - - t.Run("invalid syntax (roomNam)", func(t *testing.T) { - next := make(chan []byte) - ctx := resolve.NewContext(context.Background()) - defer ctx.Context().Done() - - source := newSubscriptionSource(ctx.Context()) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomNam: \"#test\") { text createdBy } }"}`) - err := source.Start(ctx.Context(), chatSubscriptionOptions, next) - require.NoError(t, err) - - msg, ok := <-next - assert.True(t, ok) - assert.Equal(t, `{"errors":[{"message":"Unknown argument \"roomNam\" on field \"Subscription.messageAdded\". Did you mean \"roomName\"?","locations":[{"line":1,"column":29}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}},{"message":"Field \"messageAdded\" argument \"roomName\" of type \"String!\" is required, but it was not provided.","locations":[{"line":1,"column":29}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}]}`, string(msg)) - _, ok = <-next - assert.False(t, ok) - }) - - t.Run("should close connection on stop message", func(t *testing.T) { - next := make(chan []byte) - subscriptionLifecycle, cancelSubscription := context.WithCancel(context.Background()) - resolverLifecycle, cancelResolver := context.WithCancel(context.Background()) - defer cancelResolver() - - source := newSubscriptionSource(resolverLifecycle) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomName: \"#test\") { text createdBy } }"}`) - err := source.Start(subscriptionLifecycle, chatSubscriptionOptions, next) - require.NoError(t, err) - - username := "myuser" - message := "hello world!" - go sendChatMessage(t, username, message) - - nextBytes := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"hello world!","createdBy":"myuser"}}}`, string(nextBytes)) - cancelSubscription() - _, ok := <-next - assert.False(t, ok) - }) - - t.Run("should successfully subscribe with chat example", func(t *testing.T) { - next := make(chan []byte) - ctx := resolve.NewContext(context.Background()) - defer ctx.Context().Done() - - source := newSubscriptionSource(ctx.Context()) - chatSubscriptionOptions := chatServerSubscriptionOptions(t, `{"variables": {}, "extensions": {}, "operationName": "LiveMessages", "query": "subscription LiveMessages { messageAdded(roomName: \"#test\") { text createdBy } }"}`) - err := source.Start(ctx.Context(), chatSubscriptionOptions, next) - require.NoError(t, err) - - username := "myuser" - message := "hello world!" - go sendChatMessage(t, username, message) - - nextBytes := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"hello world!","createdBy":"myuser"}}}`, string(nextBytes)) - }) -} - -type _fakeDataSource struct { - data []byte - artificialLatency time.Duration -} - -func (f *_fakeDataSource) Load(_ context.Context, _ []byte, w io.Writer) (err error) { - if f.artificialLatency != 0 { - time.Sleep(f.artificialLatency) - } - _, err = w.Write(f.data) - return -} - -func FakeDataSource(data string) *_fakeDataSource { - return &_fakeDataSource{ - data: []byte(data), - } -} - -type runTestOnTestDefinitionOptions func(planConfig *plan.Configuration, extraChecks *[]CheckFunc) - -func testWithFactory(factory *Factory) runTestOnTestDefinitionOptions { - return func(planConfig *plan.Configuration, extraChecks *[]CheckFunc) { - for _, ds := range planConfig.DataSources { - ds.Factory = factory - } - } -} - -// nolint:deadcode,unused -func testWithExtraChecks(extraChecks ...CheckFunc) runTestOnTestDefinitionOptions { - return func(planConfig *plan.Configuration, availableChecks *[]CheckFunc) { - *availableChecks = append(*availableChecks, extraChecks...) - } -} - -func runTestOnTestDefinition(operation, operationName string, expectedPlan plan.Plan, options ...runTestOnTestDefinitionOptions) func(t *testing.T) { - extraChecks := make([]CheckFunc, 0) - config := plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"hero", "heroByBirthdate", "droid", "droids", "search", "stringList", "nestedStringList"}, - }, - { - TypeName: "Mutation", - FieldNames: []string{"createReview"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"remainingJedis"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"id", "stars", "commentary"}, - }, - { - TypeName: "Character", - FieldNames: []string{"name", "friends"}, - }, - { - TypeName: "Human", - FieldNames: []string{"name", "height", "friends"}, - }, - { - TypeName: "Droid", - FieldNames: []string{"name", "primaryFunction", "friends"}, - }, - { - TypeName: "Starship", - FieldNames: []string{"name", "length"}, - }, - }, - Custom: ConfigJson(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://swapi.com/graphql", - Method: "POST", - }, - Subscription: SubscriptionConfiguration{ - URL: "wss://swapi.com/graphql", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "heroByBirthdate", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "birthdate", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "droids", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "ids", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "search", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - } - - for _, opt := range options { - opt(&config, &extraChecks) - } - - return RunTest(testDefinition, operation, operationName, expectedPlan, config, extraChecks...) -} - -func TestSource_Load(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - body, _ := io.ReadAll(r.Body) - _, _ = fmt.Fprint(w, string(body)) - })) - defer ts.Close() - - t.Run("unnull_variables", func(t *testing.T) { - var ( - src = &Source{httpClient: &http.Client{}} - serverUrl = ts.URL - variables = []byte(`{"a": null, "b": "b", "c": {}}`) - ) - - t.Run("should remove null variables and empty objects when flag is set", func(t *testing.T) { - var input []byte - input = httpclient.SetInputBodyWithPath(input, variables, "variables") - input = httpclient.SetInputURL(input, []byte(serverUrl)) - input = httpclient.SetInputFlag(input, httpclient.UNNULLVARIABLES) - buf := bytes.NewBuffer(nil) - - require.NoError(t, src.Load(context.Background(), input, buf)) - assert.Equal(t, `{"variables":{"b":"b"}}`, buf.String()) - }) - - t.Run("should only compact variables when no flag set", func(t *testing.T) { - var input []byte - input = httpclient.SetInputBodyWithPath(input, variables, "variables") - input = httpclient.SetInputURL(input, []byte(serverUrl)) - - buf := bytes.NewBuffer(nil) - - require.NoError(t, src.Load(context.Background(), input, buf)) - assert.Equal(t, `{"variables":{"a":null,"b":"b","c":{}}}`, buf.String()) - }) - }) - t.Run("remove undefined variables", func(t *testing.T) { - var ( - src = &Source{httpClient: &http.Client{}} - serverUrl = ts.URL - variables = []byte(`{"a":null,"b":null, "c": null}`) - ) - t.Run("should remove undefined variables and leave null variables", func(t *testing.T) { - var input []byte - input = httpclient.SetInputBodyWithPath(input, variables, "variables") - input = httpclient.SetInputURL(input, []byte(serverUrl)) - buf := bytes.NewBuffer(nil) - - undefinedVariables := []string{"a", "c"} - ctx := context.Background() - input = httpclient.SetUndefinedVariables(input, undefinedVariables) - - require.NoError(t, src.Load(ctx, input, buf)) - assert.Equal(t, `{"variables":{"b":null}}`, buf.String()) - }) - }) -} - -func TestUnNullVariables(t *testing.T) { - t.Run("should not unnull variables if not enabled", func(t *testing.T) { - t.Run("two variables, one null", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"a":null,"b":true}}}`)) - expected := `{"body":{"variables":{"a":null,"b":true}}}` - assert.Equal(t, expected, string(out)) - }) - }) - - t.Run("variables with whitespace and empty objects", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"email":null,"firstName": "FirstTest", "lastName":"LastTest","phone":123456,"preferences":{ "notifications":{}},"password":"password"}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{"firstName":"FirstTest","lastName":"LastTest","phone":123456,"password":"password"}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("empty variables", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("null inside an array", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"list":["a",null,"b"]}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{"list":["a",null,"b"]}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("complex null inside nested objects and arrays", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"a":null, "b": {"key":null, "nested": {"nestedkey": null}}, "arr": ["1", null, "3"], "d": {"nested_arr":["4",null,"6"]}}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{"b":{"key":null,"nested":{"nestedkey":null}},"arr":["1",null,"3"],"d":{"nested_arr":["4",null,"6"]}}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("two variables, one null", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"a":null,"b":true}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{"b":true}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("two variables, one null reverse", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"a":true,"b":null}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{"a":true}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("null variables", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":null},"unnull_variables":true}`)) - expected := `{"body":{"variables":null},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("ignore null inside non variables", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"foo":null},"body":"query {foo(bar: null){baz}}"},"unnull_variables":true}`)) - expected := `{"body":{"variables":{},"body":"query {foo(bar: null){baz}}"},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("ignore null in variable name", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"variables":{"not_null":1,"null":2,"not_null2":3}},"unnull_variables":true}`)) - expected := `{"body":{"variables":{"not_null":1,"null":2,"not_null2":3}},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("variables missing", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"query":"{foo}"},"unnull_variables":true}`)) - expected := `{"body":{"query":"{foo}"},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) - - t.Run("variables null", func(t *testing.T) { - s := &Source{} - out := s.compactAndUnNullVariables([]byte(`{"body":{"query":"{foo}","variables":null},"unnull_variables":true}`)) - expected := `{"body":{"query":"{foo}","variables":null},"unnull_variables":true}` - assert.Equal(t, expected, string(out)) - }) -} - -func BenchmarkFederationBatching(b *testing.B) { - userService := FakeDataSource(`{"data":{"me": {"id": "1234","username": "Me","__typename": "User"}}}`) - reviewsService := FakeDataSource(`{"data":{"_entities":[{"reviews": [{"body": "A highly effective form of birth control.","product": {"upc": "top-1","__typename": "Product"}},{"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product": {"upc": "top-2","__typename": "Product"}}]}]}}`) - productsService := FakeDataSource(`{"data":{"_entities":[{"name": "Trilby"},{"name": "Fedora"}]}}`) - - reviewBatchFactory := NewBatchFactory() - productBatchFactory := NewBatchFactory() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := resolve.New(ctx, resolve.NewFetcher(true), true) - - preparedPlan := &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - }, - DataSource: userService, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"`), - SegmentType: resolve.StaticSegmentType, - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`","__typename":"User"}]}}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - }, - DataSource: reviewsService, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - BatchFactory: reviewBatchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.BatchFetch{ - Fetch: &resolve.SingleFetch{ - BufferId: 2, - DataSource: productsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":`), - SegmentType: resolve.StaticSegmentType, - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string"]}`), - }, - { - Data: []byte(`,"__typename":"Product"}]}}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - }, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - BatchFactory: productBatchFactory, - }, - Fields: []*resolve.Field{ - { - Name: []byte("upc"), - Value: &resolve.String{ - Path: []string{"upc"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - var err error - expected := []byte(`{"data":{"me":{"id":"1234","username":"Me","reviews":[{"body":"A highly effective form of birth control.","product":{"upc":"top-1","name":"Trilby"}},{"body":"Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product":{"upc":"top-2","name":"Fedora"}}]}}}`) - - pool := sync.Pool{ - New: func() interface{} { - return bytes.NewBuffer(make([]byte, 0, 1024)) - }, - } - - ctxPool := sync.Pool{ - New: func() interface{} { - return resolve.NewContext(context.Background()) - }, - } - - b.ReportAllocs() - b.SetBytes(int64(len(expected))) - b.ResetTimer() - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - // _ = resolver.ResolveGraphQLResponse(ctx, plan, nil, ioutil.Discard) - ctx := ctxPool.Get().(*resolve.Context) - buf := pool.Get().(*bytes.Buffer) - err = resolver.ResolveGraphQLResponse(ctx, preparedPlan, nil, buf) - if err != nil { - b.Fatal(err) - } - if !bytes.Equal(expected, buf.Bytes()) { - b.Fatalf("want:\n%s\ngot:\n%s\n", string(expected), buf.String()) - } - - buf.Reset() - pool.Put(buf) - - ctx.Free() - ctxPool.Put(ctx) - } - }) -} - -const interfaceSelectionSchema = ` - -scalar String -scalar Boolean - -schema { - query: Query -} - -type Query { - user: User -} - -interface User { - id: ID! - displayName: String! - isLoggedIn: Boolean! -} - -type RegisteredUser implements User { - id: ID! - displayName: String! - isLoggedIn: Boolean! - hasVerifiedEmail: Boolean! -} -` - -const variableSchema = ` - -scalar String - -schema { - query: Query -} - -type Query { - user(name: String!): User -} - -type User { - normalized(data: NormalizedDataInput!): String! -} - -input NormalizedDataInput { - name: String! -} -` - -const starWarsSchema = ` -union SearchResult = Human | Droid | Starship - -directive @format on FIELD -directive @onOperation on QUERY -directive @onVariable on VARIABLE_DEFINITION - -scalar JSON - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Query { - hero: Character - droid(id: ID!): Droid - review(id: ID!): Review - search(name: String!): SearchResult - searchWithInput(input: SearchInput!): SearchResult - stringList: [String] - nestedStringList: [String] -} - -input SearchInput { - name: String - options: JSON -} - -type Mutation { - createReview(episode: Episode!, review: ReviewInput!): Review -} - -type Subscription { - remainingJedis: Int! -} - -input ReviewInput { - stars: Int! - commentary: String -} - -type Review { - id: ID! - stars: Int! - commentary: String -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI -} - -interface Character { - id: ID! - name: String! - friends: [Character] -} - -type Human implements Character { - id: ID! - name: String! - height: String! - friends: [Character] -} - -type Droid implements Character { - id: ID! - name: String! - primaryFunction: String! - friends: [Character] -} - -type Starship { - name: String! - length: Float! -}` - -const starWarsSchemaWithRenamedArgument = ` -union SearchResult = Human | Droid | Starship - -directive @format on FIELD -directive @onOperation on QUERY -directive @onVariable on VARIABLE_DEFINITION - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -scalar ReviewID - -type Query { - hero: Character - droid(id: ID!): Droid - review(id: ReviewID!): Review - search(name: String!): SearchResult - searchWithInput(input: SearchInput!): SearchResult - stringList: [String] - nestedStringList: [String] -} - -input SearchInput { - name: String -} - -type Mutation { - createReview(episode: Episode!, review: ReviewInput!): Review -} - -type Subscription { - remainingJedis: Int! -} - -input ReviewInput { - stars: Int! - commentary: String -} - -type Review { - id: ID! - stars: Int! - commentary: String -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI -} - -interface Character { - name: String! - friends: [Character] -} - -type Human implements Character { - name: String! - height: String! - friends: [Character] -} - -type Droid implements Character { - name: String! - primaryFunction: String! - friends: [Character] -} - -type Starship { - name: String! - length: Float! -}` - -const starWarsSchemaWithExportDirective = ` -union SearchResult = Human | Droid | Starship - -directive @format on FIELD -directive @onOperation on QUERY -directive @onVariable on VARIABLE_DEFINITION - -directive @export ( - as: String! -) on FIELD - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Query { - hero: Character - droid(id: ID!): Droid - search(name: String!): SearchResult - searchWithInput(input: SearchInput!): SearchResult - stringList: [String] - nestedStringList: [String] -} - -input SearchInput { - name: String -} - -type Mutation { - createReview(episode: Episode!, review: ReviewInput!): Review -} - -type Subscription { - remainingJedis: Int! -} - -input ReviewInput { - stars: Int! - commentary: String -} - -type Review { - id: ID! - stars: Int! - commentary: String -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI -} - -interface Character { - id: ID! - name: String! - friends: [Character] -} - -type Human implements Character { - id: ID! - name: String! - height: String! - friends: [Character] -} - -type Droid implements Character { - id: ID! - name: String! - primaryFunction: String! - friends: [Character] -} - -type Starship { - name: String! - length: Float! -}` - -const renamedStarWarsSchema = ` -union SearchResult_api = Human_api | Droid_api | Starship_api - -directive @api_format on FIELD -directive @otherapi_undefined on QUERY -directive @api_onOperation on QUERY -directive @api_onVariable on VARIABLE_DEFINITION - -scalar JSON_api - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Query { - api_hero: Character_api - api_droid(id: ID!): Droid_api - api_search(name: String!): SearchResult_api - api_searchWithInput(input: SearchInput_api!): SearchResult_api - api_stringList: [String] - api_nestedStringList: [String] -} - -input SearchInput_api { - name: String - options: JSON_api -} - -type Mutation { - createReview(episode: Episode_api!, review: ReviewInput_api!): Review_api -} - -type Subscription { - remainingJedis: Int! -} - -input ReviewInput_api { - stars: Int! - commentary: String -} - -type Review_api { - id: ID! - stars: Int! - commentary: String -} - -enum Episode_api { - NEWHOPE - EMPIRE - JEDI -} - -interface Character_api { - name: String! - friends: [Character_api] -} - -type Human_api implements Character_api { - name: String! - height: String! - friends: [Character_api] -} - -type Droid_api implements Character_api { - name: String! - primaryFunction: String! - friends: [Character_api] -} - -type Starship_api { - name: String! - length: Float! -}` - -const todoSchema = ` - -schema { - query: Query - mutation: Mutation -} - -scalar ID -scalar String -scalar Boolean - -"""""" -scalar DateTime - -"""""" -enum DgraphIndex { - """""" - int - """""" - float - """""" - bool - """""" - hash - """""" - exact - """""" - term - """""" - fulltext - """""" - trigram - """""" - regexp - """""" - year - """""" - month - """""" - day - """""" - hour -} - -"""""" -input DateTimeFilter { - """""" - eq: DateTime - """""" - le: DateTime - """""" - lt: DateTime - """""" - ge: DateTime - """""" - gt: DateTime -} - -"""""" -input StringHashFilter { - """""" - eq: String -} - -"""""" -type UpdateTaskPayload { - """""" - task(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - numUids: Int -} - -"""""" -type Subscription { - """""" - getTask(id: ID!): Task - """""" - queryTask(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - getUser(username: String!): User - """""" - queryUser(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] -} - -"""""" -input FloatFilter { - """""" - eq: Float - """""" - le: Float - """""" - lt: Float - """""" - ge: Float - """""" - gt: Float -} - -"""""" -input StringTermFilter { - """""" - allofterms: String - """""" - anyofterms: String -} - -"""""" -type DeleteTaskPayload { - """""" - task(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - msg: String - """""" - numUids: Int -} - -"""""" -type Mutation { - """""" - addTask(input: [AddTaskInput!]!): AddTaskPayload - """""" - updateTask(input: UpdateTaskInput!): UpdateTaskPayload - """""" - deleteTask(filter: TaskFilter!): DeleteTaskPayload - """""" - addUser(input: [AddUserInput!]!): AddUserPayload - """""" - updateUser(input: UpdateUserInput!): UpdateUserPayload - """""" - deleteUser(filter: UserFilter!): DeleteUserPayload -} - -"""""" -enum HTTPMethod { - """""" - GET - """""" - POST - """""" - PUT - """""" - PATCH - """""" - DELETE -} - -"""""" -type DeleteUserPayload { - """""" - user(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] - """""" - msg: String - """""" - numUids: Int -} - -"""""" -input TaskFilter { - """""" - id: [ID!] - """""" - title: StringFullTextFilter - """""" - completed: Boolean - """""" - and: TaskFilter - """""" - or: TaskFilter - """""" - not: TaskFilter -} - -"""""" -type UpdateUserPayload { - """""" - user(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] - """""" - numUids: Int -} - -"""""" -input TaskRef { - """""" - id: ID - """""" - title: String - """""" - completed: Boolean - """""" - user: UserRef -} - -"""""" -input UserFilter { - """""" - username: StringHashFilter - """""" - name: StringExactFilter - """""" - and: UserFilter - """""" - or: UserFilter - """""" - not: UserFilter -} - -"""""" -input UserOrder { - """""" - asc: UserOrderable - """""" - desc: UserOrderable - """""" - then: UserOrder -} - -"""""" -input AuthRule { - """""" - and: [AuthRule] - """""" - or: [AuthRule] - """""" - not: AuthRule - """""" - rule: String -} - -"""""" -type AddTaskPayload { - """""" - task(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - numUids: Int -} - -"""""" -type AddUserPayload { - """""" - user(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] - """""" - numUids: Int -} - -"""""" -type Task { - """""" - id: ID! - """""" - title: String! - """""" - completed: Boolean! - """""" - user(filter: UserFilter): User! -} - -"""""" -input IntFilter { - """""" - eq: Int - """""" - le: Int - """""" - lt: Int - """""" - ge: Int - """""" - gt: Int -} - -"""""" -input StringExactFilter { - """""" - eq: String - """""" - le: String - """""" - lt: String - """""" - ge: String - """""" - gt: String -} - -"""""" -enum UserOrderable { - """""" - username - """""" - name -} - -"""""" -input AddTaskInput { - """""" - titleSets: [[String!]] - """""" - completed: Boolean! - """""" - user: UserRef! -} - -"""""" -input TaskPatch { - """""" - title: String - """""" - completed: Boolean - """""" - user: UserRef -} - -"""""" -input UserRef { - """""" - username: String - """""" - name: String - """""" - tasks: [TaskRef] -} - -"""""" -input StringFullTextFilter { - """""" - alloftext: String - """""" - anyoftext: String -} - -"""""" -enum TaskOrderable { - """""" - title -} - -"""""" -input UpdateTaskInput { - """""" - filter: TaskFilter! - """""" - set: TaskPatch - """""" - remove: TaskPatch -} - -"""""" -input UserPatch { - """""" - name: String - """""" - tasks: [TaskRef] -} - -"""""" -type Query { - """""" - getTask(id: ID!): Task - """""" - queryTask(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] - """""" - getUser(username: String!): User - """""" - queryUser(filter: UserFilter, order: UserOrder, first: Int, offset: Int): [User] -} - -"""""" -type User { - """""" - username: String! - """""" - name: String - """""" - tasks(filter: TaskFilter, order: TaskOrder, first: Int, offset: Int): [Task] -} - -"""""" -enum Mode { - """""" - BATCH - """""" - SINGLE -} - -"""""" -input CustomHTTP { - """""" - url: String! - """""" - method: HTTPMethod! - """""" - body: String - """""" - graphql: String - """""" - mode: Mode - """""" - forwardHeaders: [String!] - """""" - secretHeaders: [String!] - """""" - introspectionHeaders: [String!] - """""" - skipIntrospection: Boolean -} - -"""""" -input StringRegExpFilter { - """""" - regexp: String -} - -"""""" -input AddUserInput { - """""" - username: String! - """""" - name: String - """""" - tasks: [TaskRef] -} - -"""""" -input TaskOrder { - """""" - asc: TaskOrderable - """""" - desc: TaskOrderable - """""" - then: TaskOrder -} - -"""""" -input UpdateUserInput { - """""" - filter: UserFilter! - """""" - set: UserPatch - """""" - remove: UserPatch -} -""" -The @cache directive caches the response server side and sets cache control headers according to the configuration. -With this setting you can reduce the load on your backend systems for operations that get hit a lot while data doesn't change that frequently. -""" -directive @cache( - """maxAge defines the maximum time in seconds a response will be understood 'fresh', defaults to 300 (5 minutes)""" - maxAge: Int! = 300 - """ - vary defines the headers to append to the cache key - In addition to all possible headers you can also select a custom claim for authenticated requests - Examples: 'jwt.sub', 'jwt.team' to vary the cache key based on 'sub' or 'team' fields on the jwt. - """ - vary: [String]! = [] -) on QUERY - -"""The @auth directive lets you configure auth for a given operation""" -directive @auth( - """disable explicitly disables authentication for the annotated operation""" - disable: Boolean! = false -) on QUERY | MUTATION | SUBSCRIPTION - -"""The @fromClaim directive overrides a variable from a select claim in the jwt""" -directive @fromClaim( - """ - name is the name of the claim you want to use for the variable - examples: sub, team, custom.nested.claim - """ - name: String! -) on VARIABLE_DEFINITION -` - -const testDefinition = ` -union SearchResult = Human | Droid | Starship -scalar Date - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Query { - hero: Character - heroByBirthdate(birthdate: Date): Character - droid(id: ID!): Droid - droids(ids: [ID!]!): [Droid] - search(name: String!): SearchResult - stringList: [String] - nestedStringList: [String] -} - -type Mutation { - createReview(episode: Episode!, review: ReviewInput!): Review -} - -type Subscription { - remainingJedis: Int! -} - -input ReviewInput { - stars: Int! - commentary: String -} - -type Review { - id: ID! - stars: Int! - commentary: String -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI -} - -interface Character { - name: String! - friends: [Character] -} - -type Human implements Character { - name: String! - height: String! - friends: [Character] -} - -type Droid implements Character { - name: String! - primaryFunction: String! - friends: [Character] -} - -type Starship { - name: String! - length: Float! -}` - -const federationTestSchema = ` -scalar String -scalar Int -scalar ID - -schema { - query: Query -} - -type Product { - upc: String! - name: String! - price: Int! - reviews: [Review] -} - -type Query { - me: User - topProducts(first: Int = 5): [Product] -} - -type Review { - body: String! - author: User! - product: Product! - notes: String - likes(filterToPublicOnly: Boolean): Int! -} - -type User { - id: ID! - username: String! - reviews: [Review] -} -` - -const federationTestSchemaWithRename = ` -scalar String -scalar Int -scalar ID -scalar XBoolean - -schema { - query: Query -} - -type Product { - upc: String! - name: String! - price: Int! - reviews: [Review] -} - -type Query { - me: User - topProducts(first: Int = 5): [Product] -} - -type Review { - body: String! - author: User! - product: Product! - notes: String - likes(filterToPublicOnly: XBoolean!): Int! -} - -type User { - id: ID! - username: String! - reviews: [Review] -} -` - -const complexFederationSchema = ` -scalar String -scalar Int -scalar Float -scalar ID - -union AccountType = PasswordAccount | SMSAccount -type Amazon { - referrer: String -} - -union Brand = Ikea | Amazon -type Car implements Vehicle { - id: String! - description: String - price: String -} - -type Error { - code: Int - message: String -} - -type Furniture implements Product { - upc: String! - sku: String! - name: String - price: String - brand: Brand - metadata: [MetadataOrError] - details: ProductDetailsFurniture - inStock: Int! -} - -type Ikea { - asile: Int -} - -type KeyValue { - key: String! - value: String! -} - -union MetadataOrError = KeyValue | Error -type Mutation { - login(username: String!, password: String!): User -} - -type Name { - first: String - last: String -} - -type PasswordAccount { - email: String! -} - -interface Product { - upc: String! - sku: String! - name: String - price: String - details: ProductDetails - inStock: Int! -} - -interface ProductDetails { - country: String -} - -type ProductDetailsBook implements ProductDetails { - country: String - pages: Int -} - -type ProductDetailsFurniture implements ProductDetails { - country: String - color: String -} - -type Query { - me: User - user(id: ID!): User - product(upc: String!): Product - vehicle(id: String!): Vehicle - topProducts(first: Int = 5): [Product] - topCars(first: Int = 5): [Car] -} - -type Review { - body: String! - author: User! - product: Product! -} - -type SMSAccount { - number: String -} - -type Subscription { - updatedPrice: Product! - updateProductPrice(upc: String!): Product! - stock: [Product!] -} - -union Thing = Car | Ikea -type User { - id: ID! - name: Name - username: String - birthDate(locale: String): String - account: AccountType - metadata: [UserMetadata] - ssn: String - vehicle: Vehicle - thing: Thing - reviews: [Review] -} - -type UserMetadata { - name: String - address: String - description: String -} - -type Van implements Vehicle { - id: String! - description: String - price: String -} - -interface Vehicle { - id: String! - description: String - price: String -} -` - -const renamedFederationTestSchema = ` -scalar String -scalar Int -scalar ID - -schema { - query: Query -} - -type Product_api { - upc: String! - name: String! - price: Int! - reviews: [Review_api] -} - -type Query { - api_me: User_api - api_topProducts(first: Int = 5): [Product_api] -} - -type Review_api { - body: String! - author: User_api! - product: Product_api! -} - -type User_api { - id: ID! - username: String! - reviews: [Review_api] -} -` - -const requiredFieldTestSchema = ` -scalar String -scalar ID - -schema { - query: Query -} - -type Query { - serviceOne: ServiceOneType -} - -type ServiceOneType { - id: ID! - serviceOneFieldOne: String! - serviceOneFieldTwo: String! - - serviceTwoFieldOne: String! - serviceTwoFieldTwo: String! -} -` - -const subgraphTestSchema = ` -directive @external on FIELD_DEFINITION -directive @requires(fields: _FieldSet!) on FIELD_DEFINITION -directive @provides(fields: _FieldSet!) on FIELD_DEFINITION -directive @key(fields: _FieldSet!) on OBJECT | INTERFACE -directive @extends on OBJECT - -scalar _Any -union _Entity = Product | User -scalar _FieldSet - -type _Service { - sdl: String -} - -type Entity { - findProductByUpc(upc: String!): Product! - findUserByID(id: ID!): User! -} - -type Product { - upc: String! - reviews: [Review] -} - -type Query { - _entities(representations: [_Any!]!): [_Entity]! - _service: _Service! -} - -type Review { - body: String! - author: User! - product: Product! -} - -type User { - id: ID! - username: String! - reviews: [Review] -} -` - -const countriesSchema = ` -scalar String -scalar Int -scalar ID - -schema { - query: Query -} - -type Country { - name: String! - code: ID! -} - -type Query { - country(code: ID!): Country - countryAlias(code: ID!): Country -} -` - -const wgSchema = `union DeleteEnvironmentResponse = Success | Error - -type Query { - user: User - edges: [Edge!]! - admin_Config: AdminConfigResponse! -} - -type NamespaceMemberRemoved { - namespace: Namespace! -} - -type NamespaceMemberAdded { - namespace: Namespace! -} - -union DeleteNamespaceResponse = Success | Error - -enum Membership { - owner - maintainer - viewer - guest -} - -input CreateAccessToken { - name: String! -} - -type ApiCreated { - api: Api! -} - -scalar Time - -union NamespaceRemoveMemberResponse = NamespaceMemberRemoved | Error - -enum EnvironmentKind { - Personal - Team - Business -} - -type Edge { - id: ID! - name: String! - location: String! -} - -type NamespaceCreated { - namespace: Namespace! -} - -union UpdateEnvironmentResponse = EnvironmentUpdated | Error - -type Deployment { - id: ID! - name: String! - config: JSON! - environments: [Environment!]! -} - -type Error { - code: ErrorCode! - message: String! -} - -type Mutation { - accessTokenCreate(input: CreateAccessToken!): CreateAccessTokenResponse! - accessTokenDelete(input: DeleteAccessToken!): DeleteAccessTokenResponse! - apiCreate(input: CreateApi!): CreateApiResponse! - apiUpdate(input: UpdateApi!): UpdateApiResponse! - apiDelete(input: DeleteApi!): DeleteApiResponse! - deploymentCreateOrUpdate(input: CreateOrUpdateDeployment!): CreateOrUpdateDeploymentResponse! - deploymentDelete(input: DeleteDeployment!): DeleteDeploymentResponse! - environmentCreate(input: CreateEnvironment!): CreateEnvironmentResponse! - environmentUpdate(input: UpdateEnvironment!): UpdateEnvironmentResponse! - environmentDelete(input: DeleteEnvironment!): DeleteEnvironmentResponse! - namespaceCreate(input: CreateNamespace!): CreateNamespaceResponse! - namespaceDelete(input: DeleteNamespace!): DeleteNamespaceResponse! - namespaceAddMember(input: NamespaceAddMember!): NamespaceAddMemberResponse! - namespaceRemoveMember(input: NamespaceRemoveMember!): NamespaceRemoveMemberResponse! - namespaceUpdateMembership(input: NamespaceUpdateMembership!): NamespaceUpdateMembershipResponse! - admin_setWunderNodeImageTag(imageTag: String!): AdminConfigResponse! -} - -type AccessToken { - id: ID! - name: String! - createdAt: Time! -} - -type EnvironmentCreated { - environment: Environment! -} - -type DeploymentUpdated { - deployment: Deployment! -} - -enum ErrorCode { - Internal - AuthenticationRequired - Unauthorized - NotFound - Conflict - UserAlreadyHasPersonalNamespace - TeamPlanInPersonalNamespace - InvalidName - UnableToDeployEnvironment - InvalidWunderGraphConfig - ApiEnvironmentNamespaceMismatch - UnableToUpdateEdgesOnPersonalEnvironment -} - -input CreateEnvironment { - namespace: ID! - name: String - primary: Boolean! - kind: EnvironmentKind! - edges: [ID!] -} - -type Environment { - id: ID! - name: String - primary: Boolean! - kind: EnvironmentKind! - edges: [Edge!] - primaryHostName: String! - hostNames: [String!]! -} - -type DeploymentCreated { - deployment: Deployment! -} - -union AdminConfigResponse = Error | AdminConfig - -input CreateNamespace { - name: String! - personal: Boolean! -} - -input NamespaceUpdateMembership { - namespaceID: ID! - memberID: ID! - newMembership: Membership! -} - -union DeleteApiResponse = Success | Error - -type ApiUpdated { - api: Api! -} - -input DeleteDeployment { - deploymentID: ID! -} - -input NamespaceRemoveMember { - namespaceID: ID! - memberID: ID! -} - -union NamespaceUpdateMembershipResponse = NamespaceMembershipUpdated | Error - -type User { - id: ID! - name: String! - email: String! - namespaces: [Namespace!]! - accessTokens: [AccessToken!]! -} - -input DeleteApi { - id: ID! -} - -type NamespaceMembershipUpdated { - namespace: Namespace! -} - -type EnvironmentUpdated { - environment: Environment! -} - -union CreateNamespaceResponse = NamespaceCreated | Error - -type Namespace { - id: ID! - name: String! - members: [Member!]! - apis: [Api!]! - environments: [Environment!]! - personal: Boolean! -} - -input UpdateEnvironment { - environmentID: ID! - edgeIDs: [ID!] -} - -input DeleteEnvironment { - environmentID: ID! -} - -enum ApiVisibility { - public - private - namespace -} - -type Member { - user: User! - membership: Membership! -} - -union DeleteAccessTokenResponse = Success | Error - -input CreateApi { - apiName: String! - namespaceID: String! - visibility: ApiVisibility! - markdownDescription: String! -} - -union CreateApiResponse = ApiCreated | Error - -union CreateEnvironmentResponse = EnvironmentCreated | Error - -union UpdateApiResponse = ApiUpdated | Error - -input CreateOrUpdateDeployment { - apiID: ID! - name: String - config: JSON! - environmentIDs: [ID!]! -} - -union CreateOrUpdateDeploymentResponse = DeploymentCreated | DeploymentUpdated | Error - -union CreateAccessTokenResponse = AccessTokenCreated | Error - -input DeleteAccessToken { - id: ID! -} - -type AdminConfig { - WunderNodeImageTag: String! -} - -input UpdateApi { - id: ID! - apiName: String! - config: JSON! - visibility: ApiVisibility! - markdownDescription: String! -} - -type Success { - message: String! -} - -scalar JSON - -input NamespaceAddMember { - namespaceID: ID! - newMemberEmail: String! - membership: Membership -} - -input DeleteNamespace { - namespaceID: ID! -} - -type AccessTokenCreated { - token: String! - accessToken: AccessToken! -} - -union NamespaceAddMemberResponse = NamespaceMemberAdded | Error - -type Api { - id: ID! - name: String! - visibility: ApiVisibility! - deployments: [Deployment!]! - markdownDescription: String! -} - -union DeleteDeploymentResponse = Success | Error -` - -const userSchema = ` -type Query { - user(id: ID!): User -} - -type User { - id: ID! - name: String! - tier: Tier - meta: Map! -} - -enum Tier { - A - B - C -} - -scalar Map -` - -const customUserSchema = ` -type Query { - custom_user(id: ID!): custom_User -} - -type custom_User { - id: ID! - name: String! - tier: custom_Tier - meta: custom_Meta! -} - -enum custom_Tier { - A - B - C -} - -type custom_Meta { - foo: String! -} - -scalar custom_Map -` - -const federatedSchemaWithInterfaceQuery = ` - scalar String - scalar Int - scalar ID - - schema { - query: Query - } - - type Query { - me: User - self: Identity - } - - interface Identity { - id: ID! - } - - type User implements Identity { - id: ID! - username: String! - reviews: [Review] - } - - interface Medium { - size: Int! - } - - type Image implements Medium { - size: Int! - extension: String! - } - - type Video implements Medium { - size: Int! - length: Int! - } - - type Review { - id: ID! - body: String! - author: User! - attachment: Medium! - } -` - -const reviewSDL = ` - interface Medium { - size: Int! - } - - type Image implements Medium { - size: Int! - extension: String! - } - - type Video implements Medium { - size: Int! - length: Int! - } - - type Review @key(fields: "id") { - id: ID! - body: String! - author: User! @provides(fields: "username") - attachment: Medium - } - - extend type User @key(fields: "id") { - id: ID! @external - reviews: [Review] - } -` - -const userSDLWithInterface = ` - extend type Query { - me: User - self: Identity - } - - interface Identity { - id: ID! - } - - type User implements Identity @key(fields: "id") { - id: ID! - username: String! - } -` - -const federatedSchemaWithComplexNestedFragments = ` - type Query { - user: User - } - type User { - id: ID! - username: String! - pets: [Pet!]! - } - type Details { - hasOwner: Boolean! - age: Int! - } - interface Pet { - name: String! - species: String! - details: Details! - } - type Cat implements Pet { - name: String! - species: String! - catField: String! - details: Details! - } - type Dog implements Pet { - name: String! - species: String! - dogField: String! - details: Details! - } -` - -const simpleUserSchema = ` - extend type Query { - user: User - } - type User @key(fields: "id") { - id: ID! - username: String! - } -` - -const petSchema = ` - type Details { - age: Int! - hasOwner : Boolean! - } - interface Pet { - name: String! - species: String! - details: Details! - } - type Cat implements Pet { - name: String! - species: String! - catField: String! - details: Details! - } - type Dog implements Pet { - name: String! - species: String! - dogField: String! - details: Details! - } - extend type User @key(fields: "id") { - id: ID! @external - pets: [Pet!]! - } -` diff --git a/pkg/engine/datasource/graphql_datasource/graphql_sse_handler.go b/pkg/engine/datasource/graphql_datasource/graphql_sse_handler.go deleted file mode 100644 index 4b57a9a0b..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_sse_handler.go +++ /dev/null @@ -1,286 +0,0 @@ -package graphql_datasource - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "math" - "net/http" - - "github.com/buger/jsonparser" - log "github.com/jensneuse/abstractlogger" - "github.com/r3labs/sse/v2" -) - -var ( - headerData = []byte("data:") - headerEvent = []byte("event:") - - eventTypeComplete = []byte("complete") - eventTypeNext = []byte("next") -) - -type gqlSSEConnectionHandler struct { - conn *http.Client - ctx context.Context - log log.Logger - options GraphQLSubscriptionOptions -} - -func newSSEConnectionHandler(ctx context.Context, conn *http.Client, opts GraphQLSubscriptionOptions, l log.Logger) *gqlSSEConnectionHandler { - return &gqlSSEConnectionHandler{ - conn: conn, - ctx: ctx, - log: l, - options: opts, - } -} - -func (h *gqlSSEConnectionHandler) StartBlocking(sub Subscription) { - reqCtx := sub.ctx - - dataCh := make(chan []byte) - errCh := make(chan []byte) - defer func() { - close(dataCh) - close(errCh) - close(sub.next) - }() - - go h.subscribe(reqCtx, sub, dataCh, errCh) - - for { - select { - case data := <-dataCh: - sub.next <- data - case err := <-errCh: - sub.next <- err - return - case <-reqCtx.Done(): - return - } - } -} - -func (h *gqlSSEConnectionHandler) subscribe(ctx context.Context, sub Subscription, dataCh, errCh chan []byte) { - resp, err := h.performSubscriptionRequest(ctx) - if err != nil { - h.log.Error("failed to perform subscription request", log.Error(err)) - - if ctx.Err() != nil { - // request context was canceled do not send an error as channel will be closed - return - } - - sub.next <- []byte(internalError) - - return - } - defer func() { - _ = resp.Body.Close() - }() - - reader := sse.NewEventStreamReader(resp.Body, math.MaxInt) - - for { - if ctx.Err() != nil { - return - } - - msg, err := reader.ReadEvent() - if err != nil { - if err == io.EOF { - return - } - - h.log.Error("failed to read event", log.Error(err)) - - errCh <- []byte(internalError) - return - } - - if len(msg) == 0 { - continue - } - - // normalize the crlf to lf to make it easier to split the lines. - // split the line by "\n" or "\r", per the spec. - lines := bytes.FieldsFunc(msg, func(r rune) bool { return r == '\n' || r == '\r' }) - for _, line := range lines { - switch { - case bytes.HasPrefix(line, headerData): - data := trim(line[len(headerData):]) - - if len(data) == 0 { - continue - } - - if ctx.Err() != nil { - // request context was canceled do not send an error as channel will be closed - return - } - - dataCh <- data - case bytes.HasPrefix(line, headerEvent): - event := trim(line[len(headerEvent):]) - - switch { - case bytes.Equal(event, eventTypeComplete): - return - case bytes.Equal(event, eventTypeNext): - continue - } - case bytes.HasPrefix(msg, []byte(":")): - // according to the spec, we ignore messages starting with a colon - continue - default: - // ideally we should not get here, or if we do, we should ignore it - // but some providers send a json object with the error messages, without the event header - - // check for errors which came without event header - data := trim(line) - - val, valueType, _, err := jsonparser.Get(data, "errors") - switch err { - case jsonparser.KeyPathNotFoundError: - continue - case jsonparser.MalformedJsonError: - // ignore garbage - continue - case nil: - if valueType == jsonparser.Array { - response := []byte(`{}`) - response, err = jsonparser.Set(response, val, "errors") - if err != nil { - h.log.Error("failed to set errors", log.Error(err)) - - errCh <- []byte(internalError) - return - } - - errCh <- response - return - } else if valueType == jsonparser.Object { - response := []byte(`{"errors":[]}`) - response, err = jsonparser.Set(response, val, "errors", "[0]") - if err != nil { - h.log.Error("failed to set errors", log.Error(err)) - - errCh <- []byte(internalError) - return - } - - errCh <- response - return - } - - default: - h.log.Error("failed to parse errors", log.Error(err)) - errCh <- []byte(internalError) - return - } - } - } - } -} - -func trim(data []byte) []byte { - // remove the leading space - data = bytes.TrimLeft(data, " \t") - - // remove the trailing new line - data = bytes.TrimRight(data, "\n") - - return data -} - -func (h *gqlSSEConnectionHandler) performSubscriptionRequest(ctx context.Context) (*http.Response, error) { - - var req *http.Request - var err error - - // default to GET requests when SSEMethodPost is not enabled in the SubscriptionConfiguration - if h.options.SSEMethodPost { - req, err = h.buildPOSTRequest(ctx) - } else { - req, err = h.buildGETRequest(ctx) - } - - if err != nil { - return nil, err - } - - resp, err := h.conn.Do(req) - if err != nil { - return nil, err - } - - switch resp.StatusCode { - case http.StatusOK: - return resp, nil - default: - return nil, fmt.Errorf("failed to connect to stream unexpected resp status code: %d", resp.StatusCode) - } -} - -func (h *gqlSSEConnectionHandler) buildGETRequest(ctx context.Context) (*http.Request, error) { - req, err := http.NewRequestWithContext(ctx, "GET", h.options.URL, nil) - if err != nil { - return nil, err - } - - if h.options.Header != nil { - req.Header = h.options.Header - } - - req.Header.Set("Accept", "text/event-stream") - req.Header.Set("Connection", "keep-alive") - req.Header.Set("Cache-Control", "no-cache") - - query := req.URL.Query() - query.Add("query", h.options.Body.Query) - - if h.options.Body.Variables != nil { - variables, _ := h.options.Body.Variables.MarshalJSON() - - query.Add("variables", string(variables)) - } - - if h.options.Body.OperationName != "" { - query.Add("operationName", h.options.Body.OperationName) - } - - if h.options.Body.Extensions != nil { - extensions, _ := h.options.Body.Extensions.MarshalJSON() - - query.Add("extensions", string(extensions)) - } - - req.URL.RawQuery = query.Encode() - - return req, nil -} - -func (h *gqlSSEConnectionHandler) buildPOSTRequest(ctx context.Context) (*http.Request, error) { - body, err := json.Marshal(h.options.Body) - if err != nil { - return nil, err - } - - req, err := http.NewRequestWithContext(ctx, "POST", h.options.URL, bytes.NewBuffer(body)) - if err != nil { - return nil, err - } - - if h.options.Header != nil { - req.Header = h.options.Header - } - - req.Header.Set("Accept", "text/event-stream") - req.Header.Set("Connection", "keep-alive") - req.Header.Set("Cache-Control", "no-cache") - - return req, nil -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_sse_handler_test.go b/pkg/engine/datasource/graphql_datasource/graphql_sse_handler_test.go deleted file mode 100644 index de13c4306..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_sse_handler_test.go +++ /dev/null @@ -1,501 +0,0 @@ -package graphql_datasource - -import ( - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestGraphQLSubscriptionClientSubscribe_SSE(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - urlQuery := r.URL.Query() - assert.Equal(t, "subscription {messageAdded(roomName: \"room\"){text}}", urlQuery.Get("query")) - - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"data":{"messageAdded":{"text":"first"}}}`) - flusher.Flush() - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"data":{"messageAdded":{"text":"second"}}}`) - flusher.Flush() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - first := <-next - second := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} - -func TestGraphQLSubscriptionClientSubscribe_SSE_RequestAbort(t *testing.T) { - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - - ctx, clientCancel := context.WithCancel(context.Background()) - // cancel after start the request - clientCancel() - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: "http://dummy", - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - assert.Eventuallyf(t, func() bool { - <-next - return true - }, time.Millisecond*100, time.Millisecond*10, "subscription did not close") -} - -func TestGraphQLSubscriptionClientSubscribe_SSE_POST(t *testing.T) { - postReqBody := GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - } - expectedReqBody, err := json.Marshal(postReqBody) - assert.NoError(t, err) - - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - - actualReqBody, err := io.ReadAll(r.Body) - assert.NoError(t, err) - assert.Equal(t, expectedReqBody, actualReqBody) - - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"data":{"messageAdded":{"text":"first"}}}`) - flusher.Flush() - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"data":{"messageAdded":{"text":"second"}}}`) - flusher.Flush() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err = client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: postReqBody, - UseSSE: true, - SSEMethodPost: true, - }, next) - assert.NoError(t, err) - - first := <-next - second := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} - -func TestGraphQLSubscriptionClientSubscribe_SSE_WithEvents(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "event: next\ndata: %s\n\n", `{"data":{"messageAdded":{"text":"first"}}}`) - flusher.Flush() - - _, _ = fmt.Fprintf(w, "event: next\ndata: %s\n\n", `{"data":{"messageAdded":{"text":"second"}}}`) - flusher.Flush() - - _, _ = fmt.Fprintf(w, "event: complete\n\n") - flusher.Flush() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - first := <-next - second := <-next - - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} - -func TestGraphQLSubscriptionClientSubscribe_SSE_Error(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"errors":[{"message":"Unexpected error.","locations":[{"line":2,"column":3}],"path":["countdown"]}]}`) - flusher.Flush() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - first := <-next - - assert.Equal(t, `{"errors":[{"message":"Unexpected error.","locations":[{"line":2,"column":3}],"path":["countdown"]}]}`, string(first)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} - -func TestGraphQLSubscriptionClientSubscribe_SSE_Error_Without_Header(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "%s\n\n", `{"errors":[{"message":"Unexpected error.","locations":[{"line":2,"column":3}],"path":["countdown"]}],"data":null}`) - flusher.Flush() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - first := <-next - - assert.Equal(t, `{"errors":[{"message":"Unexpected error.","locations":[{"line":2,"column":3}],"path":["countdown"]}]}`, string(first)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} - -func TestGraphQLSubscriptionClientSubscribe_QueryParams(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - urlQuery := r.URL.Query() - assert.Equal(t, "subscription($a: Int!){countdown(from: $a)}", urlQuery.Get("query")) - assert.Equal(t, "CountDown", urlQuery.Get("operationName")) - assert.Equal(t, `{"a":5}`, urlQuery.Get("variables")) - assert.Equal(t, `{"persistedQuery":{"version":1,"sha256Hash":"d41d8cd98f00b204e9800998ecf8427e"}}`, urlQuery.Get("extensions")) - - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"data":{"countdown":5}}`) - flusher.Flush() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription($a: Int!){countdown(from: $a)}`, - OperationName: "CountDown", - Variables: []byte(`{"a":5}`), - Extensions: []byte(`{"persistedQuery":{"version":1,"sha256Hash":"d41d8cd98f00b204e9800998ecf8427e"}}`), - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - first := <-next - assert.Equal(t, `{"data":{"countdown":5}}`, string(first)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} - -func TestBuildPOSTRequestSSE(t *testing.T) { - subscriptionOptions := GraphQLSubscriptionOptions{ - URL: "test", - Body: GraphQLBody{ - Query: `subscription($a: Int!){countdown(from: $a)}`, - OperationName: "CountDown", - Variables: []byte(`{"a":5}`), - Extensions: []byte(`{"persistedQuery":{"version":1,"sha256Hash":"d41d8cd98f00b204e9800998ecf8427e"}}`), - }, - } - - h := gqlSSEConnectionHandler{ - options: subscriptionOptions, - } - - req, err := h.buildPOSTRequest(context.Background()) - assert.NoError(t, err) - - expectedReqBody, err := json.Marshal(subscriptionOptions.Body) - assert.NoError(t, err) - - assert.Equal(t, http.MethodPost, req.Method) - - actualReqBody, err := io.ReadAll(req.Body) - assert.NoError(t, err) - assert.Equal(t, expectedReqBody, actualReqBody) -} - -func TestBuildGETRequestSSE(t *testing.T) { - subscriptionOptions := GraphQLSubscriptionOptions{ - URL: "test", - Body: GraphQLBody{ - Query: `subscription($a: Int!){countdown(from: $a)}`, - OperationName: "CountDown", - Variables: []byte(`{"a":5}`), - Extensions: []byte(`{"persistedQuery":{"version":1,"sha256Hash":"d41d8cd98f00b204e9800998ecf8427e"}}`), - }, - } - - h := gqlSSEConnectionHandler{ - options: subscriptionOptions, - } - - req, err := h.buildGETRequest(context.Background()) - assert.NoError(t, err) - - assert.Equal(t, http.MethodGet, req.Method) - - urlQuery := req.URL.Query() - assert.Equal(t, subscriptionOptions.Body.Query, urlQuery.Get("query")) - assert.Equal(t, subscriptionOptions.Body.OperationName, urlQuery.Get("operationName")) - - assert.Equal(t, string(subscriptionOptions.Body.Variables), urlQuery.Get("variables")) - assert.Equal(t, string(subscriptionOptions.Body.Extensions), urlQuery.Get("extensions")) - -} - -func TestGraphQLSubscriptionClientSubscribe_SSE_Upstream_Dies(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - urlQuery := r.URL.Query() - assert.Equal(t, "subscription {messageAdded(roomName: \"room\"){text}}", urlQuery.Get("query")) - - // Make sure that the writer supports flushing. - flusher, ok := w.(http.Flusher) - require.True(t, ok) - - w.Header().Set("Content-Type", "text/event-stream") - w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") - w.Header().Set("Access-Control-Allow-Origin", "*") - - _, _ = fmt.Fprintf(w, "data: %s\n\n", `{"data":{"messageAdded":{"text":"first"}}}`) - flusher.Flush() - - // Kill the upstream server. We should catch this event as an "unexpected EOF" - // error and return an error message to the subscriber. - h, ok := w.(http.Hijacker) - require.True(t, ok) - rawConn, _, err := h.Hijack() - require.NoError(t, err) - _ = rawConn.Close() - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - UseSSE: true, - }, next) - assert.NoError(t, err) - - first := <-next - second := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - // Upstream died - assert.Equal(t, `{"errors":[{"message":"internal error"}]}`, string(second)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_subscription_client.go b/pkg/engine/datasource/graphql_datasource/graphql_subscription_client.go deleted file mode 100644 index 2b8a955f2..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_subscription_client.go +++ /dev/null @@ -1,328 +0,0 @@ -package graphql_datasource - -import ( - "context" - "fmt" - "math" - "net/http" - "sync" - "time" - - "github.com/buger/jsonparser" - "github.com/cespare/xxhash/v2" - "github.com/jensneuse/abstractlogger" - "nhooyr.io/websocket" -) - -const ackWaitTimeout = 30 * time.Second - -// SubscriptionClient allows running multiple subscriptions via the same WebSocket either SSE connection -// It takes care of de-duplicating connections to the same origin under certain circumstances -// If Hash(URL,Body,Headers) result in the same result, an existing connection is re-used -type SubscriptionClient struct { - streamingClient *http.Client - httpClient *http.Client - engineCtx context.Context - log abstractlogger.Logger - hashPool sync.Pool - handlers map[uint64]ConnectionHandler - handlersMu sync.Mutex - wsSubProtocol string - onWsConnectionInitCallback *OnWsConnectionInitCallback - - readTimeout time.Duration -} - -type Options func(options *opts) - -func WithLogger(log abstractlogger.Logger) Options { - return func(options *opts) { - options.log = log - } -} - -func WithReadTimeout(timeout time.Duration) Options { - return func(options *opts) { - options.readTimeout = timeout - } -} - -func WithWSSubProtocol(protocol string) Options { - return func(options *opts) { - options.wsSubProtocol = protocol - } -} - -func WithOnWsConnectionInitCallback(callback *OnWsConnectionInitCallback) Options { - return func(options *opts) { - options.onWsConnectionInitCallback = callback - } -} - -type opts struct { - readTimeout time.Duration - log abstractlogger.Logger - wsSubProtocol string - onWsConnectionInitCallback *OnWsConnectionInitCallback -} - -// GraphQLSubscriptionClientFactory abstracts the way of creating a new GraphQLSubscriptionClient. -// This can be very handy for testing purposes. -type GraphQLSubscriptionClientFactory interface { - NewSubscriptionClient(httpClient, streamingClient *http.Client, engineCtx context.Context, options ...Options) GraphQLSubscriptionClient -} - -type DefaultSubscriptionClientFactory struct{} - -func (d *DefaultSubscriptionClientFactory) NewSubscriptionClient(httpClient, streamingClient *http.Client, engineCtx context.Context, options ...Options) GraphQLSubscriptionClient { - return NewGraphQLSubscriptionClient(httpClient, streamingClient, engineCtx, options...) -} - -func NewGraphQLSubscriptionClient(httpClient, streamingClient *http.Client, engineCtx context.Context, options ...Options) *SubscriptionClient { - op := &opts{ - readTimeout: time.Second, - log: abstractlogger.NoopLogger, - } - for _, option := range options { - option(op) - } - return &SubscriptionClient{ - httpClient: httpClient, - streamingClient: streamingClient, - engineCtx: engineCtx, - handlers: make(map[uint64]ConnectionHandler), - log: op.log, - readTimeout: op.readTimeout, - hashPool: sync.Pool{ - New: func() interface{} { - return xxhash.New() - }, - }, - wsSubProtocol: op.wsSubProtocol, - onWsConnectionInitCallback: op.onWsConnectionInitCallback, - } -} - -// Subscribe initiates a new GraphQL Subscription with the origin -// If an existing WS connection with the same ID (Hash) exists, it is being re-used -// If connection protocol is SSE, a new connection is always created -// If no connection exists, the client initiates a new one -func (c *SubscriptionClient) Subscribe(reqCtx context.Context, options GraphQLSubscriptionOptions, next chan<- []byte) error { - if options.UseSSE { - return c.subscribeSSE(reqCtx, options, next) - } - - return c.subscribeWS(reqCtx, options, next) -} - -func (c *SubscriptionClient) subscribeSSE(reqCtx context.Context, options GraphQLSubscriptionOptions, next chan<- []byte) error { - if c.streamingClient == nil { - return fmt.Errorf("streaming http client is nil") - } - - sub := Subscription{ - ctx: reqCtx, - options: options, - next: next, - } - - handler := newSSEConnectionHandler(reqCtx, c.streamingClient, options, c.log) - - go func() { - handler.StartBlocking(sub) - }() - - return nil -} - -func (c *SubscriptionClient) subscribeWS(reqCtx context.Context, options GraphQLSubscriptionOptions, next chan<- []byte) error { - if c.httpClient == nil { - return fmt.Errorf("http client is nil") - } - - sub := Subscription{ - ctx: reqCtx, - options: options, - next: next, - } - - // each WS connection to an origin is uniquely identified by the Hash(URL,Headers,Body) - handlerID, err := c.generateHandlerIDHash(options) - if err != nil { - return err - } - - c.handlersMu.Lock() - defer c.handlersMu.Unlock() - handler, exists := c.handlers[handlerID] - if exists { - select { - case handler.SubscribeCH() <- sub: - case <-reqCtx.Done(): - } - return nil - } - - handler, err = c.newWSConnectionHandler(reqCtx, options) - if err != nil { - return err - } - - c.handlers[handlerID] = handler - - go func(handlerID uint64) { - handler.StartBlocking(sub) - c.handlersMu.Lock() - delete(c.handlers, handlerID) - c.handlersMu.Unlock() - }(handlerID) - - return nil -} - -// generateHandlerIDHash generates a Hash based on: URL and Headers to uniquely identify Upgrade Requests -func (c *SubscriptionClient) generateHandlerIDHash(options GraphQLSubscriptionOptions) (uint64, error) { - var ( - err error - ) - xxh := c.hashPool.Get().(*xxhash.Digest) - defer c.hashPool.Put(xxh) - xxh.Reset() - - _, err = xxh.WriteString(options.URL) - if err != nil { - return 0, err - } - err = options.Header.Write(xxh) - if err != nil { - return 0, err - } - - return xxh.Sum64(), nil -} - -func (c *SubscriptionClient) newWSConnectionHandler(reqCtx context.Context, options GraphQLSubscriptionOptions) (ConnectionHandler, error) { - subProtocols := []string{ProtocolGraphQLWS, ProtocolGraphQLTWS} - if c.wsSubProtocol != "" { - subProtocols = []string{c.wsSubProtocol} - } - - conn, upgradeResponse, err := websocket.Dial(reqCtx, options.URL, &websocket.DialOptions{ - HTTPClient: c.httpClient, - HTTPHeader: options.Header, - CompressionMode: websocket.CompressionDisabled, - Subprotocols: subProtocols, - }) - if err != nil { - return nil, err - } - // Disable the maximum message size limit. Don't use MaxInt64 since - // the nhooyr.io/websocket doesn't handle it correctly on 32 bit systems. - conn.SetReadLimit(math.MaxInt32) - if upgradeResponse.StatusCode != http.StatusSwitchingProtocols { - return nil, fmt.Errorf("upgrade unsuccessful") - } - - connectionInitMessage, err := c.getConnectionInitMessage(reqCtx, options.URL, options.Header) - if err != nil { - return nil, err - } - - // init + ack - err = conn.Write(reqCtx, websocket.MessageText, connectionInitMessage) - if err != nil { - return nil, err - } - - if c.wsSubProtocol == "" { - c.wsSubProtocol = conn.Subprotocol() - } - - if err := waitForAck(reqCtx, conn); err != nil { - return nil, err - } - - switch c.wsSubProtocol { - case ProtocolGraphQLWS: - return newGQLWSConnectionHandler(c.engineCtx, conn, c.readTimeout, c.log), nil - case ProtocolGraphQLTWS: - return newGQLTWSConnectionHandler(c.engineCtx, conn, c.readTimeout, c.log), nil - default: - return nil, fmt.Errorf("unknown protocol %s", conn.Subprotocol()) - } -} - -func (c *SubscriptionClient) getConnectionInitMessage(ctx context.Context, url string, header http.Header) ([]byte, error) { - if c.onWsConnectionInitCallback == nil { - return connectionInitMessage, nil - } - - callback := *c.onWsConnectionInitCallback - - payload, err := callback(ctx, url, header) - if err != nil { - return nil, err - } - - if len(payload) == 0 { - return connectionInitMessage, nil - } - - msg, err := jsonparser.Set(connectionInitMessage, payload, "payload") - if err != nil { - return nil, err - } - - return msg, nil -} - -type ConnectionHandler interface { - StartBlocking(sub Subscription) - SubscribeCH() chan<- Subscription -} - -type Subscription struct { - ctx context.Context - options GraphQLSubscriptionOptions - next chan<- []byte -} - -func waitForAck(ctx context.Context, conn *websocket.Conn) error { - timer := time.NewTimer(ackWaitTimeout) - for { - select { - case <-timer.C: - return fmt.Errorf("timeout while waiting for connection_ack") - default: - } - - msgType, msg, err := conn.Read(ctx) - if err != nil { - return err - } - if msgType != websocket.MessageText { - return fmt.Errorf("unexpected message type") - } - - respType, err := jsonparser.GetString(msg, "type") - if err != nil { - return err - } - - switch respType { - case messageTypeConnectionKeepAlive: - continue - case messageTypePing: - err := conn.Write(ctx, websocket.MessageText, []byte(pongMessage)) - if err != nil { - return fmt.Errorf("failed to send pong message: %w", err) - } - - continue - case messageTypeConnectionAck: - return nil - default: - return fmt.Errorf("expected connection_ack or ka, got %s", respType) - } - } -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_subscription_client_test.go b/pkg/engine/datasource/graphql_datasource/graphql_subscription_client_test.go deleted file mode 100644 index d0cfdb09e..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_subscription_client_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package graphql_datasource - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "strconv" - "sync" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/buger/jsonparser" - ll "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "go.uber.org/atomic" - "go.uber.org/zap" - "nhooyr.io/websocket" -) - -func logger() ll.Logger { - logger, err := zap.NewDevelopmentConfig().Build() - if err != nil { - panic(err) - } - - return ll.NewZapLogger(logger, ll.DebugLevel) -} - -func TestGetConnectionInitMessageHelper(t *testing.T) { - var callback OnWsConnectionInitCallback = func(ctx context.Context, url string, header http.Header) (json.RawMessage, error) { - return json.RawMessage(`{"authorization":"secret"}`), nil - } - - tests := []struct { - name string - callback *OnWsConnectionInitCallback - want string - }{ - { - name: "without payload", - callback: nil, - want: `{"type":"connection_init"}`, - }, - { - name: "with payload", - callback: &callback, - want: `{"type":"connection_init","payload":{"authorization":"secret"}}`, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - client := SubscriptionClient{onWsConnectionInitCallback: tt.callback} - got, err := client.getConnectionInitMessage(context.Background(), "", nil) - require.NoError(t, err) - require.NotEmpty(t, got) - - assert.Equal(t, tt.want, string(got)) - }) - } -} - -func TestWebsocketSubscriptionClientDeDuplication(t *testing.T) { - serverDone := &sync.WaitGroup{} - connectedClients := atomic.NewInt64(0) - - assertSubscription := func(ctx context.Context, conn *websocket.Conn, subscriptionID int) { - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, fmt.Sprintf(`{"type":"start","id":"%d","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, subscriptionID), string(data)) - } - - assertSendMessages := func(ctx context.Context, conn *websocket.Conn, subscriptionID int) { - err := conn.Write(ctx, websocket.MessageText, []byte(fmt.Sprintf(`{"type":"data","id":"%d","payload":{"data":{"messageAdded":{"text":"first"}}}}`, subscriptionID))) - assert.NoError(t, err) - err = conn.Write(ctx, websocket.MessageText, []byte(fmt.Sprintf(`{"type":"data","id":"%d","payload":{"data":{"messageAdded":{"text":"second"}}}}`, subscriptionID))) - assert.NoError(t, err) - err = conn.Write(ctx, websocket.MessageText, []byte(fmt.Sprintf(`{"type":"data","id":"%d","payload":{"data":{"messageAdded":{"text":"third"}}}}`, subscriptionID))) - assert.NoError(t, err) - } - - assertInitAck := func(ctx context.Context, conn *websocket.Conn) { - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - err = conn.Write(ctx, websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - } - - assertReceiveMessages := func(next chan []byte) { - first := <-next - second := <-next - third := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"third"}}}`, string(third)) - } - - assertStop := func(ctx context.Context, conn *websocket.Conn, subscriptionID ...int) { - var receivedIDs []int - expectedSum := 0 - actualSum := 0 - for _, expected := range subscriptionID { - expectedSum += expected - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - messageType, err := jsonparser.GetString(data, "type") - assert.NoError(t, err) - assert.Equal(t, "stop", messageType) - idStr, err := jsonparser.GetString(data, "id") - assert.NoError(t, err) - id, err := strconv.Atoi(idStr) - assert.NoError(t, err) - receivedIDs = append(receivedIDs, id) - actualSum += id - } - assert.Len(t, receivedIDs, 4) - assert.Equal(t, expectedSum, actualSum) - } - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - serverDone.Add(1) - defer serverDone.Done() - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - connectedClients.Inc() - defer connectedClients.Dec() - - assertInitAck(r.Context(), conn) - - assertSubscription(r.Context(), conn, 1) - assertSendMessages(r.Context(), conn, 1) - - assertSubscription(r.Context(), conn, 2) - assertSubscription(r.Context(), conn, 3) - assertSubscription(r.Context(), conn, 4) - - assertSendMessages(r.Context(), conn, 2) - assertSendMessages(r.Context(), conn, 3) - assertSendMessages(r.Context(), conn, 4) - - assertStop(r.Context(), conn, 1, 2, 3, 4) - })) - defer server.Close() - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - clientsDone := &sync.WaitGroup{} - - next := make(chan []byte) - ctx, clientCancel := context.WithCancel(context.Background()) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - assertReceiveMessages(next) - - for i := 0; i < 3; i++ { - clientsDone.Add(1) - next := make(chan []byte) - - ctx, cancel := context.WithCancel(context.Background()) - - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - go func(next chan []byte, cancel func()) { - assertReceiveMessages(next) - cancel() - clientsDone.Done() - }(next, cancel) - } - - clientCancel() - - serverDone.Wait() - clientsDone.Wait() - assert.Eventuallyf(t, func() bool { - return connectedClients.Load() == 0 - }, time.Second, time.Millisecond, "clients not 0") -} - -func TestWebsocketSubscriptionClientImmediateClientCancel(t *testing.T) { - serverInvocations := atomic.NewInt64(0) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - serverInvocations.Inc() - })) - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - clientCancel() - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.Error(t, err) - assert.Eventuallyf(t, func() bool { - return serverInvocations.Load() == 0 - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() - assert.Eventuallyf(t, func() bool { - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -func TestWebsocketSubscriptionClientWithServerDisconnect(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"start","id":"1","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assert.NoError(t, err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"second"}}}}`)) - assert.NoError(t, err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"third"}}}}`)) - assert.NoError(t, err) - - _, _, err = conn.Read(ctx) - assert.Error(t, err) - close(serverDone) - })) - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - defer clientCancel() - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - first := <-next - second := <-next - third := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"third"}}}`, string(third)) - serverCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - assert.Eventuallyf(t, func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_tws_handler.go b/pkg/engine/datasource/graphql_datasource/graphql_tws_handler.go deleted file mode 100644 index d4883a994..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_tws_handler.go +++ /dev/null @@ -1,275 +0,0 @@ -package graphql_datasource - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - "time" - - "github.com/buger/jsonparser" - log "github.com/jensneuse/abstractlogger" - "nhooyr.io/websocket" -) - -// gqlTWSConnectionHandler is responsible for handling a connection to an origin -// it is responsible for managing all subscriptions using the underlying WebSocket connection -// if all Subscriptions are complete or cancelled/unsubscribed the handler will terminate -type gqlTWSConnectionHandler struct { - conn *websocket.Conn - ctx context.Context - log log.Logger - subscribeCh chan Subscription - nextSubscriptionID int - subscriptions map[string]Subscription - readTimeout time.Duration -} - -func newGQLTWSConnectionHandler(ctx context.Context, conn *websocket.Conn, rt time.Duration, l log.Logger) *gqlTWSConnectionHandler { - return &gqlTWSConnectionHandler{ - conn: conn, - ctx: ctx, - log: l, - subscribeCh: make(chan Subscription), - nextSubscriptionID: 0, - subscriptions: map[string]Subscription{}, - readTimeout: rt, - } -} - -func (h *gqlTWSConnectionHandler) SubscribeCH() chan<- Subscription { - return h.subscribeCh -} - -func (h *gqlTWSConnectionHandler) StartBlocking(sub Subscription) { - readCtx, cancel := context.WithCancel(h.ctx) - defer func() { - h.unsubscribeAllAndCloseConn() - cancel() - }() - - h.subscribe(sub) - dataCh := make(chan []byte) - errCh := make(chan error) - go h.readBlocking(readCtx, dataCh, errCh) - - for { - if h.ctx.Err() != nil || !h.hasActiveSubscriptions() { - return - } - - select { - case <-time.After(h.readTimeout): - continue - case sub = <-h.subscribeCh: - h.subscribe(sub) - case err := <-errCh: - h.log.Error("gqlWSConnectionHandler.StartBlocking", log.Error(err)) - h.broadcastErrorMessage(err) - return - case data := <-dataCh: - messageType, err := jsonparser.GetString(data, "type") - if err != nil { - continue - } - - switch messageType { - case messageTypePing: - h.handleMessageTypePing() - case messageTypeNext: - h.handleMessageTypeNext(data) - case messageTypeComplete: - h.handleMessageTypeComplete(data) - case messageTypeError: - h.handleMessageTypeError(data) - continue - default: - h.log.Error("unknown message type", log.String("type", messageType)) - continue - } - } - } -} - -func (h *gqlTWSConnectionHandler) unsubscribeAllAndCloseConn() { - for id := range h.subscriptions { - h.unsubscribe(id) - } - _ = h.conn.Close(websocket.StatusNormalClosure, "") -} - -func (h *gqlTWSConnectionHandler) unsubscribe(subscriptionID string) { - sub, ok := h.subscriptions[subscriptionID] - if !ok { - return - } - close(sub.next) - delete(h.subscriptions, subscriptionID) - - req := fmt.Sprintf(completeMessage, subscriptionID) - err := h.conn.Write(h.ctx, websocket.MessageText, []byte(req)) - if err != nil { - h.log.Error("failed to write complete message", log.Error(err)) - } -} - -// subscribe adds a new Subscription to the gqlTWSConnectionHandler and sends the subscribeMessage to the origin -func (h *gqlTWSConnectionHandler) subscribe(sub Subscription) { - graphQLBody, err := json.Marshal(sub.options.Body) - if err != nil { - h.log.Error("failed to marshal GraphQL body", log.Error(err)) - return - } - - h.nextSubscriptionID++ - - subscriptionID := strconv.Itoa(h.nextSubscriptionID) - - subscribeRequest := fmt.Sprintf(subscribeMessage, subscriptionID, string(graphQLBody)) - err = h.conn.Write(h.ctx, websocket.MessageText, []byte(subscribeRequest)) - if err != nil { - h.log.Error("failed to write subscribe message", log.Error(err)) - return - } - - h.subscriptions[subscriptionID] = sub -} - -func (h *gqlTWSConnectionHandler) broadcastErrorMessage(err error) { - errMsg := fmt.Sprintf(errorMessageTemplate, err) - for _, sub := range h.subscriptions { - ctx, cancel := context.WithTimeout(h.ctx, time.Second*5) - select { - case sub.next <- []byte(errMsg): - cancel() - continue - case <-ctx.Done(): - cancel() - continue - } - } -} - -func (h *gqlTWSConnectionHandler) handleMessageTypeComplete(data []byte) { - id, err := jsonparser.GetString(data, "id") - if err != nil { - return - } - sub, ok := h.subscriptions[id] - if !ok { - return - } - close(sub.next) - delete(h.subscriptions, id) -} - -func (h *gqlTWSConnectionHandler) handleMessageTypeError(data []byte) { - id, err := jsonparser.GetString(data, "id") - if err != nil { - return - } - sub, ok := h.subscriptions[id] - if !ok { - return - } - - value, valueType, _, err := jsonparser.Get(data, "payload") - if err != nil { - h.log.Error( - "failed to get payload from error message", - log.Error(err), - log.ByteString("raw message", data), - ) - sub.next <- []byte(internalError) - return - } - - switch valueType { - case jsonparser.Array: - response := []byte(`{}`) - response, err = jsonparser.Set(response, value, "errors") - if err != nil { - h.log.Error( - "failed to set errors response", - log.Error(err), - log.ByteString("raw message", value), - ) - sub.next <- []byte(internalError) - return - } - sub.next <- response - default: - sub.next <- []byte(internalError) - } -} - -func (h *gqlTWSConnectionHandler) handleMessageTypePing() { - err := h.conn.Write(h.ctx, websocket.MessageText, []byte(pongMessage)) - if err != nil { - h.log.Error("failed to write pong message", log.Error(err)) - } -} - -func (h *gqlTWSConnectionHandler) handleMessageTypeNext(data []byte) { - id, err := jsonparser.GetString(data, "id") - if err != nil { - return - } - sub, ok := h.subscriptions[id] - if !ok { - return - } - - value, _, _, err := jsonparser.Get(data, "payload") - if err != nil { - h.log.Error( - "failed to get payload from next message", - log.Error(err), - ) - sub.next <- []byte(internalError) - return - } - - ctx, cancel := context.WithTimeout(h.ctx, time.Second*5) - defer cancel() - - select { - case <-ctx.Done(): - case sub.next <- value: - case <-sub.ctx.Done(): - } -} - -// readBlocking is a dedicated loop running in a separate goroutine -// because the library "nhooyr.io/websocket" doesn't allow reading with a context with Timeout -// we'll block forever on reading until the context of the gqlTWSConnectionHandler stops -func (h *gqlTWSConnectionHandler) readBlocking(ctx context.Context, dataCh chan []byte, errCh chan error) { - for { - msgType, data, err := h.conn.Read(ctx) - if ctx.Err() != nil { - errCh <- err - return - } - if err != nil { - errCh <- err - return - } - if msgType != websocket.MessageText { - continue - } - select { - case dataCh <- data: - case <-ctx.Done(): - return - } - } -} - -func (h *gqlTWSConnectionHandler) hasActiveSubscriptions() (hasActiveSubscriptions bool) { - for id, sub := range h.subscriptions { - if sub.ctx.Err() != nil { - h.unsubscribe(id) - } - } - return len(h.subscriptions) != 0 -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_tws_handler_test.go b/pkg/engine/datasource/graphql_datasource/graphql_tws_handler_test.go deleted file mode 100644 index 997908556..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_tws_handler_test.go +++ /dev/null @@ -1,380 +0,0 @@ -package graphql_datasource - -import ( - "context" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/stretchr/testify/assert" - "nhooyr.io/websocket" -) - -func TestWebsocketSubscriptionClient_GQLTWS(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"id":"1","type":"subscribe","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assert.NoError(t, err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"second"}}}}`)) - assert.NoError(t, err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"third"}}}}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"id":"1","type":"complete"}`, string(data)) - close(serverDone) - })) - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLTWS), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - - first := <-next - second := <-next - third := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"third"}}}`, string(third)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() - assert.Eventuallyf(t, func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -func TestWebsocketSubscriptionClientPing_GQLTWS(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"id":"1","type":"subscribe","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assert.NoError(t, err) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"ping"}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"pong"}`, string(data)) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"id":"1","type":"complete"}`, string(data)) - close(serverDone) - })) - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLTWS), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - - first := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() - assert.Eventuallyf(t, func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -func TestWebsocketSubscriptionClientError_GQLTWS(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - - msgType, data, err := conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"id":"1","type":"subscribe","payload":{"query":"wrongQuery {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"payload":[{"message":"Unexpected Name \"wrongQuery\"","locations":[{"line":1,"column":1}],"extensions":{"code":"GRAPHQL_PARSE_FAILED"}}],"id":"1","type":"error"}`)) - assert.NoError(t, err) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1",type":"complete"}`)) - assert.NoError(t, err) - - close(serverDone) - })) - defer server.Close() - - serverCtx, serverCancel := context.WithCancel(context.Background()) - - clientCtx, clientCancel := context.WithCancel(context.Background()) - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLTWS), - ) - - next := make(chan []byte) - err := client.Subscribe(clientCtx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `wrongQuery {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - - message := <-next - assert.Equal(t, `{"errors":[{"message":"Unexpected Name \"wrongQuery\"","locations":[{"line":1,"column":1}],"extensions":{"code":"GRAPHQL_PARSE_FAILED"}}]}`, string(message)) - - clientCancel() - _, ok := <-next - assert.False(t, ok) - - serverCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") -} - -func TestWebSocketSubscriptionClientInitIncludePing_GQLTWS(t *testing.T) { - serverDone := make(chan struct{}) - assertion := require.New(t) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assertion.NoError(err) - - // write "ping" every second - go func() { - for { - err := conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"ping"}`)) - if err != nil { - break - } - time.Sleep(time.Second) - } - }() - - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assertion.NoError(err) - - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"type":"connection_init"}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assertion.NoError(err) - - msgType, data, err = conn.Read(ctx) - assertion.NoError(err) - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"type":"pong"}`, string(data)) - - msgType, data, err = conn.Read(ctx) - assertion.NoError(err) - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"id":"1","type":"subscribe","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assertion.NoError(err) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"second"}}}}`)) - assertion.NoError(err) - - msgType, data, err = conn.Read(ctx) - assertion.NoError(err) - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"id":"1","type":"complete"}`, string(data)) - close(serverDone) - })) - - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - serverCtx, serverCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLTWS), - ) - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assertion.NoError(err) - - first := <-next - second := <-next - assertion.Equal(`{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assertion.Equal(`{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - - clientCancel() - assertion.Eventuallyf(func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() - assertion.Eventuallyf(func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -func TestWebsocketSubscriptionClient_GQLTWS_Upstream_Dies(t *testing.T) { - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - - server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"id":"1","type":"subscribe","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"id":"1","type":"next","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assert.NoError(t, err) - - <-serverCtx.Done() - })) - - // Wrap the listener to hijack the underlying TCP connection. - // Hijacking via http.ResponseWriter doesn't work because the WebSocket - // client already hijacks the connection before us. - wrappedListener := &listenerWrapper{ - listener: server.Listener, - } - server.Listener = wrappedListener - server.Start() - - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Second), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLTWS), - ) - - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - - first := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - - // Kill the upstream here. We should get an End-of-File error. - assert.NoError(t, wrappedListener.underlyingConnection.Close()) - errorMessage := <-next - assert.Equal(t, `{"errors":[{"message":"failed to get reader: failed to read frame header: EOF"}]}`, string(errorMessage)) - - clientCancel() - serverCancel() - assert.Eventuallyf(t, func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_ws_handler.go b/pkg/engine/datasource/graphql_datasource/graphql_ws_handler.go deleted file mode 100644 index a84ff7bae..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_ws_handler.go +++ /dev/null @@ -1,276 +0,0 @@ -package graphql_datasource - -import ( - "context" - "encoding/json" - "fmt" - "strconv" - "time" - - "github.com/buger/jsonparser" - "github.com/jensneuse/abstractlogger" - "nhooyr.io/websocket" -) - -// gqlWSConnectionHandler is responsible for handling a connection to an origin -// it is responsible for managing all subscriptions using the underlying WebSocket connection -// if all Subscriptions are complete or cancelled/unsubscribed the handler will terminate -type gqlWSConnectionHandler struct { - conn *websocket.Conn - ctx context.Context - log abstractlogger.Logger - subscribeCh chan Subscription - nextSubscriptionID int - subscriptions map[string]Subscription - readTimeout time.Duration -} - -func newGQLWSConnectionHandler(ctx context.Context, conn *websocket.Conn, readTimeout time.Duration, log abstractlogger.Logger) *gqlWSConnectionHandler { - return &gqlWSConnectionHandler{ - conn: conn, - ctx: ctx, - log: log, - subscribeCh: make(chan Subscription), - nextSubscriptionID: 0, - subscriptions: map[string]Subscription{}, - readTimeout: readTimeout, - } -} - -func (h *gqlWSConnectionHandler) SubscribeCH() chan<- Subscription { - return h.subscribeCh -} - -// StartBlocking starts the single threaded event loop of the handler -// if the global context returns or the websocket connection is terminated, it will stop -func (h *gqlWSConnectionHandler) StartBlocking(sub Subscription) { - readCtx, cancel := context.WithCancel(h.ctx) - defer func() { - h.unsubscribeAllAndCloseConn() - cancel() - }() - h.subscribe(sub) - dataCh := make(chan []byte) - errCh := make(chan error) - go h.readBlocking(readCtx, dataCh, errCh) - for { - err := h.ctx.Err() - if err != nil { - h.log.Error("gqlWSConnectionHandler.StartBlocking", abstractlogger.Error(err)) - h.broadcastErrorMessage(err) - return - } - hasActiveSubscriptions := h.checkActiveSubscriptions() - if !hasActiveSubscriptions { - return - } - select { - case <-time.After(h.readTimeout): - continue - case sub = <-h.subscribeCh: - h.subscribe(sub) - case err = <-errCh: - h.log.Error("gqlWSConnectionHandler.StartBlocking", abstractlogger.Error(err)) - h.broadcastErrorMessage(err) - return - case data := <-dataCh: - messageType, err := jsonparser.GetString(data, "type") - if err != nil { - continue - } - switch messageType { - case messageTypeData: - h.handleMessageTypeData(data) - case messageTypeComplete: - h.handleMessageTypeComplete(data) - case messageTypeConnectionError: - h.handleMessageTypeConnectionError() - return - case messageTypeError: - h.handleMessageTypeError(data) - continue - default: - continue - } - } - } -} - -// readBlocking is a dedicated loop running in a separate goroutine -// because the library "nhooyr.io/websocket" doesn't allow reading with a context with Timeout -// we'll block forever on reading until the context of the gqlWSConnectionHandler stops -func (h *gqlWSConnectionHandler) readBlocking(ctx context.Context, dataCh chan []byte, errCh chan error) { - for { - msgType, data, err := h.conn.Read(ctx) - if ctx.Err() != nil { - select { - case errCh <- ctx.Err(): - case <-ctx.Done(): - return - } - } - if err != nil { - select { - case errCh <- err: - case <-ctx.Done(): - return - } - } - if msgType != websocket.MessageText { - continue - } - select { - case dataCh <- data: - case <-ctx.Done(): - return - } - } -} - -func (h *gqlWSConnectionHandler) unsubscribeAllAndCloseConn() { - for id := range h.subscriptions { - h.unsubscribe(id) - } - _ = h.conn.Close(websocket.StatusNormalClosure, "") -} - -// subscribe adds a new Subscription to the gqlWSConnectionHandler and sends the startMessage to the origin -func (h *gqlWSConnectionHandler) subscribe(sub Subscription) { - graphQLBody, err := json.Marshal(sub.options.Body) - if err != nil { - return - } - - h.nextSubscriptionID++ - - subscriptionID := strconv.Itoa(h.nextSubscriptionID) - - startRequest := fmt.Sprintf(startMessage, subscriptionID, string(graphQLBody)) - err = h.conn.Write(h.ctx, websocket.MessageText, []byte(startRequest)) - if err != nil { - return - } - - h.subscriptions[subscriptionID] = sub -} - -func (h *gqlWSConnectionHandler) handleMessageTypeData(data []byte) { - id, err := jsonparser.GetString(data, "id") - if err != nil { - return - } - sub, ok := h.subscriptions[id] - if !ok { - return - } - payload, _, _, err := jsonparser.Get(data, "payload") - if err != nil { - return - } - ctx, cancel := context.WithTimeout(h.ctx, time.Second*5) - defer cancel() - - select { - case <-ctx.Done(): - case sub.next <- payload: - case <-sub.ctx.Done(): - } -} - -func (h *gqlWSConnectionHandler) handleMessageTypeConnectionError() { - for _, sub := range h.subscriptions { - ctx, cancel := context.WithTimeout(h.ctx, time.Second*5) - select { - case sub.next <- []byte(connectionError): - cancel() - continue - case <-ctx.Done(): - cancel() - continue - } - } -} - -func (h *gqlWSConnectionHandler) broadcastErrorMessage(err error) { - errMsg := fmt.Sprintf(errorMessageTemplate, err) - for _, sub := range h.subscriptions { - ctx, cancel := context.WithTimeout(h.ctx, time.Second*5) - select { - case sub.next <- []byte(errMsg): - cancel() - continue - case <-ctx.Done(): - cancel() - continue - } - } -} - -func (h *gqlWSConnectionHandler) handleMessageTypeComplete(data []byte) { - id, err := jsonparser.GetString(data, "id") - if err != nil { - return - } - sub, ok := h.subscriptions[id] - if !ok { - return - } - close(sub.next) - delete(h.subscriptions, id) -} - -func (h *gqlWSConnectionHandler) handleMessageTypeError(data []byte) { - id, err := jsonparser.GetString(data, "id") - if err != nil { - return - } - sub, ok := h.subscriptions[id] - if !ok { - return - } - value, valueType, _, err := jsonparser.Get(data, "payload") - if err != nil { - sub.next <- []byte(internalError) - return - } - switch valueType { - case jsonparser.Array: - response := []byte(`{}`) - response, err = jsonparser.Set(response, value, "errors") - if err != nil { - sub.next <- []byte(internalError) - return - } - sub.next <- response - case jsonparser.Object: - response := []byte(`{"errors":[]}`) - response, err = jsonparser.Set(response, value, "errors", "[0]") - if err != nil { - sub.next <- []byte(internalError) - return - } - sub.next <- response - default: - sub.next <- []byte(internalError) - } -} - -func (h *gqlWSConnectionHandler) unsubscribe(subscriptionID string) { - sub, ok := h.subscriptions[subscriptionID] - if !ok { - return - } - close(sub.next) - delete(h.subscriptions, subscriptionID) - stopRequest := fmt.Sprintf(stopMessage, subscriptionID) - _ = h.conn.Write(h.ctx, websocket.MessageText, []byte(stopRequest)) -} - -func (h *gqlWSConnectionHandler) checkActiveSubscriptions() (hasActiveSubscriptions bool) { - for id, sub := range h.subscriptions { - if sub.ctx.Err() != nil { - h.unsubscribe(id) - } - } - return len(h.subscriptions) != 0 -} diff --git a/pkg/engine/datasource/graphql_datasource/graphql_ws_handler_test.go b/pkg/engine/datasource/graphql_datasource/graphql_ws_handler_test.go deleted file mode 100644 index 0f8737143..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_ws_handler_test.go +++ /dev/null @@ -1,358 +0,0 @@ -package graphql_datasource - -import ( - "context" - "net" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/stretchr/testify/assert" - "nhooyr.io/websocket" -) - -func TestWebSocketSubscriptionClientInitIncludeKA_GQLWS(t *testing.T) { - serverDone := make(chan struct{}) - assertion := require.New(t) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assertion.NoError(err) - - // write "ka" every second - go func() { - for { - err := conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"ka"}`)) - if err != nil { - break - } - time.Sleep(time.Second) - } - }() - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assertion.NoError(err) - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"type":"connection_init"}`, string(data)) - - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assertion.NoError(err) - - msgType, data, err = conn.Read(ctx) - assertion.NoError(err) - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"type":"start","id":"1","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assertion.NoError(err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"second"}}}}`)) - assertion.NoError(err) - assertion.NoError(err) - - msgType, data, err = conn.Read(ctx) - assertion.NoError(err) - assertion.Equal(websocket.MessageText, msgType) - assertion.Equal(`{"type":"stop","id":"1"}`, string(data)) - close(serverDone) - })) - - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - defer clientCancel() - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assertion.NoError(err) - first := <-next - second := <-next - assertion.Equal(`{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assertion.Equal(`{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - clientCancel() - assertion.Eventuallyf(func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() - assertion.Eventuallyf(func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -func TestWebsocketSubscriptionClient_GQLWS(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"start","id":"1","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assert.NoError(t, err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"second"}}}}`)) - assert.NoError(t, err) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"third"}}}}`)) - assert.NoError(t, err) - - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"stop","id":"1"}`, string(data)) - close(serverDone) - })) - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - first := <-next - second := <-next - third := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"second"}}}`, string(second)) - assert.Equal(t, `{"data":{"messageAdded":{"text":"third"}}}`, string(third)) - clientCancel() - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") - serverCancel() - assert.Eventuallyf(t, func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -func TestWebsocketSubscriptionClientErrorArray(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - msgType, data, err := conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"start","id":"1","payload":{"query":"subscription {messageAdded(roomNam: \"room\"){text}}"}}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"error","id":"1","payload":[{"message":"error"},{"message":"error"}]}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"stop","id":"1"}`, string(data)) - _, _, err = conn.Read(r.Context()) - assert.NotNil(t, err) - close(serverDone) - })) - defer server.Close() - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - clientCtx, clientCancel := context.WithCancel(context.Background()) - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(clientCtx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomNam: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - message := <-next - assert.Equal(t, `{"errors":[{"message":"error"},{"message":"error"}]}`, string(message)) - clientCancel() - _, ok := <-next - assert.False(t, ok) - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") -} - -func TestWebsocketSubscriptionClientErrorObject(t *testing.T) { - serverDone := make(chan struct{}) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - msgType, data, err := conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"start","id":"1","payload":{"query":"subscription {messageAdded(roomNam: \"room\"){text}}"}}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"error","id":"1","payload":{"message":"error"}}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(r.Context()) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"stop","id":"1"}`, string(data)) - _, _, err = conn.Read(r.Context()) - assert.NotNil(t, err) - close(serverDone) - })) - defer server.Close() - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - clientCtx, clientCancel := context.WithCancel(context.Background()) - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Millisecond), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(clientCtx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomNam: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - message := <-next - assert.Equal(t, `{"errors":[{"message":"error"}]}`, string(message)) - clientCancel() - _, ok := <-next - assert.False(t, ok) - assert.Eventuallyf(t, func() bool { - <-serverDone - return true - }, time.Second, time.Millisecond*10, "server did not close") -} - -func TestWebsocketSubscriptionClient_GQLWS_Upstream_Dies(t *testing.T) { - serverCtx, serverCancel := context.WithCancel(context.Background()) - defer serverCancel() - - server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - conn, err := websocket.Accept(w, r, nil) - assert.NoError(t, err) - ctx := context.Background() - msgType, data, err := conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"connection_init"}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"connection_ack"}`)) - assert.NoError(t, err) - msgType, data, err = conn.Read(ctx) - assert.NoError(t, err) - assert.Equal(t, websocket.MessageText, msgType) - assert.Equal(t, `{"type":"start","id":"1","payload":{"query":"subscription {messageAdded(roomName: \"room\"){text}}"}}`, string(data)) - err = conn.Write(r.Context(), websocket.MessageText, []byte(`{"type":"data","id":"1","payload":{"data":{"messageAdded":{"text":"first"}}}}`)) - assert.NoError(t, err) - - <-serverCtx.Done() - })) - - // Wrap the listener to hijack the underlying TCP connection. - // Hijacking via http.ResponseWriter doesn't work because the WebSocket - // client already hijacks the connection before us. - wrappedListener := &listenerWrapper{ - listener: server.Listener, - } - server.Listener = wrappedListener - server.Start() - - defer server.Close() - ctx, clientCancel := context.WithCancel(context.Background()) - - // Start a new GQL subscription and exchange some messages. - client := NewGraphQLSubscriptionClient(http.DefaultClient, http.DefaultClient, serverCtx, - WithReadTimeout(time.Second), - WithLogger(logger()), - WithWSSubProtocol(ProtocolGraphQLWS), - ) - next := make(chan []byte) - err := client.Subscribe(ctx, GraphQLSubscriptionOptions{ - URL: server.URL, - Body: GraphQLBody{ - Query: `subscription {messageAdded(roomName: "room"){text}}`, - }, - }, next) - assert.NoError(t, err) - first := <-next - assert.Equal(t, `{"data":{"messageAdded":{"text":"first"}}}`, string(first)) - - // Kill the upstream here. We should get an End-of-File error. - assert.NoError(t, wrappedListener.underlyingConnection.Close()) - errorMessage := <-next - assert.Equal(t, `{"errors":[{"message":"failed to get reader: failed to read frame header: EOF"}]}`, string(errorMessage)) - - serverCancel() - clientCancel() - assert.Eventuallyf(t, func() bool { - client.handlersMu.Lock() - defer client.handlersMu.Unlock() - return len(client.handlers) == 0 - }, time.Second, time.Millisecond, "client handlers not 0") -} - -type listenerWrapper struct { - listener net.Listener - underlyingConnection net.Conn -} - -func (l *listenerWrapper) Accept() (net.Conn, error) { - conn, err := l.listener.Accept() - if err != nil { - return nil, err - } - l.underlyingConnection = conn - return l.underlyingConnection, nil -} - -func (l *listenerWrapper) Close() error { - return l.listener.Close() -} - -func (l *listenerWrapper) Addr() net.Addr { - return l.listener.Addr() -} - -var _ net.Listener = (*listenerWrapper)(nil) diff --git a/pkg/engine/datasource/graphql_datasource/graphql_ws_proto_types.go b/pkg/engine/datasource/graphql_datasource/graphql_ws_proto_types.go deleted file mode 100644 index 2569d5838..000000000 --- a/pkg/engine/datasource/graphql_datasource/graphql_ws_proto_types.go +++ /dev/null @@ -1,45 +0,0 @@ -package graphql_datasource - -// common -var ( - connectionInitMessage = []byte(`{"type":"connection_init"}`) -) - -const ( - messageTypeConnectionAck = "connection_ack" - messageTypeComplete = "complete" - messageTypeError = "error" -) - -// websocket sub-protocol: -// https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md -const ( - ProtocolGraphQLWS = "graphql-ws" - - startMessage = `{"type":"start","id":"%s","payload":%s}` - stopMessage = `{"type":"stop","id":"%s"}` - - messageTypeConnectionKeepAlive = "ka" - messageTypeData = "data" - messageTypeConnectionError = "connection_error" -) - -// websocket sub-protocol: -// https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md -const ( - ProtocolGraphQLTWS = "graphql-transport-ws" - - subscribeMessage = `{"id":"%s","type":"subscribe","payload":%s}` - pongMessage = `{"type":"pong"}` - completeMessage = `{"id":"%s","type":"complete"}` - - messageTypePing = "ping" - messageTypeNext = "next" -) - -// internal -const ( - internalError = `{"errors":[{"message":"internal error"}]}` - connectionError = `{"errors":[{"message":"connection error"}]}` - errorMessageTemplate = `{"errors":[{"message":"%s"}]}` -) diff --git a/pkg/engine/datasource/httpclient/httpclient.go b/pkg/engine/datasource/httpclient/httpclient.go deleted file mode 100644 index 1decf8cf0..000000000 --- a/pkg/engine/datasource/httpclient/httpclient.go +++ /dev/null @@ -1,251 +0,0 @@ -package httpclient - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - - "github.com/buger/jsonparser" - bytetemplate "github.com/jensneuse/byte-template" - "github.com/tidwall/gjson" - "github.com/tidwall/sjson" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/quotes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -const ( - PATH = "path" - URL = "url" - URLENCODEBODY = "url_encode_body" - BASEURL = "base_url" - METHOD = "method" - BODY = "body" - HEADER = "header" - QUERYPARAMS = "query_params" - USESSE = "use_sse" - SSEMETHODPOST = "sse_method_post" - SCHEME = "scheme" - HOST = "host" - UNNULLVARIABLES = "unnull_variables" - UNDEFINED_VARIABLES = "undefined" -) - -var ( - inputPaths = [][]string{ - {URL}, - {METHOD}, - {BODY}, - {HEADER}, - {QUERYPARAMS}, - } - subscriptionInputPaths = [][]string{ - {URL}, - {HEADER}, - {BODY}, - } -) - -func wrapQuotesIfString(b []byte) []byte { - - if bytes.HasPrefix(b, []byte("$$")) && bytes.HasSuffix(b, []byte("$$")) { - return b - } - - if bytes.HasPrefix(b, []byte("{{")) && bytes.HasSuffix(b, []byte("}}")) { - return b - } - - inType := gjson.ParseBytes(b).Type - switch inType { - case gjson.Number, gjson.String: - return b - case gjson.JSON: - var value interface{} - withoutTemplate := bytes.ReplaceAll(b, []byte("$$"), nil) - - buf := &bytes.Buffer{} - tmpl := bytetemplate.New() - _, _ = tmpl.Execute(buf, withoutTemplate, func(w io.Writer, path []byte) (n int, err error) { - return w.Write([]byte("0")) - }) - - withoutTemplate = buf.Bytes() - - err := json.Unmarshal(withoutTemplate, &value) - if err == nil { - return b - } - case gjson.False: - if bytes.Equal(b, literal.FALSE) { - return b - } - case gjson.True: - if bytes.Equal(b, literal.TRUE) { - return b - } - case gjson.Null: - if bytes.Equal(b, literal.NULL) { - return b - } - } - return quotes.WrapBytes(b) -} - -func SetInputURL(input, url []byte) []byte { - if len(url) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, URL, wrapQuotesIfString(url)) - return out -} - -func SetInputURLEncodeBody(input []byte, urlEncodeBody bool) []byte { - if !urlEncodeBody { - return input - } - out, _ := sjson.SetRawBytes(input, URLENCODEBODY, []byte("true")) - return out -} - -func SetInputFlag(input []byte, flagName string) []byte { - out, _ := sjson.SetRawBytes(input, flagName, []byte("true")) - return out -} - -func IsInputFlagSet(input []byte, flagName string) bool { - value, dataType, _, err := jsonparser.Get(input, flagName) - if err != nil { - return false - } - if dataType != jsonparser.Boolean { - return false - } - return bytes.Equal(value, literal.TRUE) -} - -func SetInputMethod(input, method []byte) []byte { - if len(method) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, METHOD, wrapQuotesIfString(method)) - return out -} - -func SetInputBody(input, body []byte) []byte { - return SetInputBodyWithPath(input, body, "") -} - -func SetInputBodyWithPath(input, body []byte, path string) []byte { - if len(body) == 0 { - return input - } - if path != "" { - path = BODY + "." + path - } else { - path = BODY - } - out, _ := sjson.SetRawBytes(input, path, wrapQuotesIfString(body)) - return out -} - -func SetInputHeader(input, headers []byte) []byte { - if len(headers) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, HEADER, wrapQuotesIfString(headers)) - return out -} - -func SetInputQueryParams(input, queryParams []byte) []byte { - if len(queryParams) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, QUERYPARAMS, wrapQuotesIfString(queryParams)) - return out -} - -func SetInputScheme(input, scheme []byte) []byte { - if len(scheme) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, SCHEME, wrapQuotesIfString(scheme)) - return out -} - -func SetInputHost(input, host []byte) []byte { - if len(host) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, HOST, wrapQuotesIfString(host)) - return out -} - -func SetInputPath(input, path []byte) []byte { - if len(path) == 0 { - return input - } - out, _ := sjson.SetRawBytes(input, PATH, wrapQuotesIfString(path)) - return out -} - -func requestInputParams(input []byte) (url, method, body, headers, queryParams []byte) { - jsonparser.EachKey(input, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) { - switch i { - case 0: - url = bytes - case 1: - method = bytes - case 2: - body = bytes - case 3: - headers = bytes - case 4: - queryParams = bytes - } - }, inputPaths...) - return -} - -func GetSubscriptionInput(input []byte) (url, header, body []byte) { - jsonparser.EachKey(input, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) { - switch i { - case 0: - url = bytes - case 1: - header = bytes - case 2: - body = bytes - } - }, subscriptionInputPaths...) - return -} - -func setUndefinedVariables(data []byte, undefinedVariables []string) ([]byte, error) { - if len(undefinedVariables) > 0 { - encoded, err := json.Marshal(undefinedVariables) - if err != nil { - return nil, err - } - return sjson.SetRawBytes(data, UNDEFINED_VARIABLES, encoded) - } - return data, nil -} - -func SetUndefinedVariables(data []byte, undefinedVariables []string) []byte { - result, err := setUndefinedVariables(data, undefinedVariables) - if err != nil { - panic(fmt.Errorf("couldn't set undefined variables: %w", err)) - } - return result -} - -func UndefinedVariables(data []byte) []string { - var undefinedVariables []string - gjson.GetBytes(data, UNDEFINED_VARIABLES).ForEach(func(key, value gjson.Result) bool { - undefinedVariables = append(undefinedVariables, value.Str) - return true - }) - return undefinedVariables -} diff --git a/pkg/engine/datasource/httpclient/httpclient_test.go b/pkg/engine/datasource/httpclient/httpclient_test.go deleted file mode 100644 index cd127e011..000000000 --- a/pkg/engine/datasource/httpclient/httpclient_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package httpclient - -import ( - "bytes" - "compress/gzip" - "context" - "io" - "net/http" - "net/http/httptest" - "net/http/httputil" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/quotes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestHttpClient(t *testing.T) { - in := SetInputMethod(nil, literal.HTTP_METHOD_GET) - assert.Equal(t, `{"method":"GET"}`, string(in)) - - in = SetInputMethod(nil, quotes.WrapBytes(literal.HTTP_METHOD_POST)) - assert.Equal(t, `{"method":"POST"}`, string(in)) - - in = SetInputURL(nil, []byte("foo.bar.com")) - assert.Equal(t, `{"url":"foo.bar.com"}`, string(in)) - - in = SetInputURL(nil, []byte("\"foo.bar.com\"")) - assert.Equal(t, `{"url":"foo.bar.com"}`, string(in)) - - in = SetInputQueryParams(nil, []byte(`{"foo":"bar"}`)) - assert.Equal(t, `{"query_params":{"foo":"bar"}}`, string(in)) - - in = SetInputHeader(nil, []byte(`{"foo":"bar"}`)) - assert.Equal(t, `{"header":{"foo":"bar"}}`, string(in)) - - in = SetInputHeader(nil, []byte(`[true]`)) - assert.Equal(t, `{"header":[true]}`, string(in)) - - in = SetInputHeader(nil, []byte(`[null]`)) - assert.Equal(t, `{"header":[null]}`, string(in)) - - in = SetInputHeader(nil, []byte(`["str"]`)) - assert.Equal(t, `{"header":["str"]}`, string(in)) - - in = SetInputBody(nil, []byte(`{"foo":"bar"}`)) - assert.Equal(t, `{"body":{"foo":"bar"}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`{"foo":"bar"}`), "variables") - assert.Equal(t, `{"body":{"variables":{"foo":"bar"}}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`query { foo }`), "query") - assert.Equal(t, `{"body":{"query":"query { foo }"}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`{ foo }`), "query") - assert.Equal(t, `{"body":{"query":"{ foo }"}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`{foo}`), "query") - assert.Equal(t, `{"body":{"query":"{foo}"}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`{`), "query") - assert.Equal(t, `{"body":{"query":"{"}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`{topProducts {upc name price}}}`), "query") - assert.Equal(t, `{"body":{"query":"{topProducts {upc name price}}}"}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`$$0$$`), "variables.foo") - assert.Equal(t, `{"body":{"variables":{"foo":$$0$$}}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`"$$0$$"`), "variables.foo") - assert.Equal(t, `{"body":{"variables":{"foo":"$$0$$"}}}`, string(in)) - - in = SetInputBodyWithPath(nil, []byte(`{"bar":$$0$$}`), "variables.foo") - assert.Equal(t, `{"body":{"variables":{"foo":{"bar":$$0$$}}}}`, string(in)) -} - -func TestHttpClientDo(t *testing.T) { - - runTest := func(ctx context.Context, input []byte, expectedOutput string) func(t *testing.T) { - return func(t *testing.T) { - out := &bytes.Buffer{} - err := Do(http.DefaultClient, ctx, input, out) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, out.String()) - } - } - - background := context.Background() - - t.Run("simple get", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := httputil.DumpRequest(r, true) - assert.NoError(t, err) - _, err = w.Write([]byte("ok")) - assert.NoError(t, err) - })) - defer server.Close() - var input []byte - input = SetInputMethod(input, []byte("GET")) - input = SetInputURL(input, []byte(server.URL)) - t.Run("net", runTest(background, input, `ok`)) - }) - - t.Run("query params simple", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fooValues := r.URL.Query()["foo"] - assert.Len(t, fooValues, 1) - assert.Equal(t, fooValues[0], "bar") - _, err := w.Write([]byte("ok")) - assert.NoError(t, err) - })) - defer server.Close() - var input []byte - input = SetInputMethod(input, []byte("GET")) - input = SetInputURL(input, []byte(server.URL)) - input = SetInputQueryParams(input, []byte(`[{"name":"foo","value":"bar"}]`)) - t.Run("net", runTest(background, input, `ok`)) - }) - - t.Run("query params multiple", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fooValues := r.URL.Query()["foo"] - assert.Len(t, fooValues, 2) - assert.Equal(t, fooValues[0], "bar") - assert.Equal(t, fooValues[1], "baz") - - yearValues := r.URL.Query()["year"] - assert.Len(t, yearValues, 1) - assert.Equal(t, yearValues[0], "2020") - - _, err := w.Write([]byte("ok")) - assert.NoError(t, err) - })) - defer server.Close() - var input []byte - input = SetInputMethod(input, []byte("GET")) - input = SetInputURL(input, []byte(server.URL)) - input = SetInputQueryParams(input, []byte(`[{"name":"foo","value":"bar"},{"name":"foo","value":"baz"},{"name":"year","value":"2020"}]`)) - t.Run("net", runTest(background, input, `ok`)) - }) - - t.Run("query params multiple as array", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fooValues := r.URL.Query()["foo"] - assert.Len(t, fooValues, 2) - assert.Equal(t, fooValues[0], "bar") - assert.Equal(t, fooValues[1], "baz") - _, err := w.Write([]byte("ok")) - assert.NoError(t, err) - })) - defer server.Close() - var input []byte - input = SetInputMethod(input, []byte("GET")) - input = SetInputURL(input, []byte(server.URL)) - input = SetInputQueryParams(input, []byte(`[{"name":"foo","value":["bar","baz"]}]`)) - t.Run("net", runTest(background, input, `ok`)) - }) - - t.Run("post", func(t *testing.T) { - body := []byte(`{"foo":"bar"}`) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, err := w.Write([]byte("ok")) - assert.NoError(t, err) - actualBody, err := io.ReadAll(r.Body) - assert.NoError(t, err) - assert.Equal(t, string(body), string(actualBody)) - })) - defer server.Close() - var input []byte - input = SetInputMethod(input, []byte("POST")) - input = SetInputBody(input, body) - input = SetInputURL(input, []byte(server.URL)) - t.Run("net", runTest(background, input, `ok`)) - }) - - t.Run("gzip", func(t *testing.T) { - body := []byte(`{"foo":"bar"}`) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - acceptEncoding := r.Header.Get("Accept-Encoding") - assert.Equal(t, "gzip", acceptEncoding) - actualBody, err := io.ReadAll(r.Body) - assert.NoError(t, err) - assert.Equal(t, string(body), string(actualBody)) - gzipWriter := gzip.NewWriter(w) - defer gzipWriter.Close() - w.Header().Set("Content-Encoding", "gzip") - _, err = gzipWriter.Write([]byte("ok")) - assert.NoError(t, err) - })) - defer server.Close() - var input []byte - input = SetInputMethod(input, []byte("POST")) - input = SetInputBody(input, body) - input = SetInputURL(input, []byte(server.URL)) - t.Run("net", runTest(background, input, `ok`)) - }) -} diff --git a/pkg/engine/datasource/httpclient/nethttpclient.go b/pkg/engine/datasource/httpclient/nethttpclient.go deleted file mode 100644 index 5acae6233..000000000 --- a/pkg/engine/datasource/httpclient/nethttpclient.go +++ /dev/null @@ -1,124 +0,0 @@ -package httpclient - -import ( - "bytes" - "compress/flate" - "compress/gzip" - "context" - "io" - "net/http" - "time" - - "github.com/buger/jsonparser" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -const ( - ContentEncodingHeader = "Content-Encoding" - AcceptEncodingHeader = "Accept-Encoding" -) - -var ( - DefaultNetHttpClient = &http.Client{ - Timeout: time.Second * 10, - Transport: &http.Transport{ - MaxIdleConnsPerHost: 1024, - TLSHandshakeTimeout: 0 * time.Second, - }, - } - queryParamsKeys = [][]string{ - {"name"}, - {"value"}, - } -) - -func Do(client *http.Client, ctx context.Context, requestInput []byte, out io.Writer) (err error) { - - url, method, body, headers, queryParams := requestInputParams(requestInput) - - request, err := http.NewRequestWithContext(ctx, string(method), string(url), bytes.NewReader(body)) - if err != nil { - return err - } - - if headers != nil { - err = jsonparser.ObjectEach(headers, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { - _, err := jsonparser.ArrayEach(value, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - if err != nil { - return - } - if len(value) == 0 { - return - } - request.Header.Add(string(key), string(value)) - }) - return err - }) - if err != nil { - return err - } - } - - if queryParams != nil { - query := request.URL.Query() - _, err = jsonparser.ArrayEach(queryParams, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - var ( - parameterName, parameterValue []byte - ) - jsonparser.EachKey(value, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) { - switch i { - case 0: - parameterName = bytes - case 1: - parameterValue = bytes - } - }, queryParamsKeys...) - if len(parameterName) != 0 && len(parameterValue) != 0 { - if bytes.Equal(parameterValue[:1], literal.LBRACK) { - _, _ = jsonparser.ArrayEach(parameterValue, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - query.Add(string(parameterName), string(value)) - }) - } else { - query.Add(string(parameterName), string(parameterValue)) - } - } - }) - if err != nil { - return err - } - request.URL.RawQuery = query.Encode() - } - - request.Header.Add("accept", "application/json") - request.Header.Add("content-type", "application/json") - - response, err := client.Do(request) - if err != nil { - return err - } - defer response.Body.Close() - - respReader, err := respBodyReader(request, response) - if err != nil { - return err - } - - _, err = io.Copy(out, respReader) - return -} - -func respBodyReader(req *http.Request, resp *http.Response) (io.ReadCloser, error) { - if req.Header.Get(AcceptEncodingHeader) == "" { - return resp.Body, nil - } - - switch resp.Header.Get(ContentEncodingHeader) { - case "gzip": - return gzip.NewReader(resp.Body) - case "deflate": - return flate.NewReader(resp.Body), nil - } - - return resp.Body, nil -} diff --git a/pkg/engine/datasource/introspection_datasource/config_factory.go b/pkg/engine/datasource/introspection_datasource/config_factory.go deleted file mode 100644 index 2ef1c80b4..000000000 --- a/pkg/engine/datasource/introspection_datasource/config_factory.go +++ /dev/null @@ -1,77 +0,0 @@ -package introspection_datasource - -import ( - "encoding/json" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type IntrospectionConfigFactory struct { - introspectionData *introspection.Data -} - -func NewIntrospectionConfigFactory(schema *ast.Document) (*IntrospectionConfigFactory, error) { - var ( - data introspection.Data - report operationreport.Report - ) - gen := introspection.NewGenerator() - gen.Generate(schema, &report, &data) - if report.HasErrors() { - return nil, report - } - - return &IntrospectionConfigFactory{introspectionData: &data}, nil -} - -func (f *IntrospectionConfigFactory) BuildFieldConfigurations() (planFields plan.FieldConfigurations) { - return plan.FieldConfigurations{ - { - TypeName: f.introspectionData.Schema.QueryType.Name, - FieldName: "__schema", - DisableDefaultMapping: true, - }, - { - TypeName: f.introspectionData.Schema.QueryType.Name, - FieldName: "__type", - DisableDefaultMapping: true, - }, - { - TypeName: "__Type", - FieldName: "fields", - DisableDefaultMapping: true, - }, - { - TypeName: "__Type", - FieldName: "enumValues", - DisableDefaultMapping: true, - }, - } -} - -func (f *IntrospectionConfigFactory) BuildDataSourceConfiguration() plan.DataSourceConfiguration { - return plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: f.dataSourceConfigQueryTypeName(), - FieldNames: []string{"__schema", "__type"}, - }, - { - TypeName: "__Type", - FieldNames: []string{"fields", "enumValues"}, - }, - }, - Factory: NewFactory(f.introspectionData), - Custom: json.RawMessage{}, - } -} - -func (f *IntrospectionConfigFactory) dataSourceConfigQueryTypeName() string { - if f.introspectionData.Schema.QueryType == nil || len(f.introspectionData.Schema.QueryType.Name) == 0 { - return "Query" - } - return f.introspectionData.Schema.QueryType.Name -} diff --git a/pkg/engine/datasource/introspection_datasource/factory.go b/pkg/engine/datasource/introspection_datasource/factory.go deleted file mode 100644 index 9cbbad2e8..000000000 --- a/pkg/engine/datasource/introspection_datasource/factory.go +++ /dev/null @@ -1,20 +0,0 @@ -package introspection_datasource - -import ( - "context" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" -) - -type Factory struct { - introspectionData *introspection.Data -} - -func NewFactory(introspectionData *introspection.Data) *Factory { - return &Factory{introspectionData: introspectionData} -} - -func (f *Factory) Planner(_ context.Context) plan.DataSourcePlanner { - return &Planner{introspectionData: f.introspectionData} -} diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_with_deprecated.golden b/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_with_deprecated.golden deleted file mode 100644 index 2b6a52bc0..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_with_deprecated.golden +++ /dev/null @@ -1,20 +0,0 @@ -[ - { - "name": "NEWHOPE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "EMPIRE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "JEDI", - "description": "", - "isDeprecated": true, - "deprecationReason": "No longer supported" - } -] diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_without_deprecated.golden b/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_without_deprecated.golden deleted file mode 100644 index c6004d0cf..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/enum_values_without_deprecated.golden +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "name": "NEWHOPE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "EMPIRE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } -] diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/fields_with_deprecated.golden b/pkg/engine/datasource/introspection_datasource/fixtures/fields_with_deprecated.golden deleted file mode 100644 index 73cf23067..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/fields_with_deprecated.golden +++ /dev/null @@ -1,41 +0,0 @@ -[ - { - "name": "me", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "No longer supported" - }, - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } -] diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/fields_without_deprecated.golden b/pkg/engine/datasource/introspection_datasource/fixtures/fields_without_deprecated.golden deleted file mode 100644 index 197680598..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/fields_without_deprecated.golden +++ /dev/null @@ -1,29 +0,0 @@ -[ - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } -] diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/not_existing_type.golden b/pkg/engine/datasource/introspection_datasource/fixtures/not_existing_type.golden deleted file mode 100644 index ec747fa47..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/not_existing_type.golden +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection.golden b/pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection.golden deleted file mode 100644 index c13884a72..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection.golden +++ /dev/null @@ -1,240 +0,0 @@ -{ - "queryType": { - "name": "Query" - }, - "mutationType": null, - "subscriptionType": null, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": "", - "fields": [ - { - "name": "me", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "No longer supported" - }, - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "ENUM", - "name": "Episode", - "description": "", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [ - { - "name": "NEWHOPE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "EMPIRE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "JEDI", - "description": "", - "isDeprecated": true, - "deprecationReason": "No longer supported" - } - ], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Droid", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The 'Boolean' scalar type represents 'true' or 'false' .", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - } - ], - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "FIELD_DEFINITION", - "ENUM_VALUE" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ], - "isRepeatable": false - } - ] -} diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection_with_custom_root_operation_types.golden b/pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection_with_custom_root_operation_types.golden deleted file mode 100644 index 49d6a0e80..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/schema_introspection_with_custom_root_operation_types.golden +++ /dev/null @@ -1,309 +0,0 @@ -{ - "queryType": { - "name": "CustomQuery" - }, - "mutationType": { - "name": "CustomMutation" - }, - "subscriptionType": { - "name": "CustomSubscription" - }, - "types": [ - { - "kind": "OBJECT", - "name": "CustomQuery", - "description": "", - "fields": [ - { - "name": "me", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "No longer supported" - }, - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "CustomMutation", - "description": "", - "fields": [ - { - "name": "destroyDroid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "CustomSubscription", - "description": "", - "fields": [ - { - "name": "destroyedDroid", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "ENUM", - "name": "Episode", - "description": "", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [ - { - "name": "NEWHOPE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "EMPIRE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "JEDI", - "description": "", - "isDeprecated": true, - "deprecationReason": "No longer supported" - } - ], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Droid", - "description": "", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The 'Boolean' scalar type represents 'true' or 'false' .", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - } - ], - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "FIELD_DEFINITION", - "ENUM_VALUE" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ], - "isRepeatable": false - } - ] -} diff --git a/pkg/engine/datasource/introspection_datasource/fixtures/type_introspection.golden b/pkg/engine/datasource/introspection_datasource/fixtures/type_introspection.golden deleted file mode 100644 index 6993a7d35..000000000 --- a/pkg/engine/datasource/introspection_datasource/fixtures/type_introspection.golden +++ /dev/null @@ -1,50 +0,0 @@ -{ - "kind": "OBJECT", - "name": "Query", - "description": "", - "fields": [ - { - "name": "me", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "No longer supported" - }, - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] -} diff --git a/pkg/engine/datasource/introspection_datasource/input.go b/pkg/engine/datasource/introspection_datasource/input.go deleted file mode 100644 index c73aab772..000000000 --- a/pkg/engine/datasource/introspection_datasource/input.go +++ /dev/null @@ -1,75 +0,0 @@ -package introspection_datasource - -import ( - "bytes" - "strconv" -) - -type requestType int - -const ( - SchemaRequestType requestType = iota + 1 - TypeRequestType - TypeFieldsRequestType - TypeEnumValuesRequestType -) - -const ( - schemaFieldName = "__schema" - typeFieldName = "__type" - fieldsFieldName = "fields" - enumValuesFieldName = "enumValues" -) - -type introspectionInput struct { - RequestType requestType `json:"request_type"` - OnTypeName *string `json:"on_type_name"` - TypeName *string `json:"type_name"` - IncludeDeprecated bool `json:"include_deprecated"` -} - -var ( - lBrace = []byte("{") - rBrace = []byte("}") - comma = []byte(",") - requestTypeField = []byte(`"request_type":`) - onTypeField = []byte(`"on_type_name":"{{ .object.name }}"`) - typeNameField = []byte(`"type_name":"{{ .arguments.name }}"`) - includeDeprecatedField = []byte(`"include_deprecated":{{ .arguments.includeDeprecated }}`) -) - -func buildInput(fieldName string) string { - buf := &bytes.Buffer{} - buf.Write(lBrace) - - switch fieldName { - case typeFieldName: - writeRequestTypeField(buf, TypeRequestType) - buf.Write(comma) - buf.Write(typeNameField) - case fieldsFieldName: - writeRequestTypeField(buf, TypeFieldsRequestType) - writeOnTypeFields(buf) - case enumValuesFieldName: - writeRequestTypeField(buf, TypeEnumValuesRequestType) - writeOnTypeFields(buf) - default: - writeRequestTypeField(buf, SchemaRequestType) - } - - buf.Write(rBrace) - - return buf.String() -} - -func writeRequestTypeField(buf *bytes.Buffer, inputType requestType) { - buf.Write(requestTypeField) - buf.Write([]byte(strconv.Itoa(int(inputType)))) -} - -func writeOnTypeFields(buf *bytes.Buffer) { - buf.Write(comma) - buf.Write(onTypeField) - buf.Write(comma) - buf.Write(includeDeprecatedField) -} diff --git a/pkg/engine/datasource/introspection_datasource/input_test.go b/pkg/engine/datasource/introspection_datasource/input_test.go deleted file mode 100644 index edec94f46..000000000 --- a/pkg/engine/datasource/introspection_datasource/input_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package introspection_datasource - -import ( - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestBuildInput(t *testing.T) { - run := func(fieldName string, expectedJson string) func(t *testing.T) { - t.Helper() - return func(t *testing.T) { - actualResult := buildInput(fieldName) - assert.Equal(t, expectedJson, actualResult) - } - } - - t.Run("schema introspection", run(schemaFieldName, `{"request_type":1}`)) - t.Run("type introspection", run(typeFieldName, `{"request_type":2,"type_name":"{{ .arguments.name }}"}`)) - t.Run("type fields", run(fieldsFieldName, `{"request_type":3,"on_type_name":"{{ .object.name }}","include_deprecated":{{ .arguments.includeDeprecated }}}`)) - t.Run("type enum values", run(enumValuesFieldName, `{"request_type":4,"on_type_name":"{{ .object.name }}","include_deprecated":{{ .arguments.includeDeprecated }}}`)) -} - -func TestUnmarshalIntrospectionInput(t *testing.T) { - run := func(input string, expected introspectionInput) func(t *testing.T) { - t.Helper() - return func(t *testing.T) { - var actual introspectionInput - require.NoError(t, json.Unmarshal([]byte(input), &actual)) - assert.Equal(t, expected, actual) - } - } - - foo := "Foo" - - t.Run("schema introspection", run(`{"request_type":1}`, introspectionInput{RequestType: SchemaRequestType})) - t.Run("type introspection", run(`{"request_type":2,"type_name":"Foo"}`, introspectionInput{RequestType: TypeRequestType, TypeName: &foo})) - t.Run("type fields", run(`{"request_type":3,"on_type_name":"Foo","include_deprecated":true}`, introspectionInput{RequestType: TypeFieldsRequestType, OnTypeName: &foo, IncludeDeprecated: true})) - t.Run("type enum values", run(`{"request_type":4,"on_type_name":"Foo","include_deprecated":false}`, introspectionInput{RequestType: TypeEnumValuesRequestType, OnTypeName: &foo, IncludeDeprecated: false})) -} diff --git a/pkg/engine/datasource/introspection_datasource/planner.go b/pkg/engine/datasource/introspection_datasource/planner.go deleted file mode 100644 index 86de31349..000000000 --- a/pkg/engine/datasource/introspection_datasource/planner.go +++ /dev/null @@ -1,54 +0,0 @@ -package introspection_datasource - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" -) - -type Planner struct { - introspectionData *introspection.Data - v *plan.Visitor - rootField int -} - -func (p *Planner) Register(visitor *plan.Visitor, _ plan.DataSourceConfiguration, _ bool) error { - p.v = visitor - visitor.Walker.RegisterEnterFieldVisitor(p) - return nil -} - -func (p *Planner) DownstreamResponseFieldAlias(_ int) (alias string, exists bool) { - // the Introspection DataSourcePlanner doesn't rewrite upstream fields: skip - return -} - -func (p *Planner) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior { - return plan.DataSourcePlanningBehavior{ - MergeAliasedRootNodes: false, - OverrideFieldPathFromAlias: false, - } -} - -func (p *Planner) EnterField(ref int) { - p.rootField = ref -} - -func (p *Planner) configureInput() string { - fieldName := p.v.Operation.FieldNameString(p.rootField) - - return buildInput(fieldName) -} - -func (p *Planner) ConfigureFetch() plan.FetchConfiguration { - return plan.FetchConfiguration{ - Input: p.configureInput(), - DataSource: &Source{ - introspectionData: p.introspectionData, - }, - } -} - -func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration { - // the Introspection DataSourcePlanner doesn't have subscription - return plan.SubscriptionConfiguration{} -} diff --git a/pkg/engine/datasource/introspection_datasource/planner_test.go b/pkg/engine/datasource/introspection_datasource/planner_test.go deleted file mode 100644 index c11e234b0..000000000 --- a/pkg/engine/datasource/introspection_datasource/planner_test.go +++ /dev/null @@ -1,460 +0,0 @@ -package introspection_datasource - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasourcetesting" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const ( - schema = ` - type Query { - friend: String - } - ` - - schemaWithCustomRootOperationTypes = ` - schema { - query: CustomQuery - mutation: CustomMutation - subscription: CustomSubscription - } - - type CustomQuery { - friend: String - } - - type CustomMutation { - addFriend: Boolean - } - - type CustomSubscription { - lastAddedFriend: String - } - ` - - typeIntrospection = ` - query typeIntrospection { - __type(name: "Query") { - name - kind - } - } - ` - - schemaIntrospection = ` - query typeIntrospection { - __schema { - queryType { - name - } - } - } - ` - - schemaIntrospectionForAllRootOperationTypeNames = ` - query typeIntrospection { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - } - } - ` - - typeIntrospectionWithArgs = ` - query typeIntrospection { - __type(name: "Query") { - fields(includeDeprecated: true) { - name - } - enumValues(includeDeprecated: true) { - name - } - } - } - ` -) - -func TestIntrospectionDataSourcePlanning(t *testing.T) { - runTest := func(schema string, introspectionQuery string, expectedPlan plan.Plan) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - def := unsafeparser.ParseGraphqlDocumentString(schema) - err := asttransform.MergeDefinitionWithBaseSchema(&def) - require.NoError(t, err) - - var ( - introspectionData introspection.Data - report operationreport.Report - ) - - gen := introspection.NewGenerator() - gen.Generate(&def, &report, &introspectionData) - require.False(t, report.HasErrors()) - - cfgFactory := IntrospectionConfigFactory{introspectionData: &introspectionData} - introspectionDataSource := cfgFactory.BuildDataSourceConfiguration() - introspectionDataSource.Factory = &Factory{} - - planConfiguration := plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{introspectionDataSource}, - Fields: cfgFactory.BuildFieldConfigurations(), - } - - datasourcetesting.RunTest(schema, introspectionQuery, "", expectedPlan, planConfiguration)(t) - } - } - - dataSourceIdentifier := []byte("introspection_datasource.Source") - - t.Run("type introspection request", runTest(schema, typeIntrospection, - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"request_type":2,"type_name":"$$0$$"}`, - DataSource: &Source{}, - DataSourceIdentifier: dataSourceIdentifier, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__type"), - Position: resolve.Position{ - Line: 3, - Column: 4, - }, - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - Position: resolve.Position{ - Line: 4, - Column: 5, - }, - }, - { - Name: []byte("kind"), - Value: &resolve.String{ - Path: []string{"kind"}, - }, - Position: resolve.Position{ - Line: 5, - Column: 5, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - - t.Run("schema introspection request", runTest(schema, schemaIntrospection, - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"request_type":1}`, - DataSource: &Source{}, - DataSourceIdentifier: dataSourceIdentifier, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__schema"), - Position: resolve.Position{ - Line: 3, - Column: 4, - }, - Value: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("queryType"), - Value: &resolve.Object{ - Path: []string{"queryType"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - Position: resolve.Position{ - Line: 5, - Column: 6, - }, - }, - }, - }, - Position: resolve.Position{ - Line: 4, - Column: 5, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - - t.Run("schema introspection request with custom root operation types", runTest(schemaWithCustomRootOperationTypes, schemaIntrospectionForAllRootOperationTypeNames, - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"request_type":1}`, - DataSource: &Source{}, - DataSourceIdentifier: dataSourceIdentifier, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__schema"), - Position: resolve.Position{ - Line: 3, - Column: 4, - }, - Value: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("queryType"), - Value: &resolve.Object{ - Path: []string{"queryType"}, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - Position: resolve.Position{ - Line: 5, - Column: 6, - }, - }, - }, - }, - Position: resolve.Position{ - Line: 4, - Column: 5, - }, - }, - { - Name: []byte("mutationType"), - Value: &resolve.Object{ - Path: []string{"mutationType"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - Position: resolve.Position{ - Line: 8, - Column: 6, - }, - }, - }, - }, - Position: resolve.Position{ - Line: 7, - Column: 5, - }, - }, - { - Name: []byte("subscriptionType"), - Value: &resolve.Object{ - Path: []string{"subscriptionType"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - Position: resolve.Position{ - Line: 11, - Column: 6, - }, - }, - }, - }, - Position: resolve.Position{ - Line: 10, - Column: 5, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - - t.Run("type introspection request with fields args", runTest(schema, typeIntrospectionWithArgs, - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"request_type":2,"type_name":"$$0$$"}`, - DataSource: &Source{}, - DataSourceIdentifier: dataSourceIdentifier, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__type"), - Position: resolve.Position{ - Line: 3, - Column: 4, - }, - Value: &resolve.Object{ - Nullable: true, - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.SingleFetch{ - BufferId: 1, - Input: `{"request_type":3,"on_type_name":"$$0$$","include_deprecated":$$1$$}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"name"}, - Renderer: resolve.NewPlainVariableRenderer(), - }, - &resolve.ContextVariable{ - Path: []string{"b"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["boolean","null"]}`), - }, - ), - DataSourceIdentifier: dataSourceIdentifier, - }, - &resolve.SingleFetch{ - BufferId: 2, - Input: `{"request_type":4,"on_type_name":"$$0$$","include_deprecated":$$1$$}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"name"}, - Renderer: resolve.NewPlainVariableRenderer(), - }, - &resolve.ContextVariable{ - Path: []string{"c"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["boolean","null"]}`), - }, - ), - DataSourceIdentifier: dataSourceIdentifier, - }, - }, - }, - Fields: []*resolve.Field{ - { - BufferID: 1, - HasBuffer: true, - Name: []byte("fields"), - Value: &resolve.Array{ - Nullable: true, - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 5, - Column: 6, - }, - }, - }, - }, - }, Position: resolve.Position{ - Line: 4, - Column: 5, - }, - }, - { - BufferID: 2, - HasBuffer: true, - Name: []byte("enumValues"), - Value: &resolve.Array{ - Nullable: true, - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 8, - Column: 6, - }, - }, - }, - }, - }, Position: resolve.Position{ - Line: 7, - Column: 5, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) -} diff --git a/pkg/engine/datasource/introspection_datasource/source.go b/pkg/engine/datasource/introspection_datasource/source.go deleted file mode 100644 index 2011d10e1..000000000 --- a/pkg/engine/datasource/introspection_datasource/source.go +++ /dev/null @@ -1,102 +0,0 @@ -package introspection_datasource - -import ( - "context" - "encoding/json" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/introspection" -) - -var ( - null = []byte("null") -) - -type Source struct { - introspectionData *introspection.Data -} - -func (s *Source) Load(ctx context.Context, input []byte, w io.Writer) (err error) { - var req introspectionInput - if err := json.Unmarshal(input, &req); err != nil { - return err - } - - switch req.RequestType { - case TypeRequestType: - return s.singleType(w, req.TypeName) - case TypeEnumValuesRequestType: - return s.enumValuesForType(w, req.OnTypeName, req.IncludeDeprecated) - case TypeFieldsRequestType: - return s.fieldsForType(w, req.OnTypeName, req.IncludeDeprecated) - } - - return json.NewEncoder(w).Encode(s.introspectionData.Schema) -} - -func (s *Source) typeInfo(typeName *string) *introspection.FullType { - if typeName == nil { - return nil - } - - for _, fullType := range s.introspectionData.Schema.Types { - if fullType.Name == *typeName { - return &fullType - } - } - return nil -} - -func (s *Source) writeNull(w io.Writer) error { - _, err := w.Write(null) - return err -} - -func (s *Source) singleType(w io.Writer, typeName *string) error { - typeInfo := s.typeInfo(typeName) - if typeInfo == nil { - return s.writeNull(w) - } - - return json.NewEncoder(w).Encode(typeInfo) -} - -func (s *Source) fieldsForType(w io.Writer, typeName *string, includeDeprecated bool) error { - typeInfo := s.typeInfo(typeName) - if typeInfo == nil { - return s.writeNull(w) - } - - if includeDeprecated { - return json.NewEncoder(w).Encode(typeInfo.Fields) - } - - fields := make([]introspection.Field, 0, len(typeInfo.Fields)) - for _, field := range typeInfo.Fields { - if !field.IsDeprecated { - fields = append(fields, field) - } - } - - return json.NewEncoder(w).Encode(fields) -} - -func (s *Source) enumValuesForType(w io.Writer, typeName *string, includeDeprecated bool) error { - typeInfo := s.typeInfo(typeName) - if typeInfo == nil { - return s.writeNull(w) - } - - if includeDeprecated { - return json.NewEncoder(w).Encode(typeInfo.EnumValues) - } - - enumValues := make([]introspection.EnumValue, 0, len(typeInfo.EnumValues)) - for _, enumValue := range typeInfo.EnumValues { - if !enumValue.IsDeprecated { - enumValues = append(enumValues, enumValue) - } - } - - return json.NewEncoder(w).Encode(enumValues) -} diff --git a/pkg/engine/datasource/introspection_datasource/source_test.go b/pkg/engine/datasource/introspection_datasource/source_test.go deleted file mode 100644 index ae8c28db0..000000000 --- a/pkg/engine/datasource/introspection_datasource/source_test.go +++ /dev/null @@ -1,111 +0,0 @@ -package introspection_datasource - -import ( - "bytes" - "context" - "encoding/json" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestSource_Load(t *testing.T) { - run := func(schema string, input string, fixtureName string) func(t *testing.T) { - t.Helper() - return func(t *testing.T) { - def, report := astparser.ParseGraphqlDocumentString(schema) - require.False(t, report.HasErrors()) - require.NoError(t, asttransform.MergeDefinitionWithBaseSchema(&def)) - - var data introspection.Data - gen := introspection.NewGenerator() - gen.Generate(&def, &report, &data) - require.False(t, report.HasErrors()) - - buf := &bytes.Buffer{} - source := &Source{introspectionData: &data} - require.NoError(t, source.Load(context.Background(), []byte(input), buf)) - - actualResponse := &bytes.Buffer{} - require.NoError(t, json.Indent(actualResponse, buf.Bytes(), "", " ")) - goldie.Assert(t, fixtureName, actualResponse.Bytes()) - } - } - - t.Run("schema introspection", run(testSchema, `{"request_type":1}`, `schema_introspection`)) - t.Run("schema introspection with custom root operation types", run(testSchemaWithCustomRootOperationTypes, `{"request_type":1}`, `schema_introspection_with_custom_root_operation_types`)) - t.Run("type introspection", run(testSchema, `{"request_type":2,"type_name":"Query"}`, `type_introspection`)) - t.Run("type introspection of not existing type", run(testSchema, `{"request_type":2,"type_name":"NotExisting"}`, `not_existing_type`)) - - t.Run("type fields", func(t *testing.T) { - t.Run("include deprecated", run(testSchema, `{"request_type":3,"on_type_name":"Query","include_deprecated":true}`, `fields_with_deprecated`)) - - t.Run("no deprecated", run(testSchema, `{"request_type":3,"on_type_name":"Query","include_deprecated":false}`, `fields_without_deprecated`)) - - t.Run("of not existing type", run(testSchema, `{"request_type":3,"on_type_name":"NotExisting","include_deprecated":true}`, `not_existing_type`)) - }) - - t.Run("type enum values", func(t *testing.T) { - t.Run("include deprecated", run(testSchema, `{"request_type":4,"on_type_name":"Episode","include_deprecated":true}`, `enum_values_with_deprecated`)) - - t.Run("no deprecated", run(testSchema, `{"request_type":4,"on_type_name":"Episode","include_deprecated":false}`, `enum_values_without_deprecated`)) - - t.Run("of not existing type", run(testSchema, `{"request_type":4,"on_type_name":"NotExisting","include_deprecated":true}`, `not_existing_type`)) - }) -} - -const testSchema = ` -schema { - query: Query -} - -type Query { - me: Droid @deprecated - droid(id: ID!): Droid -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI @deprecated -} - -type Droid { - name: String! -} -` - -const testSchemaWithCustomRootOperationTypes = ` -schema { - query: CustomQuery - mutation: CustomMutation - subscription: CustomSubscription -} - -type CustomQuery { - me: Droid @deprecated - droid(id: ID!): Droid -} - -type CustomMutation { - destroyDroid(id: ID!): Boolean! -} - -type CustomSubscription { - destroyedDroid: Droid -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI @deprecated -} - -type Droid { - name: String! -}` diff --git a/pkg/engine/datasource/rest_datasource/rest_datasource.go b/pkg/engine/datasource/rest_datasource/rest_datasource.go deleted file mode 100644 index cef2f05d8..000000000 --- a/pkg/engine/datasource/rest_datasource/rest_datasource.go +++ /dev/null @@ -1,172 +0,0 @@ -package rest_datasource - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "regexp" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type Planner struct { - client *http.Client - v *plan.Visitor - config Configuration - rootField int - operationDefinition int -} - -func (p *Planner) DownstreamResponseFieldAlias(_ int) (alias string, exists bool) { - // the REST DataSourcePlanner doesn't rewrite upstream fields: skip - return -} - -func (p *Planner) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior { - return plan.DataSourcePlanningBehavior{ - MergeAliasedRootNodes: false, - OverrideFieldPathFromAlias: false, - } -} - -func (p *Planner) EnterOperationDefinition(ref int) { - p.operationDefinition = ref -} - -type Factory struct { - Client *http.Client -} - -func (f *Factory) Planner(ctx context.Context) plan.DataSourcePlanner { - return &Planner{ - client: f.Client, - } -} - -type Configuration struct { - Fetch FetchConfiguration - Subscription SubscriptionConfiguration -} - -func ConfigJSON(config Configuration) json.RawMessage { - out, _ := json.Marshal(config) - return out -} - -type SubscriptionConfiguration struct { - PollingIntervalMillis int64 - SkipPublishSameResponse bool -} - -type FetchConfiguration struct { - URL string - Method string - Header http.Header - Query []QueryConfiguration - Body string -} - -type QueryConfiguration struct { - Name string `json:"name"` - Value string `json:"value"` -} - -func (p *Planner) Register(visitor *plan.Visitor, configuration plan.DataSourceConfiguration, isNested bool) error { - p.v = visitor - visitor.Walker.RegisterEnterFieldVisitor(p) - visitor.Walker.RegisterEnterOperationVisitor(p) - return json.Unmarshal(configuration.Custom, &p.config) -} - -func (p *Planner) EnterField(ref int) { - p.rootField = ref -} - -func (p *Planner) configureInput() []byte { - - input := httpclient.SetInputURL(nil, []byte(p.config.Fetch.URL)) - input = httpclient.SetInputMethod(input, []byte(p.config.Fetch.Method)) - input = httpclient.SetInputBody(input, []byte(p.config.Fetch.Body)) - - header, err := json.Marshal(p.config.Fetch.Header) - if err == nil && len(header) != 0 && !bytes.Equal(header, literal.NULL) { - input = httpclient.SetInputHeader(input, header) - } - - preparedQuery := p.prepareQueryParams(p.rootField, p.config.Fetch.Query) - query, err := json.Marshal(preparedQuery) - if err == nil && len(preparedQuery) != 0 { - input = httpclient.SetInputQueryParams(input, query) - } - return input -} - -func (p *Planner) ConfigureFetch() plan.FetchConfiguration { - input := p.configureInput() - return plan.FetchConfiguration{ - Input: string(input), - DataSource: &Source{ - client: p.client, - }, - DisallowSingleFlight: p.config.Fetch.Method != "GET", - DisableDataLoader: true, - } -} - -func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration { - return plan.SubscriptionConfiguration{} -} - -var ( - selectorRegex = regexp.MustCompile(`{{\s(.*?)\s}}`) -) - -func (p *Planner) prepareQueryParams(field int, query []QueryConfiguration) []QueryConfiguration { - out := make([]QueryConfiguration, 0, len(query)) -Next: - for i := range query { - matches := selectorRegex.FindAllStringSubmatch(query[i].Value, -1) - for j := range matches { - if len(matches[j]) == 2 { - path := matches[j][1] - path = strings.TrimPrefix(path, ".") - elements := strings.Split(path, ".") - if len(elements) < 2 { - continue - } - if elements[0] != "arguments" { - continue - } - argumentName := elements[1] - arg, ok := p.v.Operation.FieldArgument(field, []byte(argumentName)) - if !ok { - continue Next - } - value := p.v.Operation.Arguments[arg].Value - if value.Kind != ast.ValueKindVariable { - continue Next - } - variableName := p.v.Operation.VariableValueNameString(value.Ref) - if !p.v.Operation.OperationDefinitionHasVariableDefinition(p.operationDefinition, variableName) { - continue Next - } - } - } - out = append(out, query[i]) - } - return out -} - -type Source struct { - client *http.Client -} - -func (s *Source) Load(ctx context.Context, input []byte, w io.Writer) (err error) { - return httpclient.Do(s.client, ctx, input, w) -} diff --git a/pkg/engine/datasource/rest_datasource/rest_datasource_test.go b/pkg/engine/datasource/rest_datasource/rest_datasource_test.go deleted file mode 100644 index e15597ebd..000000000 --- a/pkg/engine/datasource/rest_datasource/rest_datasource_test.go +++ /dev/null @@ -1,1295 +0,0 @@ -package rest_datasource - -import ( - "context" - "fmt" - "io" - "net/http" - "net/http/httptest" - "strings" - "testing" - - "github.com/buger/jsonparser" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasourcetesting" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -const ( - schema = ` - type Query { - friend: Friend - withArgument(id: String!, name: String, optional: String): Friend - withArrayArguments(names: [String]): Friend - } - - type Subscription { - friend: Friend - withArgument(id: String!, name: String, optional: String): Friend - withArrayArguments(names: [String]): Friend - } - - input InputFriend { - name: String! - } - - type Mutation { - createFriend(friend: InputFriend!): Friend - } - - type Friend { - name: String - pet: Pet - phone(name: String!): String - } - - type Pet { - id: String - name: String - } - ` - - simpleOperation = ` - query { - friend { - name - } - } - ` - nestedOperation = ` - query { - friend { - name - pet { - id - name - } - } - } - ` - - argumentOperation = ` - query ArgumentQuery($idVariable: String!) { - withArgument(id: $idVariable, name: "foo") { - name - } - } - ` - - duplicatedArgumentOperationWithAlias = ` - query ArgumentQuery($idVariable: String!) { - withArgument(id: $idVariable, name: "foo") { - name - homePhone: phone(name: "home") - officePhone: phone(name: "office") - } - - aliased: withArgument(id: $idVariable, name: "bar") { - name - } - } - ` - - argumentWithoutVariablesOperation = ` - query ArgumentWithoutVariablesQuery { - withArgument(id: "123abc", name: "foo") { - name - } - } - ` - - // nolint - argumentSubscription = ` - subscription ArgumentQuery($idVariable: String!) { - withArgument(id: $idVariable, name: "foo") { - name - } - } - ` - - arrayArgumentOperation = ` - query ArgumentQuery { - withArrayArguments(names: ["foo","bar"]) { - name - } - } - ` - - createFriendOperation = ` - mutation CreateFriend($friendVariable: InputFriend!) { - createFriend(friend: $friendVariable) { - name - } - } - ` -) - -func TestFastHttpJsonDataSourcePlanning(t *testing.T) { - t.Run("get request", datasourcetesting.RunTest(schema, nestedOperation, "", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"GET","url":"https://example.com/friend"}`, - DataSource: &Source{}, - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("friend"), - Value: &resolve.Object{ - Nullable: true, - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"GET","url":"https://example.com/friend/$$0$$/pet"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"name"}, - Renderer: resolve.NewPlainVariableRenderer(), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("pet"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - Nullable: true, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"friend"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Friend", - FieldNames: []string{"pet"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend/{{ .object.name }}/pet", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "friend", - DisableDefaultMapping: true, - }, - { - TypeName: "Friend", - FieldName: "pet", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("get request with argument", datasourcetesting.RunTest(schema, argumentOperation, "ArgumentQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"GET","url":"https://example.com/$$0$$/$$1$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"idVariable"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("withArgument"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"withArgument"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/{{ .arguments.id }}/{{ .arguments.name }}", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "withArgument", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("mutation with nested argument", datasourcetesting.RunTest(schema, createFriendOperation, "CreateFriend", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"body":"{"friend":{"name":"$$0$$"}}","method":"POST","url":"https://example.com/$$0$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"friend", "name"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DisallowSingleFlight: true, - DisableDataLoader: true, - DataSourceIdentifier: []byte("rest_datasource.Source"), - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("createFriend"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{"createFriend"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/{{ .arguments.friend.name }}", - Method: "POST", - Body: "{\"friend\":{\"name\":\"{{ .arguments.friend.name }}\"}}", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "createFriend", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("post request with nested JSON body", datasourcetesting.RunTest(authSchema, ` - mutation Login ($phoneNumber: String! $a: String) { - Login: postPasswordlessStart( - postPasswordlessStartInput: { - applicationId: $a - loginId: $phoneNumber - } - ) { - code - } - } -`, "Login", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"body":{"applicationId":$$0$$,"loginId":$$1$$},"method":"POST","url":"https://example.com/passwordless_start"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"phoneNumber"}, - Renderer: resolve.NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisallowSingleFlight: true, - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("Login"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("code"), - Value: &resolve.String{ - Path: []string{"code"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Mutation", - FieldNames: []string{"postPasswordlessStart"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/passwordless_start", - Method: "POST", - Body: "{{ .arguments.postPasswordlessStartInput }}", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "postPasswordlessStart", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("get request with duplicated argument and alias", datasourcetesting.RunTest(schema, duplicatedArgumentOperationWithAlias, "ArgumentQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"GET","url":"https://example.com/$$0$$/$$1$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"idVariable"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - &resolve.SingleFetch{ - BufferId: 3, - Input: `{"method":"GET","url":"https://example.com/$$0$$/$$1$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"idVariable"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"d"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - }, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("withArgument"), - Value: &resolve.Object{ - Nullable: true, - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"GET","url":"https://example.com/friends/phone/$$0$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"b"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - &resolve.SingleFetch{ - BufferId: 2, - Input: `{"method":"GET","url":"https://example.com/friends/phone/$$0$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"c"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - { - BufferID: 1, - HasBuffer: true, - Name: []byte("homePhone"), - Value: &resolve.String{ - Path: []string{"phone"}, - Nullable: true, - }, - }, - { - BufferID: 2, - HasBuffer: true, - Name: []byte("officePhone"), - Value: &resolve.String{ - Path: []string{"phone"}, - Nullable: true, - }, - }, - }, - }, - }, - { - BufferID: 3, - HasBuffer: true, - Name: []byte("aliased"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"withArgument"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/{{ .arguments.id }}/{{ .arguments.name }}", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Friend", - FieldNames: []string{"phone"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friends/phone/{{ .arguments.name }}", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "withArgument", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - func(t *testing.T, op ast.Document, actualPlan plan.Plan) { - assert.Equal(t, `{"d":"bar","c":"office","b":"home","a":"foo"}`, string(op.Input.Variables)) - }, - )) - t.Run("get request with argument using templates with and without spaces", datasourcetesting.RunTest(schema, argumentWithoutVariablesOperation, "ArgumentWithoutVariablesQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"GET","url":"https://example.com/$$0$$/$$1$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"b"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("withArgument"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"withArgument"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/{{.arguments.id}}/{{ .arguments.name }}", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "withArgument", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - /* t.Run("polling subscription get request with argument", datasourcetesting.RunTest(schema, argumentSubscription, "ArgumentQuery", - &plan.SubscriptionResponsePlan{ - Response: &resolve.GraphQLSubscription{ - Trigger: resolve.GraphQLSubscriptionTrigger{ - Input: []byte(`{"interval":1000,"request_input":{"method":"GET","url":"https://example.com/$$0$$/$$1$$"},"skip_publish_same_response":true}`), - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"idVariable"}, - }, - &resolve.ContextVariable{ - Path: []string{"a"}, - }, - ), - }, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("withArgument"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Subscription", - FieldNames: []string{"withArgument"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/{{ .arguments.id }}/{{ .arguments.name }}", - Method: "GET", - }, - Subscription: SubscriptionConfiguration{ - PollingIntervalMillis: 1000, - SkipPublishSameResponse: true, - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Subscription", - FieldName: "withArgument", - DisableDefaultMapping: true, - }, - }, - }, - ))*/ - t.Run("post request with body", datasourcetesting.RunTest(schema, simpleOperation, "", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"body":{"foo":"bar"},"method":"POST","url":"https://example.com/friend"}`, - DataSource: &Source{}, - DisallowSingleFlight: true, - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("friend"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"friend"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend", - Method: "POST", - Body: "{\"foo\":\"bar\"}", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "friend", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("get request with headers", datasourcetesting.RunTest(schema, simpleOperation, "", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"header":{"Authorization":["Bearer 123"],"Invalid-Template":["{{ request.headers.Authorization }}"],"Token":["Bearer $$0$$"],"X-API-Key":["456"]},"method":"GET","url":"https://example.com/friend"}`, - DataSource: &Source{}, - Variables: []resolve.Variable{ - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - }, - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("friend"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"friend"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend", - Method: "GET", - Header: http.Header{ - "Authorization": []string{"Bearer 123"}, - "X-API-Key": []string{"456"}, - "Token": []string{"Bearer {{ .request.headers.Authorization }}"}, - "Invalid-Template": []string{"{{ request.headers.Authorization }}"}, - }, - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "friend", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("get request with query", datasourcetesting.RunTest(schema, argumentOperation, "ArgumentQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"query_params":[{"name":"static","value":"staticValue"},{"name":"static","value":"secondStaticValue"},{"name":"name","value":"$$0$$"},{"name":"id","value":"$$1$$"}],"method":"GET","url":"https://example.com/friend"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - &resolve.ContextVariable{ - Path: []string{"idVariable"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["string"]}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("withArgument"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"withArgument"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend", - Method: "GET", - Query: []QueryConfiguration{ - { - Name: "static", - Value: "staticValue", - }, - { - Name: "static", - Value: "secondStaticValue", - }, - { - Name: "name", - Value: "{{ .arguments.name }}", - }, - { - Name: "id", - Value: "{{ .arguments.id }}", - }, - { - Name: "optional", - Value: "{{ .arguments.optional }}", - }, - }, - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "withArgument", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("get request with array query", datasourcetesting.RunTest(schema, arrayArgumentOperation, "ArgumentQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"query_params":[{"name":"names","value":"$$0$$"}],"method":"GET","url":"https://example.com/friend"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewPlainVariableRendererWithValidation(`{"type":["array","null"],"items":{"type":["string","null"]}}`), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("withArrayArguments"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"withArrayArguments"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend", - Method: "GET", - Query: []QueryConfiguration{ - { - Name: "names", - Value: "{{ .arguments.names }}", - }, - }, - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "withArrayArguments", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) - t.Run("get request with array query", datasourcetesting.RunTest(schema, arrayArgumentOperation, "ArgumentQuery", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"GET","url":"https://example.com/friend/$$0$$"}`, - DataSource: &Source{}, - Variables: resolve.NewVariables( - &resolve.ContextVariable{ - Path: []string{"a"}, - Renderer: resolve.NewCSVVariableRenderer(resolve.JsonRootType{Value: jsonparser.String}), - }, - ), - DataSourceIdentifier: []byte("rest_datasource.Source"), - DisableDataLoader: true, - }, - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("withArrayArguments"), - Value: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"withArrayArguments"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Fetch: FetchConfiguration{ - URL: "https://example.com/friend/{{ .arguments.names }}", - Method: "GET", - }, - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "withArrayArguments", - DisableDefaultMapping: true, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "names", - RenderConfig: plan.RenderArgumentAsArrayCSV, - }, - }, - }, - }, - DisableResolveFieldPositions: true, - }, - )) -} - -func TestHttpJsonDataSource_Load(t *testing.T) { - runTests := func(t *testing.T, source *Source) { - t.Run("simple get", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, r.Method, http.MethodGet) - _, _ = w.Write([]byte(`ok`)) - })) - - defer server.Close() - - input := []byte(fmt.Sprintf(`{"method":"GET","url":"%s"}`, server.URL)) - b := &strings.Builder{} - require.NoError(t, source.Load(context.Background(), input, b)) - assert.Equal(t, `ok`, b.String()) - }) - t.Run("get with query parameters", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, r.Method, http.MethodGet) - fooQueryParam := r.URL.Query().Get("foo") - assert.Equal(t, fooQueryParam, "bar") - doubleQueryParam := r.URL.Query()["double"] - assert.Len(t, doubleQueryParam, 2) - assert.Equal(t, "first", doubleQueryParam[0]) - assert.Equal(t, "second", doubleQueryParam[1]) - _, _ = w.Write([]byte(`ok`)) - })) - - defer server.Close() - - input := []byte(fmt.Sprintf(`{"query_params":[{"name":"foo","value":"bar"},{"name":"double","value":"first"},{"name":"double","value":"second"}],"method":"GET","url":"%s"}`, server.URL)) - b := &strings.Builder{} - require.NoError(t, source.Load(context.Background(), input, b)) - assert.Equal(t, `ok`, b.String()) - }) - t.Run("get with headers", func(t *testing.T) { - authorization := "Bearer 123" - xApiKey := "456" - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, r.Method, http.MethodGet) - assert.Equal(t, authorization, r.Header.Get("Authorization")) - assert.Equal(t, xApiKey, r.Header.Get("X-API-KEY")) - assert.Equal(t, []string{"one", "two"}, r.Header["Multi"]) - assert.Equal(t, "x,y", r.Header.Get("MultiComma")) - _, notExists := r.Header[http.CanonicalHeaderKey("NotExists")] - assert.False(t, notExists) - - _, _ = w.Write([]byte(`ok`)) - })) - - defer server.Close() - - input := []byte(fmt.Sprintf(`{"method":"GET","url":"%s","header":{"Multi":["one", "two"],"MultiComma":["x,y"],"Authorization":["Bearer 123"],"Token":["%s"],"X-API-Key":["%s"],"NotExists":[""]}}`, server.URL, authorization, xApiKey)) - b := &strings.Builder{} - require.NoError(t, source.Load(context.Background(), input, b)) - assert.Equal(t, `ok`, b.String()) - }) - t.Run("post with body", func(t *testing.T) { - body := `{"foo":"bar"}` - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, http.MethodPost, r.Method) - actualBody, err := io.ReadAll(r.Body) - assert.NoError(t, err) - assert.Equal(t, string(actualBody), body) - _, _ = w.Write([]byte(`ok`)) - })) - - defer server.Close() - - input := []byte(fmt.Sprintf(`{"method":"POST","url":"%s","body":%s}`, server.URL, body)) - b := &strings.Builder{} - require.NoError(t, source.Load(context.Background(), input, b)) - assert.Equal(t, `ok`, b.String()) - }) - } - - t.Run("net/http", func(t *testing.T) { - source := &Source{ - client: http.DefaultClient, - } - runTests(t, source) - }) -} - -const authSchema = ` -type Mutation { - postPasswordlessStart(postPasswordlessStartInput: postPasswordlessStartInput): PostPasswordlessStart - postPasswordlessStartList(postPasswordlessStartInput: [postPasswordlessStartInput]): PostPasswordlessStart - postPasswordlessLogin(postPasswordlessLoginInput: postPasswordlessLoginInput): PostPasswordlessLogin -} - -type PostPasswordlessStart { - code: String -} - -input postPasswordlessStartInput { - applicationId: String - loginId: String - nested: postPasswordlessStartInput -} - -type PostPasswordlessLogin { - refreshToken: String - token: String - user: User -} - -type User { - username: String - verified: Boolean - firstName: String - lastName: String - email: String - mobilePhone: String - timezone: String -} - -input postPasswordlessLoginInput { - code: String - ipAddress: String - metaData: MetaDataInput -} - -input MetaDataInput { - device: DeviceInput -} - -input DeviceInput { - name: String -} -` diff --git a/pkg/engine/datasource/staticdatasource/static_datasource.go b/pkg/engine/datasource/staticdatasource/static_datasource.go deleted file mode 100644 index c1e31ee7f..000000000 --- a/pkg/engine/datasource/staticdatasource/static_datasource.go +++ /dev/null @@ -1,66 +0,0 @@ -package staticdatasource - -import ( - "context" - "encoding/json" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" -) - -type Configuration struct { - Data string `json:"data"` -} - -func ConfigJSON(config Configuration) json.RawMessage { - out, _ := json.Marshal(config) - return out -} - -type Factory struct{} - -func (f *Factory) Planner(ctx context.Context) plan.DataSourcePlanner { - return &Planner{} -} - -type Planner struct { - config Configuration -} - -func (p *Planner) DownstreamResponseFieldAlias(downstreamFieldRef int) (alias string, exists bool) { - // skip, not required - return -} - -func (p *Planner) DataSourcePlanningBehavior() plan.DataSourcePlanningBehavior { - return plan.DataSourcePlanningBehavior{ - MergeAliasedRootNodes: false, - OverrideFieldPathFromAlias: false, - } -} - -func (p *Planner) Register(_ *plan.Visitor, configuration plan.DataSourceConfiguration, _ bool) error { - return json.Unmarshal(configuration.Custom, &p.config) -} - -func (p *Planner) ConfigureFetch() plan.FetchConfiguration { - return plan.FetchConfiguration{ - Input: p.config.Data, - DataSource: Source{}, - DisableDataLoader: true, - DisallowSingleFlight: true, - } -} - -func (p *Planner) ConfigureSubscription() plan.SubscriptionConfiguration { - return plan.SubscriptionConfiguration{ - Input: p.config.Data, - } -} - -type Source struct{} - -func (Source) Load(ctx context.Context, input []byte, w io.Writer) (err error) { - _, err = w.Write(input) - return -} diff --git a/pkg/engine/datasource/staticdatasource/static_datasource_test.go b/pkg/engine/datasource/staticdatasource/static_datasource_test.go deleted file mode 100644 index 84b193a71..000000000 --- a/pkg/engine/datasource/staticdatasource/static_datasource_test.go +++ /dev/null @@ -1,67 +0,0 @@ -package staticdatasource - -import ( - "testing" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasourcetesting" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -const ( - definition = `type Query { hello: String }` - operation = `{ hello }` -) - -func TestStaticDataSourcePlanning(t *testing.T) { - t.Run("simple", datasourcetesting.RunTest(definition, operation, "", - &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("hello"), - Value: &resolve.String{ - Nullable: true, - }, - }, - }, - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: "world", - DataSource: Source{}, - DataSourceIdentifier: []byte("staticdatasource.Source"), - DisableDataLoader: true, - DisallowSingleFlight: true, - }, - }, - }, - }, - plan.Configuration{ - DataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"hello"}, - }, - }, - Custom: ConfigJSON(Configuration{ - Data: "world", - }), - Factory: &Factory{}, - }, - }, - Fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hello", - DisableDefaultMapping: true, - }, - }, - DisableResolveFieldPositions: true, - }, - )) -} diff --git a/pkg/engine/datasourcetesting/datasourcetesting.go b/pkg/engine/datasourcetesting/datasourcetesting.go deleted file mode 100644 index 6392e6110..000000000 --- a/pkg/engine/datasourcetesting/datasourcetesting.go +++ /dev/null @@ -1,66 +0,0 @@ -package datasourcetesting - -import ( - "context" - "encoding/json" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type CheckFunc func(t *testing.T, op ast.Document, actualPlan plan.Plan) - -func RunTest(definition, operation, operationName string, expectedPlan plan.Plan, config plan.Configuration, extraChecks ...CheckFunc) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - def := unsafeparser.ParseGraphqlDocumentString(definition) - op := unsafeparser.ParseGraphqlDocumentString(operation) - err := asttransform.MergeDefinitionWithBaseSchema(&def) - if err != nil { - t.Fatal(err) - } - norm := astnormalization.NewNormalizer(true, true) - var report operationreport.Report - norm.NormalizeOperation(&op, &def, &report) - valid := astvalidation.DefaultOperationValidator() - valid.Validate(&op, &def, &report) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - p := plan.NewPlanner(ctx, config) - actualPlan := p.Plan(&op, &def, operationName, &report) - if report.HasErrors() { - _, err := astprinter.PrintStringIndent(&def, nil, " ") - if err != nil { - t.Fatal(err) - } - _, err = astprinter.PrintStringIndent(&op, &def, " ") - if err != nil { - t.Fatal(err) - } - t.Fatal(report.Error()) - } - - actualBytes, _ := json.MarshalIndent(actualPlan, "", " ") - expectedBytes, _ := json.MarshalIndent(expectedPlan, "", " ") - - if string(expectedBytes) != string(actualBytes) { - assert.Equal(t, expectedPlan, actualPlan) - t.Error(cmp.Diff(string(expectedBytes), string(actualBytes))) - } - - for _, extraCheck := range extraChecks { - extraCheck(t, op, actualPlan) - } - } -} diff --git a/pkg/engine/plan/analyze_plan_kind.go b/pkg/engine/plan/analyze_plan_kind.go deleted file mode 100644 index 66260aa37..000000000 --- a/pkg/engine/plan/analyze_plan_kind.go +++ /dev/null @@ -1,65 +0,0 @@ -package plan - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func AnalyzePlanKind(operation, definition *ast.Document, operationName string) (subscription, streaming bool, error error) { - walker := astvisitor.NewWalker(48) - visitor := &planKindVisitor{ - Walker: &walker, - operationName: operationName, - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterOperationVisitor(visitor) - walker.RegisterEnterDirectiveVisitor(visitor) - - var report operationreport.Report - walker.Walk(operation, definition, &report) - if report.HasErrors() { - return false, false, report - } - subscription = visitor.isSubscription - streaming = visitor.hasDeferDirective || visitor.hasStreamDirective - return -} - -type planKindVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - operationName string - isSubscription, hasStreamDirective, hasDeferDirective bool -} - -func (p *planKindVisitor) EnterDirective(ref int) { - directiveName := p.operation.DirectiveNameString(ref) - ancestor := p.Ancestors[len(p.Ancestors)-1] - switch ancestor.Kind { - case ast.NodeKindField: - switch directiveName { - case "defer": - p.hasDeferDirective = true - case "stream": - p.hasStreamDirective = true - } - } -} - -func (p *planKindVisitor) EnterOperationDefinition(ref int) { - name := p.operation.OperationDefinitionNameString(ref) - if p.operationName != name { - p.SkipNode() - return - } - switch p.operation.OperationDefinitions[ref].OperationType { - case ast.OperationTypeSubscription: - p.isSubscription = true - } -} - -func (p *planKindVisitor) EnterDocument(operation, definition *ast.Document) { - p.operation, p.definition = operation, definition -} diff --git a/pkg/engine/plan/analyze_plan_kind_test.go b/pkg/engine/plan/analyze_plan_kind_test.go deleted file mode 100644 index 28cecb205..000000000 --- a/pkg/engine/plan/analyze_plan_kind_test.go +++ /dev/null @@ -1,181 +0,0 @@ -package plan - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -type expectation func(t *testing.T, subscription, streaming bool, err error) - -func mustNotErr() expectation { - return func(t *testing.T, subscription, streaming bool, err error) { - assert.NoError(t, err) - } -} - -func mustSubscription(expectSubscription bool) expectation { - return func(t *testing.T, subscription, streaming bool, err error) { - assert.Equal(t, expectSubscription, subscription) - } -} - -func mustStreaming(expectStreaming bool) expectation { - return func(t *testing.T, subscription, streaming bool, err error) { - assert.Equal(t, expectStreaming, streaming) - } -} - -func TestAnalyzePlanKind(t *testing.T) { - run := func(definition, operation, operationName string, expectations ...expectation) func(t *testing.T) { - return func(t *testing.T) { - def := unsafeparser.ParseGraphqlDocumentString(definition) - op := unsafeparser.ParseGraphqlDocumentString(operation) - err := asttransform.MergeDefinitionWithBaseSchema(&def) - if err != nil { - t.Fatal(err) - } - subscription, streaming, err := AnalyzePlanKind(&op, &def, operationName) - for i := range expectations { - expectations[i](t, subscription, streaming, err) - } - } - } - - t.Run("query", run(testDefinition, ` - query MyQuery($id: ID!) { - droid(id: $id){ - name - friends { - name - } - friends { - name - } - primaryFunction - favoriteEpisode - } - }`, - "MyQuery", - mustNotErr(), - mustStreaming(false), - mustSubscription(false), - )) - t.Run("query stream", run(testDefinition, ` - query MyQuery($id: ID!) { - droid(id: $id){ - name - friends @stream { - name - } - friends { - name - } - primaryFunction - favoriteEpisode - } - }`, - "MyQuery", - mustNotErr(), - mustStreaming(true), - mustSubscription(false), - )) - t.Run("query defer", run(testDefinition, ` - query MyQuery($id: ID!) { - droid(id: $id){ - name - friends { - name - } - friends { - name - } - primaryFunction - favoriteEpisode @defer - } - }`, - "MyQuery", - mustNotErr(), - mustStreaming(true), - mustSubscription(false), - )) - t.Run("query defer", run(testDefinition, ` - query MyQuery($id: ID!) { - droid(id: $id){ - name - friends { - name - } - friends { - name - } - primaryFunction - favoriteEpisode - } - } - query OtherDeferredQuery { - droid(id: $id){ - name - friends @stream { - name - } - } - }`, - "MyQuery", - mustNotErr(), - mustStreaming(false), - mustSubscription(false), - )) - t.Run("query defer different name", run(testDefinition, ` - query MyQuery($id: ID!) { - droid(id: $id){ - name - friends { - name - } - friends { - name - } - primaryFunction - favoriteEpisode @defer - } - }`, - "OperationNameNotExists", - mustNotErr(), - mustStreaming(false), - mustSubscription(false), - )) - t.Run("subscription", run(testDefinition, ` - subscription RemainingJedis { - remainingJedis - }`, - "RemainingJedis", - mustNotErr(), - mustStreaming(false), - mustSubscription(true), - )) - t.Run("subscription with streaming", run(testDefinition, ` - subscription NewReviews { - newReviews { - id - stars @defer - } - }`, - "NewReviews", - mustNotErr(), - mustStreaming(true), - mustSubscription(true), - )) - t.Run("subscription name not exists", run(testDefinition, ` - subscription RemainingJedis { - remainingJedis - }`, - "OperationNameNotExists", - mustNotErr(), - mustStreaming(false), - mustSubscription(false), - )) -} diff --git a/pkg/engine/plan/local_type_field_extractor.go b/pkg/engine/plan/local_type_field_extractor.go deleted file mode 100644 index 7408fcb27..000000000 --- a/pkg/engine/plan/local_type_field_extractor.go +++ /dev/null @@ -1,349 +0,0 @@ -package plan - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -const FederationKeyDirectiveName = "key" - -const ( - federationRequireDirectiveName = "requires" - federationExternalDirectiveName = "external" -) - -// LocalTypeFieldExtractor takes an ast.Document as input and generates the -// TypeField configuration for both root and child nodes. Root nodes are the -// root operation types (usually Query, Mutation and Schema--though these types -// can be configured via the schema keyword) plus "entities" as defined by the -// Apollo federation specification. In short, entities are types with a @key -// directive. Child nodes are field types recursively accessible via a root -// node. Nodes are either object or interface definitions or extensions. Root -// nodes only include "local" fields; they don't include fields that have the -// @external directive. -type LocalTypeFieldExtractor struct { - document *ast.Document - queryTypeName string - mutationTypeName string - subscriptionTypeName string - nodeInfoMap map[string]*nodeInformation - possibleInterfaceTypes map[string][]string - rootNodeNames *rootNodeNamesMap - childrenSeen map[string]struct{} - childrenToProcess []string - rootNodes []TypeField - childNodes []TypeField -} - -func NewLocalTypeFieldExtractor(document *ast.Document) *LocalTypeFieldExtractor { - return &LocalTypeFieldExtractor{ - document: document, - queryTypeName: "Query", - mutationTypeName: "Mutation", - subscriptionTypeName: "Subscription", - rootNodes: make([]TypeField, 0), - childNodes: make([]TypeField, 0), - } -} - -type nodeInformation struct { - typeName string - hasKeyDirective bool - isInterface bool - isRoot bool - concreteTypeNames []string - localFieldRefs []int - externalFieldRefs []int - requiredFields map[string]struct{} -} - -type rootNodeNamesMap struct { - index int - names map[string]int -} - -func newRootNodeNamesMap() *rootNodeNamesMap { - return &rootNodeNamesMap{ - index: 0, - names: map[string]int{}, - } -} - -func (r *rootNodeNamesMap) append(name string) { - if _, ok := r.names[name]; ok { - return - } - - r.names[name] = r.index - r.index++ -} - -func (r *rootNodeNamesMap) asSlice() []string { - s := make([]string, len(r.names)) - for name, i := range r.names { - s[i] = name - } - - return s -} - -// GetAllNodes returns all root and child nodes in the document associated with -// the LocalTypeFieldExtractor. See LocalTypeFieldExtractor for a detailed -// explanation of what root and child nodes are. -func (e *LocalTypeFieldExtractor) GetAllNodes() ([]TypeField, []TypeField) { - // The strategy for the extractor is as follows: - // - // 1. Loop over each node in the document and collect information into - // "node info" structs. All document nodes are processed before creating - // the final "root" and "child" plan nodes because multiple document - // nodes may correspond to a single "node info" struct. For example, - // `type User { ... }` and `extend type User { ... }` nodes will - // correspond to a single User struct. - // - // 2. Build root nodes for each node info struct identified as a root node. - // - // 3. Push the root node info structs into a queue and construct a child - // node for each info struct in the queue. After constructing a child - // node, loop over the fields of the child type and add any object or - // abstract type to the queue if the type hasn't yet been processed. An - // abstract type is either an interface or union. When processing - // abstract types, also add the corresponding concrete types to the - // queue (i.e. all the types that implement an interface and union - // members). Note that child nodes aren't created for union types--only - // union members--since it ISN'T possible to select directly from a - // union; union selection sets MUST contain fragments. - - e.nodeInfoMap = make(map[string]*nodeInformation, len(e.document.RootNodes)) - e.possibleInterfaceTypes = map[string][]string{} - e.rootNodeNames = newRootNodeNamesMap() - e.overrideRootOperationTypeNames() - - // 1. Loop over each node in the document (see description above). - e.collectNodeInformation() - - // Record the concrete types for each interface. - e.assignConcreteTypesToInterfaces() - - // Make sure that root and child node slices are cleared - e.resetRootAndChildNodes() - - // 2. Create the root nodes. Also, loop over the fields to find additional - // child nodes to process. - e.createRootNodes() - - // 3. Process the child node queue to create child nodes. When processing - // child nodes, loop over the fields of the child to find additional - // children to process. - e.createChildNodes() - - return e.rootNodes, e.childNodes -} - -func (e *LocalTypeFieldExtractor) overrideRootOperationTypeNames() { - indexedQueryTypeName := string(e.document.Index.QueryTypeName) - if indexedQueryTypeName != "" && indexedQueryTypeName != e.queryTypeName { - e.queryTypeName = indexedQueryTypeName - } - - indexedMutationTypeName := string(e.document.Index.MutationTypeName) - if indexedMutationTypeName != "" && indexedMutationTypeName != e.mutationTypeName { - e.mutationTypeName = indexedMutationTypeName - } - - indexedSubscriptionTypeName := string(e.document.Index.SubscriptionTypeName) - if indexedSubscriptionTypeName != "" && indexedSubscriptionTypeName != e.subscriptionTypeName { - e.subscriptionTypeName = indexedSubscriptionTypeName - } -} - -func (e *LocalTypeFieldExtractor) collectNodeInformation() { - for _, astNode := range e.document.RootNodes { - nodeInfo := e.getNodeInfo(astNode) - - switch astNode.Kind { - case ast.NodeKindObjectTypeDefinition, ast.NodeKindObjectTypeExtension: - for _, ref := range e.document.NodeInterfaceRefs(astNode) { - interfaceName := e.document.ResolveTypeNameString(ref) - // The document doesn't provide a way to directly look up the - // types that implement an interface, so instead we track the - // interfaces implemented for each type and after all nodes - // have been processed record the concrete types for each - // interface. - e.possibleInterfaceTypes[interfaceName] = append( - e.possibleInterfaceTypes[interfaceName], nodeInfo.typeName) - } - case ast.NodeKindInterfaceTypeDefinition, ast.NodeKindInterfaceTypeExtension: - nodeInfo.isInterface = true - case ast.NodeKindUnionTypeDefinition, ast.NodeKindUnionTypeExtension: - for _, ref := range e.document.NodeUnionMemberRefs(astNode) { - // Local union extensions are disjoint. For details, see the GraphQL - // spec: https://spec.graphql.org/October2021/#sec-Union-Extensions - memberName := e.document.ResolveTypeNameString(ref) - nodeInfo.concreteTypeNames = append(nodeInfo.concreteTypeNames, memberName) - } - default: - continue - } - - nodeInfo.isRoot = nodeInfo.isRoot || e.isRootNode(nodeInfo) - if nodeInfo.isRoot { - e.rootNodeNames.append(nodeInfo.typeName) - } - - // Record the local, external, and required fields separately for later - // processing. Root nodes only include local fields, while child nodes - // include all three fields. - e.collectFieldDefinitions(astNode, nodeInfo) - } -} - -func (e *LocalTypeFieldExtractor) getNodeInfo(node ast.Node) *nodeInformation { - typeName := e.document.NodeNameString(node) - nodeInfo, ok := e.nodeInfoMap[typeName] - if ok { - // if this node has the key directive, we need to add it to the node information - nodeInfo.hasKeyDirective = nodeInfo.hasKeyDirective || e.document.NodeHasDirectiveByNameString(node, FederationKeyDirectiveName) - return nodeInfo - } - - nodeInfo = &nodeInformation{ - typeName: typeName, - hasKeyDirective: e.document.NodeHasDirectiveByNameString(node, FederationKeyDirectiveName), - requiredFields: make(map[string]struct{}), - } - - e.nodeInfoMap[typeName] = nodeInfo - return nodeInfo -} - -func (e *LocalTypeFieldExtractor) isRootNode(nodeInfo *nodeInformation) bool { - isFederationEntity := nodeInfo.hasKeyDirective && !nodeInfo.isInterface - return nodeInfo.typeName == e.queryTypeName || - nodeInfo.typeName == e.mutationTypeName || - nodeInfo.typeName == e.subscriptionTypeName || - isFederationEntity -} - -func (e *LocalTypeFieldExtractor) collectFieldDefinitions(node ast.Node, nodeInfo *nodeInformation) { - for _, ref := range e.document.NodeFieldDefinitions(node) { - isExternal := e.document.FieldDefinitionHasNamedDirective(ref, - federationExternalDirectiveName) - - if isExternal { - nodeInfo.externalFieldRefs = append(nodeInfo.externalFieldRefs, ref) - } else { - nodeInfo.localFieldRefs = append(nodeInfo.localFieldRefs, ref) - } - - requiredFields := requiredFieldsByRequiresDirective(e.document, ref) - for _, field := range requiredFields { - nodeInfo.requiredFields[field] = struct{}{} - } - } -} - -func (e *LocalTypeFieldExtractor) assignConcreteTypesToInterfaces() { - for interfaceName, concreteTypeNames := range e.possibleInterfaceTypes { - if nodeInfo, ok := e.nodeInfoMap[interfaceName]; ok { - nodeInfo.concreteTypeNames = concreteTypeNames - } - } -} - -// pushChildIfNotAlreadyProcessed pushes a child type onto the queue if it -// hasn't already been processed. Only types with node info are pushed onto -// the queue. Recall that node info is limited to object types, interfaces -// and union members above. -func (e *LocalTypeFieldExtractor) pushChildIfNotAlreadyProcessed(typeName string) { - if _, ok := e.childrenSeen[typeName]; !ok { - if _, ok := e.nodeInfoMap[typeName]; ok { - e.childrenToProcess = append(e.childrenToProcess, typeName) - } - e.childrenSeen[typeName] = struct{}{} - } -} - -// processFieldRef pushes node info for the field's type as well as--in the -// case of abstract types--node info for each concrete type. -func (e *LocalTypeFieldExtractor) processFieldRef(ref int) string { - fieldType := e.document.FieldDefinitionType(ref) - fieldTypeName := e.document.ResolveTypeNameString(fieldType) - e.pushChildIfNotAlreadyProcessed(fieldTypeName) - if nodeInfo, ok := e.nodeInfoMap[fieldTypeName]; ok { - for _, name := range nodeInfo.concreteTypeNames { - e.pushChildIfNotAlreadyProcessed(name) - } - } - return e.document.FieldDefinitionNameString(ref) -} - -func (e *LocalTypeFieldExtractor) resetRootAndChildNodes() { - e.rootNodes = e.rootNodes[:0] - e.childNodes = e.childNodes[:0] - - // This is the queue used in step 3, child node construction. - e.childrenSeen = make(map[string]struct{}, len(e.nodeInfoMap)) - e.childrenToProcess = make([]string, 0, len(e.nodeInfoMap)) -} - -func (e *LocalTypeFieldExtractor) createRootNodes() { - for _, typeName := range e.rootNodeNames.asSlice() { - nodeInfo := e.nodeInfoMap[typeName] - numFields := len(nodeInfo.localFieldRefs) - if numFields == 0 { - continue - } - fieldNames := make([]string, numFields) - for i, ref := range nodeInfo.localFieldRefs { - fieldNames[i] = e.processFieldRef(ref) - } - e.rootNodes = append(e.rootNodes, TypeField{ - TypeName: typeName, - FieldNames: fieldNames, - }) - } -} - -func (e *LocalTypeFieldExtractor) createChildNodes() { - for len(e.childrenToProcess) > 0 { - typeName := e.childrenToProcess[len(e.childrenToProcess)-1] - e.childrenToProcess = e.childrenToProcess[:len(e.childrenToProcess)-1] - nodeInfo, ok := e.nodeInfoMap[typeName] - if !ok { - continue - } - numFields := len(nodeInfo.localFieldRefs) + len(nodeInfo.externalFieldRefs) - if numFields == 0 { - continue - } - fieldNames := make([]string, 0, numFields) - for _, ref := range nodeInfo.localFieldRefs { - fieldNames = append(fieldNames, e.processFieldRef(ref)) - } - for _, ref := range nodeInfo.externalFieldRefs { - // We assume that a field is marked @external for only three - // reasons: - // 1) the enclosing type is using it as a @key field - // 2) another field in this datasource @provide's it - // 3) another field in the enclosing type @require's it - // In the first two cases, that means that this datasource - // knows the value of the field, and thus we want to include - // the field in our ChildNodes. In the last case, this - // datasource does *not* know the value of the field, so - // we don't include it. - // (Note it's legal for someone to add an `@external` - // field to their extended type just for the heck of it, - // and never use that field for anything. The code below - // will wrongly say that this datasource can provide its - // value. Hopefully people don't actually do that.) - fieldName := e.processFieldRef(ref) - _, isRequired := nodeInfo.requiredFields[fieldName] - if !isRequired { - fieldNames = append(fieldNames, fieldName) - } - } - e.childNodes = append(e.childNodes, TypeField{ - TypeName: typeName, - FieldNames: fieldNames, - }) - } -} diff --git a/pkg/engine/plan/local_type_field_extractor_test.go b/pkg/engine/plan/local_type_field_extractor_test.go deleted file mode 100644 index 71ffd6067..000000000 --- a/pkg/engine/plan/local_type_field_extractor_test.go +++ /dev/null @@ -1,944 +0,0 @@ -package plan - -import ( - "sort" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func sortNodesAndFields(nodes []TypeField) { - sort.Slice(nodes, func(i, j int) bool { - return nodes[i].TypeName < nodes[j].TypeName - }) - for i := range nodes { - sort.Strings(nodes[i].FieldNames) - } -} - -func TestLocalTypeFieldExtractor_GetAllNodes(t *testing.T) { - run := func(t *testing.T, SDL string, expectedRoot, expectedChild []TypeField) { - t.Helper() - - document := unsafeparser.ParseGraphqlDocumentString(SDL) - extractor := NewLocalTypeFieldExtractor(&document) - gotRoot, gotChild := extractor.GetAllNodes() - - sortNodesAndFields(gotRoot) - sortNodesAndFields(gotChild) - - assert.Equal(t, expectedRoot, gotRoot, "root nodes dont match") - assert.Equal(t, expectedChild, gotChild, "child nodes dont match") - } - - t.Run("only root operation", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - } - - extend type Mutation { - addUser(id: ID!): User - deleteUser(id: ID!): User - } - - extend type Subscription { - userChanges(id: ID!): User! - } - - type User { - id: ID! - } - `, - []TypeField{ - {TypeName: "Mutation", FieldNames: []string{"addUser", "deleteUser"}}, - {TypeName: "Query", FieldNames: []string{"me"}}, - {TypeName: "Subscription", FieldNames: []string{"userChanges"}}, - }, - []TypeField{ - {TypeName: "User", FieldNames: []string{"id"}}, - }) - }) - t.Run("orphan pair", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - } - - type User { - id: ID! - } - - # This type isn't connected to a root node, so - # it doesn't show up as a child node. - type OrphanOne { - id: ID! - two: OrphanTwo - } - - type OrphanTwo { - id: ID! - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"me"}}, - }, - []TypeField{ - {TypeName: "User", FieldNames: []string{"id"}}, - }) - }) - t.Run("orphan cycle", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - } - - type User { - id: ID! - } - - # This type isn't connected to a root node, so - # it doesn't show up as a child node. - type OrphanOne { - id: ID! - two: OrphanTwo - } - - type OrphanTwo { - id: ID! - one: OrphanOne - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"me"}}, - }, - []TypeField{ - {TypeName: "User", FieldNames: []string{"id"}}, - }) - }) - t.Run("nested child nodes", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - review(id: ID!): Review - user(id: ID!): User - } - - type User { - id: ID! - reviews: [Review!]! - } - - type Review { - id: ID! - comment: String! - rating: Int! - user: User - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"me", "review", "user"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }) - }) - t.Run("child node only available via nested child", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - } - - type User { - id: ID! - reviews: [Review!]! - } - - # The Review type is connected to the Query root node via the User - # type. It should therefore be found and included as a child node. - type Review { - id: ID! - comment: String! - rating: Int! - user: User - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"me"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }) - }) - t.Run("interface", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - communication(id: ID!): Communication - user(id: ID!): User - } - - type User { - id: ID! - communications: [Communication!]! - } - - type Review implements Communication { - id: ID! - comment: String! - rating: Int! - user: User - } - - type Comment implements Communication { - id: ID! - comment: String! - user: User - } - - interface Communication { - id: ID! - comment: String! - user: User - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"communication", "me", "user"}}, - }, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Communication", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"communications", "id"}}, - }) - }) - t.Run("interface with key directive", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - communication(id: ID!): Communication - user(id: ID!): User - } - - type User { - id: ID! - communications: [Communication!]! - } - - type Review implements Communication @key(fields: "id") { - id: ID! - comment: String! - rating: Int! - user: User - } - - type Comment implements Communication @key(fields: "id") { - id: ID! - comment: String! - user: User - } - - # A key directive on an interface is allowed, but it doesn't make - # the interface a root node. Entity queries can only be made for - # concrete types. - interface Communication @key(fields: "id") { - id: ID! - comment: String! - user: User - } - `, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Query", FieldNames: []string{"communication", "me", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - }, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Communication", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"communications", "id"}}, - }) - }) - t.Run("extended interface", func(t *testing.T) { - t.Log("Bug: The concrete types that implement an interface should also be included") - - run(t, ` - extend type Query { - me: User - communication(id: ID!): Communication - user(id: ID!): User - } - - type User { - id: ID! - communications: [Communication!]! - } - - extend type Review implements Communication @key(fields: "id") { - id: ID! @external - comment: String! - rating: Int! - user: User - } - - extend type Comment implements Communication @key(fields: "id") { - id: ID! @external - comment: String! - user: User - } - - extend interface Communication @key(fields: "id") { - id: ID! @external - comment: String! - user: User - } - `, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "user"}}, - {TypeName: "Query", FieldNames: []string{"communication", "me", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "rating", "user"}}, - }, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Communication", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"communications", "id"}}, - }) - }) - t.Run("union", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - communication(id: ID!): Communication - user(id: ID!): User - } - - type User { - id: ID! - communications: [Communication!]! - } - - type Review { - id: ID! - comment: String! - rating: Int! - user: User - } - - type Comment { - id: ID! - comment: String! - user: User - } - - union Communication = Review | Comment - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"communication", "me", "user"}}, - }, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"communications", "id"}}, - }) - }) - t.Run("extended union", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - communication(id: ID!): Communication - user(id: ID!): User - } - - type User { - id: ID! - communications: [Communication!]! - } - - extend type Review @key(fields: "id") { - id: ID! @external - comment: String! - rating: Int! - user: User - } - - extend type Comment @key(fields: "id") { - id: ID! @external - comment: String! - user: User - } - - extend union Communication = Review | Comment - `, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "user"}}, - {TypeName: "Query", FieldNames: []string{"communication", "me", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "rating", "user"}}, - }, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"communications", "id"}}, - }) - }) - t.Run("local union extension", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - communication(id: ID!): Communication - user(id: ID!): User - } - - type User { - id: ID! - communications: [Communication!]! - } - - type Review { - id: ID! @external - comment: String! - rating: Int! - user: User - } - - type Comment { - id: ID! @external - comment: String! - user: User - } - - type Post { - id: ID! - content: String! - } - - union Communication = Review | Comment - - extend union Communication = Post - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"communication", "me", "user"}}, - }, - []TypeField{ - {TypeName: "Comment", FieldNames: []string{"comment", "id", "user"}}, - {TypeName: "Post", FieldNames: []string{"content", "id"}}, - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating", "user"}}, - {TypeName: "User", FieldNames: []string{"communications", "id"}}, - }) - }) - t.Run("Entity definition", func(t *testing.T) { - run(t, ` - type User @key(fields: "id") { - id: ID! - reviews: [Review!]! - } - - type Review { - id: ID! - comment: String! - rating: Int! - } - `, - []TypeField{ - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating"}}, - }) - }) - t.Run("nested Entity definition", func(t *testing.T) { - run(t, ` - extend type Query { - me: User - } - - type User @key(fields: "id") { - id: ID! - reviews: [Review!]! - } - - type Review { - id: ID! - comment: String! - rating: Int! - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"me"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"comment", "id", "rating"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }) - }) - t.Run("extended Entity", func(t *testing.T) { - run(t, ` - extend type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review!] - } - - type Review { - comment: String! - author: User! @provide(fields: "username") - } - `, - []TypeField{ - {TypeName: "User", FieldNames: []string{"reviews"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"author", "comment"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews", "username"}}, - }) - }) - t.Run("extended Entity without local fields", func(t *testing.T) { - run(t, ` - extend type Query { - review(id: ID!): Review - } - - # This entity doesn't define any local fields, so it shouldn't be - # included as a root node. - extend type User @key(fields: "id") { - id: ID! @external - } - - type Review { - comment: String! - author: User! - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"review"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"author", "comment"}}, - {TypeName: "User", FieldNames: []string{"id"}}, - }) - }) - t.Run("extended Entity with root definitions", func(t *testing.T) { - run(t, ` - extend type Query { - reviews(IDs: [ID!]!): [Review!] - } - - extend type User @key(fields: "id") { - id: ID! @external - reviews: [Review!] - } - - type Review { - id: String! - comment: String! - author: User! - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"reviews"}}, - {TypeName: "User", FieldNames: []string{"reviews"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"author", "comment", "id"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }) - }) - t.Run("extended Entity with required fields", func(t *testing.T) { - run(t, ` - extend type User @key(fields: "id") { - id: ID! @external - username: String! @external - lastname: String! @external - - reviews: [Review!] - fullname: String @requires(fields: "{ lastname }") - } - - type Review { - comment: String! - author: User! @provide(fields: "username") - } - `, - []TypeField{ - {TypeName: "User", FieldNames: []string{"fullname", "reviews"}}, - }, - []TypeField{ - {TypeName: "Review", FieldNames: []string{"author", "comment"}}, - {TypeName: "User", FieldNames: []string{"fullname", "id", "reviews", "username"}}, - }) - }) - t.Run("local type extension", func(t *testing.T) { - run(t, ` - extend type Query { - reviews(IDs: [ID!]!): [Review!] - products(IDs: [ID!]!): [Product!] - } - - extend type User @key(fields: "id") { - id: ID! @external - reviews: [Review!] - } - - type Review { - id: String! - author: User! - } - - extend type Review { - comment: String! - } - - # Product is an owned federated type that also has a local type - # extension. - - type Product @key(fields: "id") { - id: ID! - addedBy: User! - } - - extend type Product { - description: String! - } - `, - []TypeField{ - {TypeName: "Product", FieldNames: []string{"addedBy", "description", "id"}}, - {TypeName: "Query", FieldNames: []string{"products", "reviews"}}, - {TypeName: "User", FieldNames: []string{"reviews"}}, - }, - []TypeField{ - {TypeName: "Product", FieldNames: []string{"addedBy", "description", "id"}}, - {TypeName: "Review", FieldNames: []string{"author", "comment", "id"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }) - }) - t.Run("local type extension defined before local type", func(t *testing.T) { - run(t, ` - extend type Query { - reviews(IDs: [ID!]!): [Review!] - products(IDs: [ID!]!): [Product!] - } - - extend type User @key(fields: "id") { - id: ID! @external - reviews: [Review!] - } - - extend type Review { - comment: String! - } - - type Review { - id: ID! - author: User! - } - - # Product is an owned federated type that also has a local type - # extension. - - extend type Product { - description: String! - } - - type Product @key(fields: "id") { - id: ID! - addedBy: User! - } - `, - []TypeField{ - {TypeName: "Product", FieldNames: []string{"addedBy", "description", "id"}}, - {TypeName: "Query", FieldNames: []string{"products", "reviews"}}, - {TypeName: "User", FieldNames: []string{"reviews"}}, - }, - []TypeField{ - {TypeName: "Product", FieldNames: []string{"addedBy", "description", "id"}}, - {TypeName: "Review", FieldNames: []string{"author", "comment", "id"}}, - {TypeName: "User", FieldNames: []string{"id", "reviews"}}, - }) - }) - t.Run("union types", func(t *testing.T) { - run(t, ` - extend type Query { - search(name: String!): SearchResult - } - - union SearchResult = Human | Droid | Starship - - interface Character { - name: String! - friends: [Character] - } - - type Human implements Character { - name: String! - height: String! - friends: [Character] - } - - type Droid implements Character { - name: String! - primaryFunction: String! - friends: [Character] - } - - type Starship { - name: String! - length: Float! - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"search"}}, - }, - []TypeField{ - {TypeName: "Character", FieldNames: []string{"friends", "name"}}, - {TypeName: "Droid", FieldNames: []string{"friends", "name", "primaryFunction"}}, - {TypeName: "Human", FieldNames: []string{"friends", "height", "name"}}, - {TypeName: "Starship", FieldNames: []string{"length", "name"}}, - }) - }) - t.Run("interface types", func(t *testing.T) { - run(t, ` - extend type Query { - search(name: String!): Character - } - - interface Character { - name: String! - friends: [Character] - } - - type Human implements Character { - name: String! - height: String! - friends: [Character] - } - - type Droid implements Character { - name: String! - primaryFunction: String! - friends: [Character] - } - `, - []TypeField{ - {TypeName: "Query", FieldNames: []string{"search"}}, - }, - []TypeField{ - {TypeName: "Character", FieldNames: []string{"friends", "name"}}, - {TypeName: "Droid", FieldNames: []string{"friends", "name", "primaryFunction"}}, - {TypeName: "Human", FieldNames: []string{"friends", "height", "name"}}, - }) - }) -} - -func BenchmarkGetAllNodes(b *testing.B) { - document := unsafeparser.ParseGraphqlDocumentString(benchmarkSDL) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - extractor := NewLocalTypeFieldExtractor(&document) - extractor.GetAllNodes() - } -} - -const benchmarkSDL = ` - extend type Query { - ownedA: OwnedA! - ownedB: OwnedB! - ownedC: OwnedC! - ownedD: OwnedD! - ownedE: OwnedE! - ownedF: OwnedF! - ownedG: OwnedG! - ownedH: OwnedH! - ownedI: OwnedI! - ownedJ: OwnedJ! - ownedK: OwnedK! - ownedL: OwnedL! - ownedM: OwnedM! - ownedN: OwnedN! - ownedO: OwnedO! - ownedP: OwnedP! - extendedA: ExtendedA! - extendedB: ExtendedB! - extendedC: ExtendedC! - extendedD: ExtendedD! - extendedE: ExtendedE! - extendedF: ExtendedF! - extendedG: ExtendedG! - extendedH: ExtendedH! - } - - type OwnedA { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedB! - } - - type OwnedB { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedC! - } - - type OwnedC { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedD! - } - - type OwnedD { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedE! - } - - type OwnedE { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedF! - } - - type OwnedF { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedG! - } - - type OwnedG { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedH! - } - - type OwnedH { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedI! - } - - type OwnedI { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedJ! - } - - type OwnedJ { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedK! - } - - type OwnedK { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedL! - } - - type OwnedL { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedM! - } - - type OwnedM { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedN! - } - - type OwnedN { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedO! - } - - type OwnedO { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedP! - } - - type OwnedP { - id: ID! - fieldOne: String! - fieldTwo: String! - nextOwnedType: OwnedA! - } - - extend type ExtendedA { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedB! - } - - extend type ExtendedB { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedC! - } - - extend type ExtendedC { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedD! - } - - extend type ExtendedD { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedE! - } - - extend type ExtendedE { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedF! - } - - extend type ExtendedF { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedG! - } - - extend type ExtendedG { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedH! - } - - extend type ExtendedH { - id: ID! @external - fieldOne: String! - fieldTwo: String! - nextExtendedType: ExtendedA! - } -` diff --git a/pkg/engine/plan/plan.go b/pkg/engine/plan/plan.go deleted file mode 100644 index 4725d5af1..000000000 --- a/pkg/engine/plan/plan.go +++ /dev/null @@ -1,1867 +0,0 @@ -package plan - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "reflect" - "regexp" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astimport" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type Planner struct { - config Configuration - configurationWalker *astvisitor.Walker - configurationVisitor *configurationVisitor - planningWalker *astvisitor.Walker - planningVisitor *Visitor - requiredFieldsWalker *astvisitor.Walker - requiredFieldsVisitor *requiredFieldsVisitor -} - -type Configuration struct { - DefaultFlushIntervalMillis int64 - DataSources []DataSourceConfiguration - Fields FieldConfigurations - Types TypeConfigurations - // DisableResolveFieldPositions should be set to true for testing purposes - // This setting removes position information from all fields - // In production, this should be set to false so that error messages are easier to understand - DisableResolveFieldPositions bool - CustomResolveMap map[string]resolve.CustomResolve -} - -type DirectiveConfigurations []DirectiveConfiguration - -func (d *DirectiveConfigurations) RenameTypeNameOnMatchStr(directiveName string) string { - for i := range *d { - if (*d)[i].DirectiveName == directiveName { - return (*d)[i].RenameTo - } - } - return directiveName -} - -func (d *DirectiveConfigurations) RenameTypeNameOnMatchBytes(directiveName []byte) []byte { - str := string(directiveName) - for i := range *d { - if (*d)[i].DirectiveName == str { - return []byte((*d)[i].RenameTo) - } - } - return directiveName -} - -type DirectiveConfiguration struct { - DirectiveName string - RenameTo string -} - -type TypeConfigurations []TypeConfiguration - -func (t *TypeConfigurations) RenameTypeNameOnMatchStr(typeName string) string { - for i := range *t { - if (*t)[i].TypeName == typeName { - return (*t)[i].RenameTo - } - } - return typeName -} - -func (t *TypeConfigurations) RenameTypeNameOnMatchBytes(typeName []byte) []byte { - str := string(typeName) - for i := range *t { - if (*t)[i].TypeName == str { - return []byte((*t)[i].RenameTo) - } - } - return typeName -} - -type TypeConfiguration struct { - TypeName string - // RenameTo modifies the TypeName - // so that a downstream Operation can contain a different TypeName than the upstream Schema - // e.g. if the downstream Operation contains { ... on Human_api { height } } - // the upstream Operation can be rewritten to { ... on Human { height }} - // by setting RenameTo to Human - // This way, Types can be suffixed / renamed in downstream Schemas while keeping the contract with the upstream ok - RenameTo string -} - -type FieldConfigurations []FieldConfiguration - -func (f FieldConfigurations) ForTypeField(typeName, fieldName string) *FieldConfiguration { - for i := range f { - if f[i].TypeName == typeName && f[i].FieldName == fieldName { - return &f[i] - } - } - return nil -} - -type FieldConfiguration struct { - TypeName string - FieldName string - // DisableDefaultMapping - instructs planner whether to use path mapping coming from Path field - DisableDefaultMapping bool - // Path - represents a json path to lookup for a field value in response json - Path []string - Arguments ArgumentsConfigurations - RequiresFields []string - // UnescapeResponseJson set to true will allow fields (String,List,Object) - // to be resolved from an escaped JSON string - // e.g. {"response":"{\"foo\":\"bar\"}"} will be returned as {"foo":"bar"} when path is "response" - // This way, it is possible to resolve a JSON string as part of the response without extra String encoding of the JSON - UnescapeResponseJson bool -} - -type ArgumentsConfigurations []ArgumentConfiguration - -func (a ArgumentsConfigurations) ForName(argName string) *ArgumentConfiguration { - for i := range a { - if a[i].Name == argName { - return &a[i] - } - } - return nil -} - -type SourceType string -type ArgumentRenderConfig string - -const ( - ObjectFieldSource SourceType = "object_field" - FieldArgumentSource SourceType = "field_argument" - RenderArgumentDefault ArgumentRenderConfig = "" - RenderArgumentAsArrayCSV ArgumentRenderConfig = "render_argument_as_array_csv" - RenderArgumentAsGraphQLValue ArgumentRenderConfig = "render_argument_as_graphql_value" - RenderArgumentAsJSONValue ArgumentRenderConfig = "render_argument_as_json_value" -) - -type ArgumentConfiguration struct { - Name string - SourceType SourceType - SourcePath []string - RenderConfig ArgumentRenderConfig - RenameTypeTo string -} - -type DataSourceConfiguration struct { - // RootNodes - defines the nodes where the responsibility of the DataSource begins - // When you enter a node, and it is not a child node - // when you have entered into a field which representing data source - it means that we starting a new planning stage - RootNodes []TypeField - // ChildNodes - describes additional fields which will be requested along with fields which has a datasources - // They are always required for the Graphql datasources cause each field could have it's own datasource - // For any single point datasource like HTTP/REST or GRPC we could not request less fields, as we always get a full response - ChildNodes []TypeField - Directives DirectiveConfigurations - Factory PlannerFactory - Custom json.RawMessage -} - -func (d *DataSourceConfiguration) HasRootNode(typeName, fieldName string) bool { - for i := range d.RootNodes { - if typeName != d.RootNodes[i].TypeName { - continue - } - for j := range d.RootNodes[i].FieldNames { - if fieldName == d.RootNodes[i].FieldNames[j] { - return true - } - } - } - return false -} - -type PlannerFactory interface { - // Planner should return the DataSourcePlanner - // closer is the closing channel for all stateful DataSources - // At runtime, the Execution Engine will be instantiated with one global resolve.Closer. - // Once the Closer gets closed, all stateful DataSources must close their connections and cleanup themselves. - // They can do so by starting a goroutine on instantiation time that blocking reads on the resolve.Closer. - // Once the Closer emits the close event, they have to terminate (e.g. close database connections). - Planner(ctx context.Context) DataSourcePlanner -} - -type TypeField struct { - TypeName string - FieldNames []string -} - -type FieldMapping struct { - TypeName string - FieldName string - DisableDefaultMapping bool - Path []string -} - -// NewPlanner creates a new Planner from the Configuration and a ctx object -// The context.Context object is used to determine the lifecycle of stateful DataSources -// It's important to note that stateful DataSources must be closed when they are no longer being used -// Stateful DataSources could be those that initiate a WebSocket connection to an origin, a database client, a streaming client, etc... -// All DataSources are initiated with the same context.Context object provided to the Planner. -// To ensure that there are no memory leaks, it's therefore important to add a cancel func or timeout to the context.Context -// At the time when the resolver and all operations should be garbage collected, ensure to first cancel or timeout the ctx object -// If you don't cancel the context.Context, the goroutines will run indefinitely and there's no reference left to stop them -func NewPlanner(ctx context.Context, config Configuration) *Planner { - - // required fields pre-processing - - requiredFieldsWalker := astvisitor.NewWalker(48) - requiredFieldsV := &requiredFieldsVisitor{ - walker: &requiredFieldsWalker, - } - - requiredFieldsWalker.RegisterEnterDocumentVisitor(requiredFieldsV) - requiredFieldsWalker.RegisterEnterOperationVisitor(requiredFieldsV) - requiredFieldsWalker.RegisterEnterFieldVisitor(requiredFieldsV) - requiredFieldsWalker.RegisterLeaveDocumentVisitor(requiredFieldsV) - - // configuration - - configurationWalker := astvisitor.NewWalker(48) - configVisitor := &configurationVisitor{ - walker: &configurationWalker, - ctx: ctx, - } - - configurationWalker.RegisterEnterDocumentVisitor(configVisitor) - configurationWalker.RegisterFieldVisitor(configVisitor) - configurationWalker.RegisterEnterOperationVisitor(configVisitor) - configurationWalker.RegisterSelectionSetVisitor(configVisitor) - - // planning - - planningWalker := astvisitor.NewWalker(48) - planningVisitor := &Visitor{ - Walker: &planningWalker, - fieldConfigs: map[int]*FieldConfiguration{}, - disableResolveFieldPositions: config.DisableResolveFieldPositions, - } - - p := &Planner{ - config: config, - configurationWalker: &configurationWalker, - configurationVisitor: configVisitor, - planningWalker: &planningWalker, - planningVisitor: planningVisitor, - requiredFieldsWalker: &requiredFieldsWalker, - requiredFieldsVisitor: requiredFieldsV, - } - - return p -} - -func (p *Planner) SetConfig(config Configuration) { - p.config = config -} - -func (p *Planner) Plan(operation, definition *ast.Document, operationName string, report *operationreport.Report) (plan Plan) { - - // make a copy of the config as the pre-processor modifies it - - config := p.config - - // clean objects and current fields from previous invocation - p.planningVisitor.objects = p.planningVisitor.objects[:0] - p.planningVisitor.currentFields = p.planningVisitor.currentFields[:0] - - // select operation - - p.selectOperation(operation, operationName, report) - if report.HasErrors() { - return - } - - // pre-process required fields - - p.preProcessRequiredFields(&config, operation, definition, report) - - // find planning paths - - p.configurationVisitor.config = config - p.configurationWalker.Walk(operation, definition, report) - - // configure planning visitor - - p.planningVisitor.planners = p.configurationVisitor.planners - p.planningVisitor.Config = config - p.planningVisitor.fetchConfigurations = p.configurationVisitor.fetches - p.planningVisitor.fieldBuffers = p.configurationVisitor.fieldBuffers - p.planningVisitor.skipFieldPaths = p.requiredFieldsVisitor.skipFieldPaths - - p.planningWalker.ResetVisitors() - p.planningWalker.SetVisitorFilter(p.planningVisitor) - p.planningWalker.RegisterDocumentVisitor(p.planningVisitor) - p.planningWalker.RegisterEnterOperationVisitor(p.planningVisitor) - p.planningWalker.RegisterFieldVisitor(p.planningVisitor) - p.planningWalker.RegisterSelectionSetVisitor(p.planningVisitor) - p.planningWalker.RegisterEnterDirectiveVisitor(p.planningVisitor) - p.planningWalker.RegisterInlineFragmentVisitor(p.planningVisitor) - - for key := range p.planningVisitor.planners { - config := p.planningVisitor.planners[key].dataSourceConfiguration - isNested := p.planningVisitor.planners[key].isNestedPlanner() - err := p.planningVisitor.planners[key].planner.Register(p.planningVisitor, config, isNested) - if err != nil { - report.AddInternalError(err) - return - } - } - - // process the plan - - p.planningWalker.Walk(operation, definition, report) - - return p.planningVisitor.plan -} - -func (p *Planner) selectOperation(operation *ast.Document, operationName string, report *operationreport.Report) { - - numOfOperations := operation.NumOfOperationDefinitions() - operationName = strings.TrimSpace(operationName) - if len(operationName) == 0 && numOfOperations > 1 { - report.AddExternalError(operationreport.ErrRequiredOperationNameIsMissing()) - return - } - - if len(operationName) == 0 && numOfOperations == 1 { - operationName = operation.OperationDefinitionNameString(0) - } - - if !operation.OperationNameExists(operationName) { - report.AddExternalError(operationreport.ErrOperationWithProvidedOperationNameNotFound(operationName)) - return - } - - p.requiredFieldsVisitor.operationName = operationName - p.configurationVisitor.operationName = operationName - p.planningVisitor.OperationName = operationName -} - -func (p *Planner) preProcessRequiredFields(config *Configuration, operation, definition *ast.Document, report *operationreport.Report) { - if !p.hasRequiredFields(config) { - return - } - - p.requiredFieldsVisitor.config = config - p.requiredFieldsVisitor.operation = operation - p.requiredFieldsVisitor.definition = definition - p.requiredFieldsWalker.Walk(operation, definition, report) -} - -func (p *Planner) hasRequiredFields(config *Configuration) bool { - for i := range config.Fields { - if len(config.Fields[i].RequiresFields) != 0 { - return true - } - } - return false -} - -type Visitor struct { - Operation, Definition *ast.Document - Walker *astvisitor.Walker - Importer astimport.Importer - Config Configuration - plan Plan - OperationName string - operationDefinition int - objects []*resolve.Object - currentFields []objectFields - currentField *resolve.Field - planners []plannerConfiguration - fetchConfigurations []objectFetchConfiguration - fieldBuffers map[int]int - skipFieldPaths []string - fieldConfigs map[int]*FieldConfiguration - exportedVariables map[string]struct{} - skipIncludeFields map[int]skipIncludeField - disableResolveFieldPositions bool -} - -type skipIncludeField struct { - skip bool - skipVariableName string - include bool - includeVariableName string -} - -type objectFields struct { - popOnField int - fields *[]*resolve.Field -} - -type objectFetchConfiguration struct { - object *resolve.Object - trigger *resolve.GraphQLSubscriptionTrigger - planner DataSourcePlanner - bufferID int - isSubscription bool - fieldRef int - fieldDefinitionRef int -} - -func (v *Visitor) AllowVisitor(kind astvisitor.VisitorKind, ref int, visitor interface{}) bool { - if visitor == v { - return true - } - path := v.Walker.Path.DotDelimitedString() - switch kind { - case astvisitor.EnterField, astvisitor.LeaveField: - fieldAliasOrName := v.Operation.FieldAliasOrNameString(ref) - path = path + "." + fieldAliasOrName - } - if !strings.Contains(path, ".") { - return true - } - for _, config := range v.planners { - if config.planner == visitor && config.hasPath(path) { - switch kind { - case astvisitor.EnterField, astvisitor.LeaveField: - return config.shouldWalkFieldsOnPath(path) - case astvisitor.EnterSelectionSet, astvisitor.LeaveSelectionSet: - return !config.isExitPath(path) - default: - return true - } - } - } - return false -} - -func (v *Visitor) currentFullPath() string { - path := v.Walker.Path.DotDelimitedString() - if v.Walker.CurrentKind == ast.NodeKindField { - fieldAliasOrName := v.Operation.FieldAliasOrNameString(v.Walker.CurrentRef) - path = path + "." + fieldAliasOrName - } - return path -} - -func (v *Visitor) EnterDirective(ref int) { - directiveName := v.Operation.DirectiveNameString(ref) - ancestor := v.Walker.Ancestors[len(v.Walker.Ancestors)-1] - switch ancestor.Kind { - case ast.NodeKindOperationDefinition: - switch directiveName { - case "flushInterval": - if value, ok := v.Operation.DirectiveArgumentValueByName(ref, literal.MILLISECONDS); ok { - if value.Kind == ast.ValueKindInteger { - v.plan.SetFlushInterval(v.Operation.IntValueAsInt(value.Ref)) - } - } - } - case ast.NodeKindField: - switch directiveName { - case "stream": - initialBatchSize := 0 - if value, ok := v.Operation.DirectiveArgumentValueByName(ref, literal.INITIAL_BATCH_SIZE); ok { - if value.Kind == ast.ValueKindInteger { - initialBatchSize = int(v.Operation.IntValueAsInt32(value.Ref)) - } - } - v.currentField.Stream = &resolve.StreamField{ - InitialBatchSize: initialBatchSize, - } - case "defer": - v.currentField.Defer = &resolve.DeferField{} - } - } -} - -func (v *Visitor) EnterInlineFragment(ref int) { - directives := v.Operation.InlineFragments[ref].Directives.Refs - skip, skipVariableName := v.resolveSkip(directives) - include, includeVariableName := v.resolveInclude(directives) - set := v.Operation.InlineFragments[ref].SelectionSet - if set == -1 { - return - } - for _, selection := range v.Operation.SelectionSets[set].SelectionRefs { - switch v.Operation.Selections[selection].Kind { - case ast.SelectionKindField: - ref := v.Operation.Selections[selection].Ref - if skip || include { - v.skipIncludeFields[ref] = skipIncludeField{ - skip: skip, - skipVariableName: skipVariableName, - include: include, - includeVariableName: includeVariableName, - } - } - } - } -} - -func (v *Visitor) LeaveInlineFragment(_ int) { - -} - -func (v *Visitor) EnterSelectionSet(_ int) { - -} - -func (v *Visitor) LeaveSelectionSet(_ int) { - -} - -func (v *Visitor) EnterField(ref int) { - if v.skipField(ref) { - return - } - - skip, skipVariableName := v.resolveSkipForField(ref) - include, includeVariableName := v.resolveIncludeForField(ref) - - fieldName := v.Operation.FieldNameBytes(ref) - fieldAliasOrName := v.Operation.FieldAliasOrNameBytes(ref) - if bytes.Equal(fieldName, literal.TYPENAME) { - v.currentField = &resolve.Field{ - Name: fieldAliasOrName, - Value: &resolve.String{ - Nullable: false, - Path: []string{"__typename"}, - IsTypeName: true, - }, - OnTypeNames: v.resolveOnTypeNames(), - Position: v.resolveFieldPosition(ref), - SkipDirectiveDefined: skip, - SkipVariableName: skipVariableName, - IncludeDirectiveDefined: include, - IncludeVariableName: includeVariableName, - } - *v.currentFields[len(v.currentFields)-1].fields = append(*v.currentFields[len(v.currentFields)-1].fields, v.currentField) - return - } - - fieldDefinition, ok := v.Walker.FieldDefinition(ref) - if !ok { - return - } - - var ( - hasFetchConfig bool - i int - ) - for i = range v.fetchConfigurations { - if ref == v.fetchConfigurations[i].fieldRef { - hasFetchConfig = true - break - } - } - if hasFetchConfig { - if v.fetchConfigurations[i].isSubscription { - plan, ok := v.plan.(*SubscriptionResponsePlan) - if ok { - v.fetchConfigurations[i].trigger = &plan.Response.Trigger - } - } else { - v.fetchConfigurations[i].object = v.objects[len(v.objects)-1] - } - } - - path := v.resolveFieldPath(ref) - fieldDefinitionType := v.Definition.FieldDefinitionType(fieldDefinition) - bufferID, hasBuffer := v.fieldBuffers[ref] - - v.currentField = &resolve.Field{ - Name: fieldAliasOrName, - Value: v.resolveFieldValue(ref, fieldDefinitionType, true, path), - HasBuffer: hasBuffer, - BufferID: bufferID, - OnTypeNames: v.resolveOnTypeNames(), - Position: v.resolveFieldPosition(ref), - SkipDirectiveDefined: skip, - SkipVariableName: skipVariableName, - IncludeDirectiveDefined: include, - IncludeVariableName: includeVariableName, - } - - *v.currentFields[len(v.currentFields)-1].fields = append(*v.currentFields[len(v.currentFields)-1].fields, v.currentField) - - typeName := v.Walker.EnclosingTypeDefinition.NameString(v.Definition) - fieldNameStr := v.Operation.FieldNameString(ref) - fieldConfig := v.Config.Fields.ForTypeField(typeName, fieldNameStr) - if fieldConfig == nil { - return - } - v.fieldConfigs[ref] = fieldConfig -} - -func (v *Visitor) resolveFieldPosition(ref int) resolve.Position { - if v.disableResolveFieldPositions { - return resolve.Position{} - } - return resolve.Position{ - Line: v.Operation.Fields[ref].Position.LineStart, - Column: v.Operation.Fields[ref].Position.CharStart, - } -} - -func (v *Visitor) resolveSkipForField(ref int) (bool, string) { - skipInclude, ok := v.skipIncludeFields[ref] - if ok { - return skipInclude.skip, skipInclude.skipVariableName - } - return v.resolveSkip(v.Operation.Fields[ref].Directives.Refs) -} - -func (v *Visitor) resolveIncludeForField(ref int) (bool, string) { - skipInclude, ok := v.skipIncludeFields[ref] - if ok { - return skipInclude.include, skipInclude.includeVariableName - } - return v.resolveInclude(v.Operation.Fields[ref].Directives.Refs) -} - -func (v *Visitor) resolveSkip(directiveRefs []int) (bool, string) { - for _, i := range directiveRefs { - if v.Operation.DirectiveNameString(i) != "skip" { - continue - } - if value, ok := v.Operation.DirectiveArgumentValueByName(i, literal.IF); ok { - if value.Kind == ast.ValueKindVariable { - return true, v.Operation.VariableValueNameString(value.Ref) - } - } - } - return false, "" -} - -func (v *Visitor) resolveInclude(directiveRefs []int) (bool, string) { - for _, i := range directiveRefs { - if v.Operation.DirectiveNameString(i) != "include" { - continue - } - if value, ok := v.Operation.DirectiveArgumentValueByName(i, literal.IF); ok { - if value.Kind == ast.ValueKindVariable { - return true, v.Operation.VariableValueNameString(value.Ref) - } - } - } - return false, "" -} - -func (v *Visitor) resolveOnTypeNames() [][]byte { - if len(v.Walker.Ancestors) < 2 { - return nil - } - inlineFragment := v.Walker.Ancestors[len(v.Walker.Ancestors)-2] - if inlineFragment.Kind != ast.NodeKindInlineFragment { - return nil - } - typeName := v.Operation.InlineFragmentTypeConditionName(inlineFragment.Ref) - if typeName == nil { - typeName = v.Walker.EnclosingTypeDefinition.NameBytes(v.Definition) - } - node, exists := v.Definition.NodeByName(typeName) - // If not an interface, return the concrete type - if !exists || !node.Kind.IsAbstractType() { - return [][]byte{v.Config.Types.RenameTypeNameOnMatchBytes(typeName)} - } - if node.Kind == ast.NodeKindUnionTypeDefinition { - // This should never be true. If it is, it's an error - panic("resolveOnTypeNames called with a union type") - } - // We're dealing with an interface, so add all objects that implement this interface to the slice - onTypeNames := make([][]byte, 0, 2) - for objectTypeDefinitionRef := range v.Definition.ObjectTypeDefinitions { - if v.Definition.ObjectTypeDefinitionImplementsInterface(objectTypeDefinitionRef, typeName) { - onTypeNames = append(onTypeNames, v.Definition.ObjectTypeDefinitionNameBytes(objectTypeDefinitionRef)) - } - } - if len(onTypeNames) < 1 { - return nil - } - return onTypeNames -} - -func (v *Visitor) LeaveField(ref int) { - if v.currentFields[len(v.currentFields)-1].popOnField == ref { - v.currentFields = v.currentFields[:len(v.currentFields)-1] - } - fieldDefinition, ok := v.Walker.FieldDefinition(ref) - if !ok { - return - } - fieldDefinitionTypeNode := v.Definition.FieldDefinitionTypeNode(fieldDefinition) - switch fieldDefinitionTypeNode.Kind { - case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition, ast.NodeKindUnionTypeDefinition: - v.objects = v.objects[:len(v.objects)-1] - } -} - -func (v *Visitor) skipField(ref int) bool { - fullPath := v.Walker.Path.DotDelimitedString() + "." + v.Operation.FieldAliasOrNameString(ref) - for i := range v.skipFieldPaths { - if v.skipFieldPaths[i] == fullPath { - return true - } - } - return false -} - -func (v *Visitor) resolveFieldValue(fieldRef, typeRef int, nullable bool, path []string) resolve.Node { - ofType := v.Definition.Types[typeRef].OfType - - fieldName := v.Operation.FieldNameString(fieldRef) - enclosingTypeName := v.Walker.EnclosingTypeDefinition.NameString(v.Definition) - fieldConfig := v.Config.Fields.ForTypeField(enclosingTypeName, fieldName) - unescapeResponseJson := false - if fieldConfig != nil { - unescapeResponseJson = fieldConfig.UnescapeResponseJson - } - - switch v.Definition.Types[typeRef].TypeKind { - case ast.TypeKindNonNull: - return v.resolveFieldValue(fieldRef, ofType, false, path) - case ast.TypeKindList: - listItem := v.resolveFieldValue(fieldRef, ofType, true, nil) - return &resolve.Array{ - Nullable: nullable, - Path: path, - Item: listItem, - } - case ast.TypeKindNamed: - typeName := v.Definition.ResolveTypeNameString(typeRef) - customResolve, ok := v.Config.CustomResolveMap[typeName] - if ok { - return &resolve.CustomNode{ - CustomResolve: customResolve, - Path: path, - Nullable: nullable, - } - } - typeDefinitionNode, ok := v.Definition.Index.FirstNodeByNameStr(typeName) - if !ok { - return &resolve.Null{} - } - switch typeDefinitionNode.Kind { - case ast.NodeKindScalarTypeDefinition: - fieldExport := v.resolveFieldExport(fieldRef) - switch typeName { - case "String": - return &resolve.String{ - Path: path, - Nullable: nullable, - Export: fieldExport, - UnescapeResponseJson: unescapeResponseJson, - } - case "Boolean": - return &resolve.Boolean{ - Path: path, - Nullable: nullable, - Export: fieldExport, - } - case "Int": - return &resolve.Integer{ - Path: path, - Nullable: nullable, - Export: fieldExport, - } - case "Float": - return &resolve.Float{ - Path: path, - Nullable: nullable, - Export: fieldExport, - } - case "BigInt": - return &resolve.BigInt{ - Path: path, - Nullable: nullable, - Export: fieldExport, - } - default: - return &resolve.String{ - Path: path, - Nullable: nullable, - Export: fieldExport, - UnescapeResponseJson: unescapeResponseJson, - } - } - case ast.NodeKindEnumTypeDefinition: - return &resolve.String{ - Path: path, - Nullable: nullable, - UnescapeResponseJson: unescapeResponseJson, - } - case ast.NodeKindObjectTypeDefinition, ast.NodeKindInterfaceTypeDefinition, ast.NodeKindUnionTypeDefinition: - object := &resolve.Object{ - Nullable: nullable, - Path: path, - Fields: []*resolve.Field{}, - UnescapeResponseJson: unescapeResponseJson, - } - v.objects = append(v.objects, object) - v.Walker.Defer(func() { - v.currentFields = append(v.currentFields, objectFields{ - popOnField: fieldRef, - fields: &object.Fields, - }) - }) - return object - default: - return &resolve.Null{} - } - default: - return &resolve.Null{} - } -} - -func (v *Visitor) resolveFieldExport(fieldRef int) *resolve.FieldExport { - if !v.Operation.Fields[fieldRef].HasDirectives { - return nil - } - exportAs := "" - for _, ref := range v.Operation.Fields[fieldRef].Directives.Refs { - if v.Operation.Input.ByteSliceString(v.Operation.Directives[ref].Name) == "export" { - value, ok := v.Operation.DirectiveArgumentValueByName(ref, []byte("as")) - if !ok { - continue - } - if value.Kind != ast.ValueKindString { - continue - } - exportAs = v.Operation.StringValueContentString(value.Ref) - } - } - if exportAs == "" { - return nil - } - variableDefinition, ok := v.Operation.VariableDefinitionByNameAndOperation(v.Walker.Ancestors[0].Ref, []byte(exportAs)) - if !ok { - return nil - } - v.exportedVariables[exportAs] = struct{}{} - - typeName := v.Operation.ResolveTypeNameString(v.Operation.VariableDefinitions[variableDefinition].Type) - switch typeName { - case "Int", "Float", "Boolean": - return &resolve.FieldExport{ - Path: []string{exportAs}, - } - default: - return &resolve.FieldExport{ - Path: []string{exportAs}, - AsString: true, - } - } -} - -func (v *Visitor) fieldRequiresExportedVariable(fieldRef int) bool { - for _, arg := range v.Operation.Fields[fieldRef].Arguments.Refs { - if v.valueRequiresExportedVariable(v.Operation.Arguments[arg].Value) { - return true - } - } - return false -} - -func (v *Visitor) valueRequiresExportedVariable(value ast.Value) bool { - switch value.Kind { - case ast.ValueKindVariable: - name := v.Operation.VariableValueNameString(value.Ref) - if _, ok := v.exportedVariables[name]; ok { - return true - } - return false - case ast.ValueKindList: - for _, ref := range v.Operation.ListValues[value.Ref].Refs { - if v.valueRequiresExportedVariable(v.Operation.Values[ref]) { - return true - } - } - return false - case ast.ValueKindObject: - for _, ref := range v.Operation.ObjectValues[value.Ref].Refs { - if v.valueRequiresExportedVariable(v.Operation.ObjectFieldValue(ref)) { - return true - } - } - return false - default: - return false - } -} - -func (v *Visitor) EnterOperationDefinition(ref int) { - operationName := v.Operation.OperationDefinitionNameString(ref) - if v.OperationName != operationName { - v.Walker.SkipNode() - return - } - - v.operationDefinition = ref - - rootObject := &resolve.Object{ - Fields: []*resolve.Field{}, - } - - v.objects = append(v.objects, rootObject) - v.currentFields = append(v.currentFields, objectFields{ - fields: &rootObject.Fields, - popOnField: -1, - }) - - isSubscription, _, err := AnalyzePlanKind(v.Operation, v.Definition, v.OperationName) - if err != nil { - v.Walker.StopWithInternalErr(err) - return - } - - graphQLResponse := &resolve.GraphQLResponse{ - Data: rootObject, - } - - if isSubscription { - v.plan = &SubscriptionResponsePlan{ - FlushInterval: v.Config.DefaultFlushIntervalMillis, - Response: &resolve.GraphQLSubscription{ - Response: graphQLResponse, - }, - } - return - } - - /*if isStreaming { - - }*/ - - v.plan = &SynchronousResponsePlan{ - Response: graphQLResponse, - } -} - -func (v *Visitor) resolveFieldPath(ref int) []string { - typeName := v.Walker.EnclosingTypeDefinition.NameString(v.Definition) - fieldName := v.Operation.FieldNameUnsafeString(ref) - config := v.currentOrParentPlannerConfiguration() - aliasOverride := false - if config.planner != nil { - aliasOverride = config.planner.DataSourcePlanningBehavior().OverrideFieldPathFromAlias - } - - for i := range v.Config.Fields { - if v.Config.Fields[i].TypeName == typeName && v.Config.Fields[i].FieldName == fieldName { - if aliasOverride { - override, exists := config.planner.DownstreamResponseFieldAlias(ref) - if exists { - return []string{override} - } - } - if aliasOverride && v.Operation.FieldAliasIsDefined(ref) { - return []string{v.Operation.FieldAliasString(ref)} - } - if v.Config.Fields[i].DisableDefaultMapping { - return nil - } - if len(v.Config.Fields[i].Path) != 0 { - return v.Config.Fields[i].Path - } - return []string{fieldName} - } - } - - if aliasOverride { - return []string{v.Operation.FieldAliasOrNameString(ref)} - } - - return []string{fieldName} -} - -func (v *Visitor) EnterDocument(operation, definition *ast.Document) { - v.Operation, v.Definition = operation, definition - v.fieldConfigs = map[int]*FieldConfiguration{} - v.exportedVariables = map[string]struct{}{} - v.skipIncludeFields = map[int]skipIncludeField{} -} - -func (v *Visitor) LeaveDocument(_, _ *ast.Document) { - for _, config := range v.fetchConfigurations { - if config.isSubscription { - v.configureSubscription(config) - } else { - v.configureObjectFetch(config) - } - } -} - -var ( - templateRegex = regexp.MustCompile(`{{.*?}}`) - selectorRegex = regexp.MustCompile(`{{\s*\.(.*?)\s*}}`) -) - -func (v *Visitor) currentOrParentPlannerConfiguration() plannerConfiguration { - const none = -1 - currentPath := v.currentFullPath() - plannerIndex := none - plannerPathDeepness := none - - for i := range v.planners { - for _, plannerPath := range v.planners[i].paths { - if v.isCurrentOrParentPath(currentPath, plannerPath.path) { - currentPlannerPathDeepness := v.pathDeepness(plannerPath.path) - if currentPlannerPathDeepness > plannerPathDeepness { - plannerPathDeepness = currentPlannerPathDeepness - plannerIndex = i - break - } - } - } - } - - if plannerIndex != none { - return v.planners[plannerIndex] - } - - return plannerConfiguration{} -} - -func (v *Visitor) isCurrentOrParentPath(currentPath string, parentPath string) bool { - return strings.HasPrefix(currentPath, parentPath) -} - -func (v *Visitor) pathDeepness(path string) int { - return strings.Count(path, ".") -} - -func (v *Visitor) resolveInputTemplates(config objectFetchConfiguration, input *string, variables *resolve.Variables) { - *input = templateRegex.ReplaceAllStringFunc(*input, func(s string) string { - selectors := selectorRegex.FindStringSubmatch(s) - if len(selectors) != 2 { - return s - } - selector := strings.TrimPrefix(selectors[1], ".") - parts := strings.Split(selector, ".") - if len(parts) < 2 { - return s - } - path := parts[1:] - var ( - variableName string - ) - switch parts[0] { - case "object": - variable := &resolve.ObjectVariable{ - Path: path, - Renderer: resolve.NewPlainVariableRenderer(), - } - variableName, _ = variables.AddVariable(variable) - case "arguments": - argumentName := path[0] - arg, ok := v.Operation.FieldArgument(config.fieldRef, []byte(argumentName)) - if !ok { - break - } - value := v.Operation.ArgumentValue(arg) - if value.Kind != ast.ValueKindVariable { - inputValueDefinition := -1 - for _, ref := range v.Definition.FieldDefinitions[config.fieldDefinitionRef].ArgumentsDefinition.Refs { - inputFieldName := v.Definition.Input.ByteSliceString(v.Definition.InputValueDefinitions[ref].Name) - if inputFieldName == argumentName { - inputValueDefinition = ref - break - } - } - if inputValueDefinition == -1 { - return "null" - } - return v.renderJSONValueTemplate(value, variables, inputValueDefinition) - } - variableValue := v.Operation.VariableValueNameString(value.Ref) - if !v.Operation.OperationDefinitionHasVariableDefinition(v.operationDefinition, variableValue) { - break // omit optional argument when variable is not defined - } - variableDefinition, exists := v.Operation.VariableDefinitionByNameAndOperation(v.operationDefinition, v.Operation.VariableValueNameBytes(value.Ref)) - if !exists { - break - } - variableTypeRef := v.Operation.VariableDefinitions[variableDefinition].Type - typeName := v.Operation.ResolveTypeNameBytes(v.Operation.VariableDefinitions[variableDefinition].Type) - node, exists := v.Definition.Index.FirstNodeByNameBytes(typeName) - if !exists { - break - } - - var variablePath []string - if len(parts) > 2 && node.Kind == ast.NodeKindInputObjectTypeDefinition { - variablePath = append(variablePath, path...) - } else { - variablePath = append(variablePath, variableValue) - } - - variable := &resolve.ContextVariable{ - Path: variablePath, - } - - if fieldConfig, ok := v.fieldConfigs[config.fieldRef]; ok { - if argumentConfig := fieldConfig.Arguments.ForName(argumentName); argumentConfig != nil { - switch argumentConfig.RenderConfig { - case RenderArgumentAsArrayCSV: - variable.Renderer = resolve.NewCSVVariableRendererFromTypeRef(v.Operation, v.Definition, variableTypeRef) - case RenderArgumentDefault: - renderer, err := resolve.NewPlainVariableRendererWithValidationFromTypeRef(v.Operation, v.Definition, variableTypeRef, variablePath...) - if err != nil { - break - } - variable.Renderer = renderer - case RenderArgumentAsGraphQLValue: - renderer, err := resolve.NewGraphQLVariableRendererFromTypeRef(v.Operation, v.Definition, variableTypeRef) - if err != nil { - break - } - variable.Renderer = renderer - case RenderArgumentAsJSONValue: - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(v.Operation, v.Definition, variableTypeRef) - if err != nil { - break - } - variable.Renderer = renderer - } - } - } - - if variable.Renderer == nil { - renderer, err := resolve.NewPlainVariableRendererWithValidationFromTypeRef(v.Operation, v.Definition, variableTypeRef, variablePath...) - if err != nil { - break - } - variable.Renderer = renderer - } - - variableName, _ = variables.AddVariable(variable) - case "request": - if len(path) != 2 { - break - } - switch path[0] { - case "headers": - key := path[1] - variableName, _ = variables.AddVariable(&resolve.HeaderVariable{ - Path: []string{key}, - }) - } - } - return variableName - }) -} - -func (v *Visitor) renderJSONValueTemplate(value ast.Value, variables *resolve.Variables, inputValueDefinition int) (out string) { - switch value.Kind { - case ast.ValueKindList: - out += "[" - addComma := false - for _, ref := range v.Operation.ListValues[value.Ref].Refs { - if addComma { - out += "," - } else { - addComma = true - } - listValue := v.Operation.Values[ref] - out += v.renderJSONValueTemplate(listValue, variables, inputValueDefinition) - } - out += "]" - case ast.ValueKindObject: - out += "{" - addComma := false - for _, ref := range v.Operation.ObjectValues[value.Ref].Refs { - fieldName := v.Operation.Input.ByteSlice(v.Operation.ObjectFields[ref].Name) - fieldValue := v.Operation.ObjectFields[ref].Value - typeName := v.Definition.ResolveTypeNameString(v.Definition.InputValueDefinitions[inputValueDefinition].Type) - typeDefinitionNode, ok := v.Definition.Index.FirstNodeByNameStr(typeName) - if !ok { - continue - } - objectFieldDefinition, ok := v.Definition.NodeInputFieldDefinitionByName(typeDefinitionNode, fieldName) - if !ok { - continue - } - if addComma { - out += "," - } else { - addComma = true - } - out += fmt.Sprintf("\"%s\":", string(fieldName)) - out += v.renderJSONValueTemplate(fieldValue, variables, objectFieldDefinition) - } - out += "}" - case ast.ValueKindVariable: - variablePath := v.Operation.VariableValueNameString(value.Ref) - inputType := v.Definition.InputValueDefinitions[inputValueDefinition].Type - renderer, err := resolve.NewJSONVariableRendererWithValidationFromTypeRef(v.Definition, v.Definition, inputType) - if err != nil { - renderer = resolve.NewJSONVariableRenderer() - } - variableName, _ := variables.AddVariable(&resolve.ContextVariable{ - Path: []string{variablePath}, - Renderer: renderer, - }) - out += variableName - } - return -} - -func (v *Visitor) configureSubscription(config objectFetchConfiguration) { - subscription := config.planner.ConfigureSubscription() - config.trigger.Variables = subscription.Variables - config.trigger.Source = subscription.DataSource - config.trigger.ProcessResponseConfig = subscription.ProcessResponseConfig - v.resolveInputTemplates(config, &subscription.Input, &config.trigger.Variables) - config.trigger.Input = []byte(subscription.Input) -} - -func (v *Visitor) configureObjectFetch(config objectFetchConfiguration) { - if config.object == nil { - return - } - fetchConfig := config.planner.ConfigureFetch() - fetch := v.configureFetch(config, fetchConfig) - - switch f := fetch.(type) { - case *resolve.SingleFetch: - v.resolveInputTemplates(config, &f.Input, &f.Variables) - case *resolve.BatchFetch: - v.resolveInputTemplates(config, &f.Fetch.Input, &f.Fetch.Variables) - } - if config.object.Fetch == nil { - config.object.Fetch = fetch - return - } - switch existing := config.object.Fetch.(type) { - case *resolve.SingleFetch: - copyOfExisting := *existing - parallel := &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{©OfExisting, fetch}, - } - config.object.Fetch = parallel - case *resolve.BatchFetch: - copyOfExisting := *existing - parallel := &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{©OfExisting, fetch}, - } - config.object.Fetch = parallel - case *resolve.ParallelFetch: - existing.Fetches = append(existing.Fetches, fetch) - } -} - -func (v *Visitor) configureFetch(internal objectFetchConfiguration, external FetchConfiguration) resolve.Fetch { - dataSourceType := reflect.TypeOf(external.DataSource).String() - dataSourceType = strings.TrimPrefix(dataSourceType, "*") - - singleFetch := &resolve.SingleFetch{ - BufferId: internal.bufferID, - Input: external.Input, - DataSource: external.DataSource, - Variables: external.Variables, - DisallowSingleFlight: external.DisallowSingleFlight, - DataSourceIdentifier: []byte(dataSourceType), - ProcessResponseConfig: external.ProcessResponseConfig, - DisableDataLoader: external.DisableDataLoader, - SetTemplateOutputToNullOnVariableNull: external.SetTemplateOutputToNullOnVariableNull, - } - - // if a field depends on an exported variable, data loader needs to be disabled - // this is because the data loader will render all input templates before all fields are evaluated - // exporting field values into a variable depends on the field being evaluated first - // for that reason, if a field depends on an exported variable, data loader needs to be disabled - disableDataLoader := v.fieldRequiresExportedVariable(internal.fieldRef) - if disableDataLoader { - singleFetch.DisableDataLoader = true - } - - if !external.BatchConfig.AllowBatch { - return singleFetch - } - - return &resolve.BatchFetch{ - Fetch: singleFetch, - BatchFactory: external.BatchConfig.BatchFactory, - } -} - -type Kind int - -const ( - SynchronousResponseKind Kind = iota + 1 - StreamingResponseKind - SubscriptionResponseKind -) - -type Plan interface { - PlanKind() Kind - SetFlushInterval(interval int64) -} - -type SynchronousResponsePlan struct { - Response *resolve.GraphQLResponse - FlushInterval int64 -} - -func (s *SynchronousResponsePlan) SetFlushInterval(interval int64) { - s.FlushInterval = interval -} - -func (_ *SynchronousResponsePlan) PlanKind() Kind { - return SynchronousResponseKind -} - -type StreamingResponsePlan struct { - Response *resolve.GraphQLStreamingResponse - FlushInterval int64 -} - -func (s *StreamingResponsePlan) SetFlushInterval(interval int64) { - s.FlushInterval = interval -} - -func (_ *StreamingResponsePlan) PlanKind() Kind { - return StreamingResponseKind -} - -type SubscriptionResponsePlan struct { - Response *resolve.GraphQLSubscription - FlushInterval int64 -} - -func (s *SubscriptionResponsePlan) SetFlushInterval(interval int64) { - s.FlushInterval = interval -} - -func (_ *SubscriptionResponsePlan) PlanKind() Kind { - return SubscriptionResponseKind -} - -type DataSourcePlanningBehavior struct { - // MergeAliasedRootNodes will reuse a data source for multiple root fields with aliases if true. - // Example: - // { - // rootField - // alias: rootField - // } - // On dynamic data sources (e.g. GraphQL, SQL, ...) this should return true and for - // static data sources (e.g. REST, static, GRPC...) it should be false. - MergeAliasedRootNodes bool - // OverrideFieldPathFromAlias will let the planner know if the response path should also be aliased (= true) - // or not (= false) - // Example: - // { - // rootField - // alias: original - // } - // When true expected response will be { "rootField": ..., "alias": ... } - // When false expected response will be { "rootField": ..., "original": ... } - OverrideFieldPathFromAlias bool - // IncludeTypeNameFields should be set to true if the planner wants to get EnterField & LeaveField events - // for __typename fields - IncludeTypeNameFields bool -} - -type DataSourcePlanner interface { - Register(visitor *Visitor, configuration DataSourceConfiguration, isNested bool) error - ConfigureFetch() FetchConfiguration - ConfigureSubscription() SubscriptionConfiguration - DataSourcePlanningBehavior() DataSourcePlanningBehavior - // DownstreamResponseFieldAlias allows the DataSourcePlanner to overwrite the response path with an alias - // It's required to set OverrideFieldPathFromAlias to true - // This function is useful in the following scenario - // 1. The downstream Query doesn't contain an alias - // 2. The path configuration rewrites the field to an existing field - // 3. The DataSourcePlanner is using an alias to the upstream - // Example: - // - // type Query { - // country: Country - // countryAlias: Country - // } - // - // Both, country and countryAlias have a path in the FieldConfiguration of "country" - // In theory, they would be treated as the same field - // However, by using DownstreamResponseFieldAlias, it's possible for the DataSourcePlanner to use an alias for countryAlias. - // In this case, the response would contain both, country and countryAlias fields in the response. - // At the same time, the downstream Query would only expect the response on the path "country", - // as both country and countryAlias have a mapping to the path "country". - // The DataSourcePlanner could keep track that it rewrites the upstream query and use DownstreamResponseFieldAlias - // to indicate to the Planner to expect the response for countryAlias on the path "countryAlias" instead of "country". - DownstreamResponseFieldAlias(downstreamFieldRef int) (alias string, exists bool) -} - -type SubscriptionConfiguration struct { - Input string - Variables resolve.Variables - DataSource resolve.SubscriptionDataSource - ProcessResponseConfig resolve.ProcessResponseConfig -} - -type FetchConfiguration struct { - Input string - Variables resolve.Variables - DataSource resolve.DataSource - DisallowSingleFlight bool - // DisableDataLoader will configure the Resolver to not use DataLoader - // If this is set to false, the planner might still decide to override it, - // e.g. if a field depends on an exported variable which doesn't work with DataLoader - DisableDataLoader bool - ProcessResponseConfig resolve.ProcessResponseConfig - BatchConfig BatchConfig - // SetTemplateOutputToNullOnVariableNull will safely return "null" if one of the template variables renders to null - // This is the case, e.g. when using batching and one sibling is null, resulting in a null value for one batch item - // Returning null in this case tells the batch implementation to skip this item - SetTemplateOutputToNullOnVariableNull bool -} - -type BatchConfig struct { - AllowBatch bool - BatchFactory resolve.DataSourceBatchFactory -} - -type configurationVisitor struct { - operationName string - operation, definition *ast.Document - walker *astvisitor.Walker - config Configuration - planners []plannerConfiguration - fetches []objectFetchConfiguration - currentBufferId int - fieldBuffers map[int]int - - parentTypeNodes []ast.Node - - ctx context.Context -} - -func (c *configurationVisitor) EnterSelectionSet(_ int) { - c.parentTypeNodes = append(c.parentTypeNodes, c.walker.EnclosingTypeDefinition) -} - -func (c *configurationVisitor) LeaveSelectionSet(_ int) { - c.parentTypeNodes = c.parentTypeNodes[:len(c.parentTypeNodes)-1] -} - -type plannerConfiguration struct { - parentPath string - planner DataSourcePlanner - paths []pathConfiguration - dataSourceConfiguration DataSourceConfiguration - bufferID int -} - -// isNestedPlanner returns true in case the planner is not directly attached to the Operation root -// a nested planner should always build a Query -func (p *plannerConfiguration) isNestedPlanner() bool { - for i := range p.paths { - pathElements := strings.Count(p.paths[i].path, ".") + 1 - if pathElements == 2 { - return false - } - } - return true -} - -func (c *configurationVisitor) nextBufferID() int { - c.currentBufferId++ - return c.currentBufferId -} - -func (p *plannerConfiguration) hasPath(path string) bool { - for i := range p.paths { - if p.paths[i].path == path { - return true - } - } - return false -} - -func (p *plannerConfiguration) isExitPath(path string) bool { - for i := range p.paths { - if p.paths[i].path == path { - return p.paths[i].exitPlannerOnNode - } - } - return false -} - -func (p *plannerConfiguration) shouldWalkFieldsOnPath(path string) bool { - for i := range p.paths { - if p.paths[i].path == path { - return p.paths[i].shouldWalkFields - } - } - return false -} - -func (p *plannerConfiguration) setPathExit(path string) { - for i := range p.paths { - if p.paths[i].path == path { - p.paths[i].exitPlannerOnNode = true - return - } - } -} - -func (p *plannerConfiguration) hasPathPrefix(prefix string) bool { - for i := range p.paths { - if p.paths[i].path == prefix { - continue - } - if strings.HasPrefix(p.paths[i].path, prefix) { - return true - } - } - return false -} - -func (p *plannerConfiguration) hasParent(parent string) bool { - return p.parentPath == parent -} - -func (p *plannerConfiguration) hasChildNode(typeName, fieldName string) bool { - for i := range p.dataSourceConfiguration.ChildNodes { - if typeName != p.dataSourceConfiguration.ChildNodes[i].TypeName { - continue - } - for j := range p.dataSourceConfiguration.ChildNodes[i].FieldNames { - if fieldName == p.dataSourceConfiguration.ChildNodes[i].FieldNames[j] { - return true - } - } - } - return false -} - -func (p *plannerConfiguration) hasRootNode(typeName, fieldName string) bool { - for i := range p.dataSourceConfiguration.RootNodes { - if typeName != p.dataSourceConfiguration.RootNodes[i].TypeName { - continue - } - for j := range p.dataSourceConfiguration.RootNodes[i].FieldNames { - if fieldName == p.dataSourceConfiguration.RootNodes[i].FieldNames[j] { - return true - } - } - } - return false -} - -type pathConfiguration struct { - path string - exitPlannerOnNode bool - // shouldWalkFields indicates whether the planner is allowed to walk into fields - // this is needed in case we're dealing with a nested federated abstract query - // we need to be able to walk into the inline fragments and selection sets in the root - // however, we want to skip the fields at this level - // so, by setting shouldWalkFields to false, we can walk into non fields only - shouldWalkFields bool -} - -func (c *configurationVisitor) EnterOperationDefinition(ref int) { - operationName := c.operation.OperationDefinitionNameString(ref) - if c.operationName != operationName { - c.walker.SkipNode() - return - } -} - -func (c *configurationVisitor) EnterField(ref int) { - fieldName := c.operation.FieldNameUnsafeString(ref) - fieldAliasOrName := c.operation.FieldAliasOrNameString(ref) - typeName := c.walker.EnclosingTypeDefinition.NameString(c.definition) - parentPath := c.walker.Path.DotDelimitedString() - currentPath := parentPath + "." + fieldAliasOrName - root := c.walker.Ancestors[0] - if root.Kind != ast.NodeKindOperationDefinition { - return - } - isSubscription := c.isSubscription(root.Ref, currentPath) - for i, plannerConfig := range c.planners { - planningBehaviour := plannerConfig.planner.DataSourcePlanningBehavior() - if fieldAliasOrName == "__typename" && planningBehaviour.IncludeTypeNameFields { - c.planners[i].paths = append(c.planners[i].paths, pathConfiguration{path: currentPath, shouldWalkFields: true}) - return - } - if plannerConfig.hasParent(parentPath) && plannerConfig.hasRootNode(typeName, fieldName) && planningBehaviour.MergeAliasedRootNodes { - // same parent + root node = root sibling - c.planners[i].paths = append(c.planners[i].paths, pathConfiguration{path: currentPath, shouldWalkFields: true}) - c.fieldBuffers[ref] = plannerConfig.bufferID - return - } - if plannerConfig.hasPath(parentPath) { - if plannerConfig.hasChildNode(typeName, fieldName) { - // has parent path + has child node = child - c.planners[i].paths = append(c.planners[i].paths, pathConfiguration{path: currentPath, shouldWalkFields: true}) - return - } - - if pathAdded := c.addPlannerPathForUnionChildOfObjectParent(ref, i, currentPath); pathAdded { - return - } - - if pathAdded := c.addPlannerPathForChildOfAbstractParent(i, typeName, fieldName, currentPath); pathAdded { - return - } - } - } - for i, config := range c.config.DataSources { - if !config.HasRootNode(typeName, fieldName) { - continue - } - var ( - bufferID int - ) - if !isSubscription { - bufferID = c.nextBufferID() - c.fieldBuffers[ref] = bufferID - } - planner := c.config.DataSources[i].Factory.Planner(c.ctx) - isParentAbstract := c.isParentTypeNodeAbstractType() - paths := []pathConfiguration{ - { - path: currentPath, - shouldWalkFields: true, - }, - } - if isParentAbstract { - // if the parent is abstract, we add the parent path as well - // this will ensure that we're walking into and out of the root inline fragments - // otherwise, we'd only walk into the fields inside the inline fragments in the root, - // so we'd miss the selection sets and inline fragments in the root - paths = append([]pathConfiguration{ - { - path: parentPath, - shouldWalkFields: false, - }, - }, paths...) - } - c.planners = append(c.planners, plannerConfiguration{ - bufferID: bufferID, - parentPath: parentPath, - planner: planner, - paths: paths, - dataSourceConfiguration: config, - }) - fieldDefinition, ok := c.walker.FieldDefinition(ref) - if !ok { - continue - } - c.fetches = append(c.fetches, objectFetchConfiguration{ - bufferID: bufferID, - planner: planner, - isSubscription: isSubscription, - fieldRef: ref, - fieldDefinitionRef: fieldDefinition, - }) - return - } -} - -func (c *configurationVisitor) addPlannerPathForUnionChildOfObjectParent(fieldRef int, plannerIndex int, currentPath string) (pathAdded bool) { - if c.walker.EnclosingTypeDefinition.Kind != ast.NodeKindObjectTypeDefinition { - return false - } - fieldDefRef, exists := c.definition.NodeFieldDefinitionByName(c.walker.EnclosingTypeDefinition, c.operation.FieldNameBytes(fieldRef)) - if !exists { - return false - } - - fieldDefTypeRef := c.definition.FieldDefinitionType(fieldDefRef) - fieldDefTypeName := c.definition.TypeNameBytes(fieldDefTypeRef) - node, ok := c.definition.NodeByName(fieldDefTypeName) - if !ok { - return false - } - - if node.Kind == ast.NodeKindUnionTypeDefinition { - c.planners[plannerIndex].paths = append(c.planners[plannerIndex].paths, pathConfiguration{path: currentPath, shouldWalkFields: true}) - return true - } - return false -} - -func (c *configurationVisitor) addPlannerPathForChildOfAbstractParent( - plannerIndex int, typeName, fieldName, currentPath string, -) (pathAdded bool) { - if !c.isParentTypeNodeAbstractType() { - return false - } - // If the field is a root node in any of the data sources, the path shouldn't be handled here - for _, d := range c.config.DataSources { - if d.HasRootNode(typeName, fieldName) { - return false - } - } - // The path for this field should only be added if the parent path also exists on this planner - c.planners[plannerIndex].paths = append(c.planners[plannerIndex].paths, pathConfiguration{path: currentPath, shouldWalkFields: true}) - return true -} - -func (c *configurationVisitor) isParentTypeNodeAbstractType() bool { - if len(c.parentTypeNodes) < 2 { - return false - } - parentTypeNode := c.parentTypeNodes[len(c.parentTypeNodes)-2] - return parentTypeNode.Kind.IsAbstractType() -} - -func (c *configurationVisitor) LeaveField(ref int) { - fieldAliasOrName := c.operation.FieldAliasOrNameString(ref) - parent := c.walker.Path.DotDelimitedString() - current := parent + "." + fieldAliasOrName - for i, planner := range c.planners { - if planner.hasPath(current) && !planner.hasPathPrefix(current) { - c.planners[i].setPathExit(current) - return - } - } -} - -func (c *configurationVisitor) EnterDocument(operation, definition *ast.Document) { - c.operation, c.definition = operation, definition - c.currentBufferId = -1 - c.parentTypeNodes = c.parentTypeNodes[:0] - if c.planners == nil { - c.planners = make([]plannerConfiguration, 0, 8) - } else { - c.planners = c.planners[:0] - } - if c.fetches == nil { - c.fetches = []objectFetchConfiguration{} - } else { - c.fetches = c.fetches[:0] - } - if c.fieldBuffers == nil { - c.fieldBuffers = map[int]int{} - } else { - for i := range c.fieldBuffers { - delete(c.fieldBuffers, i) - } - } -} - -func (c *configurationVisitor) isSubscription(root int, path string) bool { - rootOperationType := c.operation.OperationDefinitions[root].OperationType - if rootOperationType != ast.OperationTypeSubscription { - return false - } - return strings.Count(path, ".") == 1 -} - -type skipFieldData struct { - selectionSetRef int - fieldConfig *FieldConfiguration - requiredField string - fieldPath string -} - -type requiredFieldsVisitor struct { - operation, definition *ast.Document - walker *astvisitor.Walker - config *Configuration - operationName string - skipFieldPaths []string - // selectedFieldPaths is a set of all explicitly selected field paths - selectedFieldPaths map[string]struct{} - // skipFieldDataPaths is to prevent appending duplicate skipFieldData to potentialSkipFieldDatas - skipFieldDataPaths map[string]struct{} - // potentialSkipFieldDatas is used in LeaveDocument to determine whether a required field should be skipped - // Must be a slice to preserve field order, which is why duplicates are handled with a set - potentialSkipFieldDatas []*skipFieldData -} - -func (r *requiredFieldsVisitor) EnterDocument(_, _ *ast.Document) { - r.skipFieldPaths = r.skipFieldPaths[:0] - r.selectedFieldPaths = make(map[string]struct{}) - r.potentialSkipFieldDatas = make([]*skipFieldData, 0) -} - -func (r *requiredFieldsVisitor) EnterField(ref int) { - typeName := r.walker.EnclosingTypeDefinition.NameString(r.definition) - fieldName := r.operation.FieldNameUnsafeString(ref) - fieldConfig := r.config.Fields.ForTypeField(typeName, fieldName) - path := r.walker.Path.DotDelimitedString() - if fieldConfig == nil { - // Record all explicitly selected fields - // A field selected on an interface will have the same field path as a fragment on an object - // LeaveDocument uses this record to ensure only required fields that were not explicitly selected are skipped - r.selectedFieldPaths[fmt.Sprintf("%s.%s", path, fieldName)] = struct{}{} - return - } - if len(fieldConfig.RequiresFields) == 0 { - return - } - selectionSet := r.walker.Ancestors[len(r.walker.Ancestors)-1] - if selectionSet.Kind != ast.NodeKindSelectionSet { - return - } - for _, requiredField := range fieldConfig.RequiresFields { - requiredFieldPath := fmt.Sprintf("%s.%s", path, requiredField) - // Prevent adding duplicates to the slice (order is necessary; hence, a separate map) - if _, ok := r.skipFieldDataPaths[requiredFieldPath]; ok { - continue - } - // For each required field, collect the data required to handle (in LeaveDocument) whether we should skip it - data := &skipFieldData{ - selectionSetRef: selectionSet.Ref, - fieldConfig: fieldConfig, - requiredField: requiredField, - fieldPath: requiredFieldPath, - } - r.potentialSkipFieldDatas = append(r.potentialSkipFieldDatas, data) - } -} - -func (r *requiredFieldsVisitor) handleRequiredField(selectionSet int, requiredFieldName, fullFieldPath string) { - for _, ref := range r.operation.SelectionSets[selectionSet].SelectionRefs { - selection := r.operation.Selections[ref] - if selection.Kind != ast.SelectionKindField { - continue - } - name := r.operation.FieldAliasOrNameString(selection.Ref) - if name == requiredFieldName { - // already exists - return - } - } - r.addRequiredField(requiredFieldName, selectionSet, fullFieldPath) -} - -func (r *requiredFieldsVisitor) addRequiredField(fieldName string, selectionSet int, fullFieldPath string) { - field := ast.Field{ - Name: r.operation.Input.AppendInputString(fieldName), - } - addedField := r.operation.AddField(field) - selection := ast.Selection{ - Kind: ast.SelectionKindField, - Ref: addedField.Ref, - } - r.operation.AddSelection(selectionSet, selection) - r.skipFieldPaths = append(r.skipFieldPaths, fullFieldPath) -} - -func (r *requiredFieldsVisitor) EnterOperationDefinition(ref int) { - operationName := r.operation.OperationDefinitionNameString(ref) - if r.operationName != operationName { - r.walker.SkipNode() - return - } -} - -func (r *requiredFieldsVisitor) LeaveDocument(_, _ *ast.Document) { - for _, data := range r.potentialSkipFieldDatas { - path := data.fieldPath - // If a field was not explicitly selected, skip it - if _, ok := r.selectedFieldPaths[path]; !ok { - r.handleRequiredField(data.selectionSetRef, data.requiredField, path) - } - } -} diff --git a/pkg/engine/plan/plan_closer_test.go b/pkg/engine/plan/plan_closer_test.go deleted file mode 100644 index cd8f0f82d..000000000 --- a/pkg/engine/plan/plan_closer_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package plan - -import ( - "context" - "io" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestCloser(t *testing.T) { - - definition := `schema {query:Query} type Query { me: String! }` - operation := `{me}` - - def := unsafeparser.ParseGraphqlDocumentString(definition) - op := unsafeparser.ParseGraphqlDocumentString(operation) - err := asttransform.MergeDefinitionWithBaseSchema(&def) - if err != nil { - t.Fatal(err) - } - norm := astnormalization.NewNormalizer(true, true) - report := &operationreport.Report{} - norm.NormalizeOperation(&op, &def, report) - valid := astvalidation.DefaultOperationValidator() - valid.Validate(&op, &def, report) - - ctx, cancel := context.WithCancel(context.Background()) - closedSignal := make(chan struct{}) - - factory := &FakeFactory{ - signalClosed: closedSignal, - } - - cfg := Configuration{ - DefaultFlushIntervalMillis: 500, - DataSources: []DataSourceConfiguration{ - { - RootNodes: []TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - }, - ChildNodes: nil, - Factory: factory, - Custom: nil, - }, - }, - Fields: nil, - } - - p := NewPlanner(ctx, cfg) - plan := p.Plan(&op, &def, "", report) - assert.NotNil(t, plan) - - cancel() // terminate all stateful sources - <-ctx.Done() // stateful source closed from closer - <-closedSignal - // test terminates only if stateful source closed -} - -type StatefulSource struct { - signalClosed chan struct{} -} - -func (s *StatefulSource) Start(ctx context.Context) { - <-ctx.Done() - close(s.signalClosed) -} - -type FakeFactory struct { - signalClosed chan struct{} -} - -func (f *FakeFactory) Planner(ctx context.Context) DataSourcePlanner { - source := &StatefulSource{ - signalClosed: f.signalClosed, - } - go source.Start(ctx) - return &FakePlanner{ - source: source, - } -} - -type FakePlanner struct { - source *StatefulSource -} - -func (f *FakePlanner) EnterDocument(operation, definition *ast.Document) { - -} - -func (f *FakePlanner) Register(visitor *Visitor, configuration DataSourceConfiguration, isNested bool) error { - visitor.Walker.RegisterEnterDocumentVisitor(f) - return nil -} - -func (f *FakePlanner) ConfigureFetch() FetchConfiguration { - return FetchConfiguration{ - DataSource: &FakeDataSource{ - source: f.source, - }, - } -} - -func (f *FakePlanner) ConfigureSubscription() SubscriptionConfiguration { - return SubscriptionConfiguration{} -} - -func (f *FakePlanner) DataSourcePlanningBehavior() DataSourcePlanningBehavior { - return DataSourcePlanningBehavior{ - MergeAliasedRootNodes: false, - OverrideFieldPathFromAlias: false, - } -} - -func (f *FakePlanner) DownstreamResponseFieldAlias(downstreamFieldRef int) (alias string, exists bool) { - return -} - -type FakeDataSource struct { - source *StatefulSource -} - -func (f *FakeDataSource) Load(ctx context.Context, input []byte, w io.Writer) (err error) { - return -} diff --git a/pkg/engine/plan/plan_test.go b/pkg/engine/plan/plan_test.go deleted file mode 100644 index d57cad202..000000000 --- a/pkg/engine/plan/plan_test.go +++ /dev/null @@ -1,723 +0,0 @@ -package plan - -import ( - "context" - "encoding/json" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestPlanner_Plan(t *testing.T) { - testLogic := func(definition, operation, operationName string, config Configuration, report *operationreport.Report) Plan { - def := unsafeparser.ParseGraphqlDocumentString(definition) - op := unsafeparser.ParseGraphqlDocumentString(operation) - err := asttransform.MergeDefinitionWithBaseSchema(&def) - if err != nil { - t.Fatal(err) - } - norm := astnormalization.NewNormalizer(true, true) - norm.NormalizeOperation(&op, &def, report) - valid := astvalidation.DefaultOperationValidator() - valid.Validate(&op, &def, report) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - p := NewPlanner(ctx, config) - return p.Plan(&op, &def, operationName, report) - } - - test := func(definition, operation, operationName string, expectedPlan Plan, config Configuration) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - var report operationreport.Report - plan := testLogic(definition, operation, operationName, config, &report) - if report.HasErrors() { - t.Fatal(report.Error()) - } - assert.Equal(t, expectedPlan, plan) - - toJson := func(v interface{}) string { - b := &strings.Builder{} - e := json.NewEncoder(b) - e.SetIndent("", " ") - _ = e.Encode(v) - return b.String() - } - - assert.Equal(t, toJson(expectedPlan), toJson(plan)) - - } - } - - testWithError := func(definition, operation, operationName string, config Configuration) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - var report operationreport.Report - _ = testLogic(definition, operation, operationName, config, &report) - assert.True(t, report.HasErrors()) - } - } - - t.Run("stream & defer Query", test(testDefinition, ` - query MyQuery($id: ID!) @flushInterval(milliSeconds: 100) { - droid(id: $id){ - name - aliased: name - friends @stream { - name - } - friendsWithInitialBatch: friends @stream(initialBatchSize: 5) { - name - } - primaryFunction - favoriteEpisode @defer - } - } - `, "MyQuery", &SynchronousResponsePlan{ - FlushInterval: 100, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("droid"), - Position: resolve.Position{ - Line: 3, - Column: 4, - }, - Value: &resolve.Object{ - Path: []string{"droid"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 4, - Column: 5, - }, - }, - { - Name: []byte("aliased"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 5, - Column: 5, - }, - }, - { - Name: []byte("friends"), - Stream: &resolve.StreamField{ - InitialBatchSize: 0, - }, - Position: resolve.Position{ - Line: 6, - Column: 5, - }, - Value: &resolve.Array{ - Nullable: true, - Path: []string{"friends"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 7, - Column: 6, - }, - }, - }, - }, - }, - }, - { - Name: []byte("friendsWithInitialBatch"), - Position: resolve.Position{ - Line: 9, - Column: 5, - }, - Stream: &resolve.StreamField{ - InitialBatchSize: 5, - }, - Value: &resolve.Array{ - Nullable: true, - Path: []string{"friends"}, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 10, - Column: 6, - }, - }, - }, - }, - }, - }, - { - Name: []byte("primaryFunction"), - Position: resolve.Position{ - Line: 12, - Column: 5, - }, - Value: &resolve.String{ - Path: []string{"primaryFunction"}, - }, - }, - { - Name: []byte("favoriteEpisode"), - Position: resolve.Position{ - Line: 13, - Column: 5, - }, - Defer: &resolve.DeferField{}, - Value: &resolve.String{ - Nullable: true, - Path: []string{"favoriteEpisode"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, Configuration{ - DefaultFlushIntervalMillis: 0, - })) - - t.Run("Union response type with interface fragments", test(testDefinition, ` - query SearchResults { - searchResults { - ... on Character { - name - } - ... on Vehicle { - length - } - } - } - `, "SearchResults", &SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Nullable: false, - Fields: []*resolve.Field{ - { - Name: []byte("searchResults"), - Value: &resolve.Array{ - Path: []string{"searchResults"}, - Nullable: true, - ResolveAsynchronous: false, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - Nullable: false, - }, - OnTypeNames: [][]byte{[]byte("Human"), []byte("Droid")}, - }, - { - Name: []byte("length"), - Value: &resolve.Float{ - Path: []string{"length"}, - Nullable: false, - }, - OnTypeNames: [][]byte{[]byte("Starship")}, - }, - }, - }, - }, - }, - }, - }, - }, - }, Configuration{ - DisableResolveFieldPositions: true, - })) - - t.Run("operation selection", func(t *testing.T) { - t.Run("should successfully plan a single named query by providing an operation name", test(testDefinition, ` - query MyHero { - hero{ - name - } - } - `, "MyHero", expectedMyHeroPlan, Configuration{}, - )) - - t.Run("should successfully plan unnamed query with fragment", test(testDefinition, ` - fragment CharacterFields on Character { - name - } - query { - hero { - ...CharacterFields - } - } - `, "", expectedMyHeroPlanWithFragment, Configuration{}, - )) - - t.Run("should successfully plan multiple named queries by providing an operation name", test(testDefinition, ` - query MyHero { - hero { - name - } - } - - query MyDroid($id: ID!) { - droid(id: $id){ - name - } - } - `, "MyHero", expectedMyHeroPlan, Configuration{}, - )) - - t.Run("should successfully plan a single named query without providing an operation name", test(testDefinition, ` - query MyHero { - hero { - name - } - } - `, "", expectedMyHeroPlan, Configuration{}, - )) - - t.Run("should successfully plan a single unnamed query without providing an operation name", test(testDefinition, ` - { - hero { - name - } - } - `, "", expectedMyHeroPlan, Configuration{}, - )) - - t.Run("should write into error report when no query with name was found", testWithError(testDefinition, ` - query MyHero { - hero{ - name - } - } - `, "NoHero", Configuration{}, - )) - - t.Run("should write into error report when no operation name was provided on multiple named queries", testWithError(testDefinition, ` - query MyDroid($id: ID!) { - droid(id: $id){ - name - } - } - - query MyHero { - hero{ - name - } - } - `, "", Configuration{}, - )) - }) - - t.Run("unescape response json", func(t *testing.T) { - schema := ` - scalar JSON - - schema { - query: Query - } - - type Query { - hero: Character! - } - - type Character { - info: JSON! - infos: [JSON!]! - optInfo: JSON - } - ` - - t.Run("with field configuration", func(t *testing.T) { - t.Run("field with json type", test( - schema, ` - { - hero { - info - } - } - `, "", - &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Fields: []*resolve.Field{ - { - Name: []byte("info"), - Value: &resolve.String{ - Path: []string{"info"}, - UnescapeResponseJson: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Configuration{ - DisableResolveFieldPositions: true, - Fields: FieldConfigurations{ - FieldConfiguration{ - TypeName: "Character", - FieldName: "info", - UnescapeResponseJson: true, - }, - }, - }, - )) - t.Run("list with json type", test( - schema, ` - { - hero { - infos - } - } - `, "", - &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Fields: []*resolve.Field{ - { - Name: []byte("infos"), - Value: &resolve.Array{ - Path: []string{"infos"}, - Item: &resolve.String{ - UnescapeResponseJson: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Configuration{ - DisableResolveFieldPositions: true, - Fields: FieldConfigurations{ - FieldConfiguration{ - TypeName: "Character", - FieldName: "infos", - UnescapeResponseJson: true, - }, - }, - }, - )) - }) - - t.Run("without field configuration", func(t *testing.T) { - t.Run("field with json type", test( - schema, ` - { - hero { - info - } - } - `, "", - &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Fields: []*resolve.Field{ - { - Name: []byte("info"), - Value: &resolve.String{ - Path: []string{"info"}, - UnescapeResponseJson: false, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Configuration{ - DisableResolveFieldPositions: true, - }, - )) - }) - - t.Run("field with required custom resolve", test( - schema, ` - { - hero { - info - } - } - `, "", - &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Fields: []*resolve.Field{ - { - Name: []byte("info"), - Value: &resolve.CustomNode{ - Path: []string{"info"}, - Nullable: false, - CustomResolve: &customResolver{}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Configuration{ - DisableResolveFieldPositions: true, - CustomResolveMap: map[string]resolve.CustomResolve{ - "JSON": &customResolver{}, - }, - }, - )) - - t.Run("field with nullable custom resolve", test( - schema, ` - { - hero { - optInfo - } - } - `, "", - &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Value: &resolve.Object{ - Path: []string{"hero"}, - Fields: []*resolve.Field{ - { - Name: []byte("optInfo"), - Value: &resolve.CustomNode{ - Path: []string{"optInfo"}, - Nullable: true, - CustomResolve: &customResolver{}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Configuration{ - DisableResolveFieldPositions: true, - CustomResolveMap: map[string]resolve.CustomResolve{ - "JSON": &customResolver{}, - }, - }, - )) - }) -} - -type customResolver struct{} - -func (customResolver) Resolve(data []byte) ([]byte, error) { - return data, nil -} - -var expectedMyHeroPlan = &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Position: resolve.Position{ - Line: 3, - Column: 6, - }, - Value: &resolve.Object{ - Path: []string{"hero"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 4, - Column: 7, - }, - }, - }, - }, - }, - }, - }, - }, -} - -var expectedMyHeroPlanWithFragment = &SynchronousResponsePlan{ - FlushInterval: 0, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("hero"), - Position: resolve.Position{ - Line: 6, - Column: 6, - }, - Value: &resolve.Object{ - Path: []string{"hero"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - Position: resolve.Position{ - Line: 3, - Column: 6, - }, - }, - }, - }, - }, - }, - }, - }, -} - -const testDefinition = ` - -directive @defer on FIELD - -directive @flushInterval(milliSeconds: Int!) on QUERY | SUBSCRIPTION - -directive @stream(initialBatchSize: Int) on FIELD - -union SearchResult = Human | Droid | Starship - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Query { - hero: Character - droid(id: ID!): Droid - search(name: String!): SearchResult - searchResults: [SearchResult] -} - -type Mutation { - createReview(episode: Episode!, review: ReviewInput!): Review -} - -type Subscription { - remainingJedis: Int! - newReviews: Review -} - -input ReviewInput { - stars: Int! - commentary: String -} - -type Review { - id: ID! - stars: Int! - commentary: String -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI -} - -interface Character { - name: String! - friends: [Character] -} - -type Human implements Character { - name: String! - height: String! - friends: [Character] -} - -type Droid implements Character { - name: String! - primaryFunction: String! - friends: [Character] - favoriteEpisode: Episode -} - -interface Vehicle { - length: Float! -} - -type Starship implements Vehicle { - name: String! - length: Float! -} -` diff --git a/pkg/engine/plan/required_field_extractor.go b/pkg/engine/plan/required_field_extractor.go deleted file mode 100644 index f84b7cc4c..000000000 --- a/pkg/engine/plan/required_field_extractor.go +++ /dev/null @@ -1,140 +0,0 @@ -package plan - -import ( - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -var fieldsArgumentNameBytes = []byte("fields") - -// RequiredFieldExtractor extracts all required fields from an ast.Document -// containing a parsed federation subgraph SDL -// by visiting the directives specified in the federation specification -// and extracting the required meta data -type RequiredFieldExtractor struct { - document *ast.Document -} - -func NewRequiredFieldExtractor(document *ast.Document) *RequiredFieldExtractor { - return &RequiredFieldExtractor{ - document: document, - } -} - -func (f *RequiredFieldExtractor) GetAllRequiredFields() FieldConfigurations { - var fieldRequires FieldConfigurations - - f.addFieldsForObjectExtensionDefinitions(&fieldRequires) - f.addFieldsForObjectDefinitions(&fieldRequires) - - return fieldRequires -} - -func (f *RequiredFieldExtractor) addFieldsForObjectExtensionDefinitions(fieldRequires *FieldConfigurations) { - for _, objectTypeExt := range f.document.ObjectTypeExtensions { - objectType := objectTypeExt.ObjectTypeDefinition - typeName := f.document.Input.ByteSliceString(objectType.Name) - - primaryKeys, exists := f.primaryKeyFieldsIfObjectTypeIsEntity(objectType) - if !exists { - continue - } - - for _, fieldDefinitionRef := range objectType.FieldsDefinition.Refs { - if f.document.FieldDefinitionHasNamedDirective(fieldDefinitionRef, federationExternalDirectiveName) { - continue - } - - fieldName := f.document.FieldDefinitionNameString(fieldDefinitionRef) - - requiredFields := make([]string, len(primaryKeys)) - copy(requiredFields, primaryKeys) - - requiredFieldsByRequiresDirective := requiredFieldsByRequiresDirective(f.document, fieldDefinitionRef) - requiredFields = append(requiredFields, requiredFieldsByRequiresDirective...) - - *fieldRequires = append(*fieldRequires, FieldConfiguration{ - TypeName: typeName, - FieldName: fieldName, - RequiresFields: requiredFields, - }) - } - } -} - -func (f *RequiredFieldExtractor) addFieldsForObjectDefinitions(fieldRequires *FieldConfigurations) { - for _, objectType := range f.document.ObjectTypeDefinitions { - typeName := f.document.Input.ByteSliceString(objectType.Name) - - primaryKeys, exists := f.primaryKeyFieldsIfObjectTypeIsEntity(objectType) - if !exists { - continue - } - - primaryKeysSet := make(map[string]struct{}, len(primaryKeys)) - for _, val := range primaryKeys { - primaryKeysSet[val] = struct{}{} - } - - for _, fieldRef := range objectType.FieldsDefinition.Refs { - fieldName := f.document.FieldDefinitionNameString(fieldRef) - if _, exists := primaryKeysSet[fieldName]; exists { // Field is part of primary key, it couldn't have any required fields - continue - } - - requiredFields := make([]string, len(primaryKeys)) - copy(requiredFields, primaryKeys) - - *fieldRequires = append(*fieldRequires, FieldConfiguration{ - TypeName: typeName, - FieldName: fieldName, - RequiresFields: requiredFields, - }) - } - } -} - -func requiredFieldsByRequiresDirective(document *ast.Document, fieldDefinitionRef int) []string { - for _, directiveRef := range document.FieldDefinitions[fieldDefinitionRef].Directives.Refs { - if directiveName := document.DirectiveNameString(directiveRef); directiveName != federationRequireDirectiveName { - continue - } - - value, exists := document.DirectiveArgumentValueByName(directiveRef, fieldsArgumentNameBytes) - if !exists { - continue - } - if value.Kind != ast.ValueKindString { - continue - } - - fieldsStr := document.StringValueContentString(value.Ref) - - return strings.Split(fieldsStr, " ") - } - - return nil -} - -func (f *RequiredFieldExtractor) primaryKeyFieldsIfObjectTypeIsEntity(objectType ast.ObjectTypeDefinition) (keyFields []string, ok bool) { - for _, directiveRef := range objectType.Directives.Refs { - if directiveName := f.document.DirectiveNameString(directiveRef); directiveName != FederationKeyDirectiveName { - continue - } - - value, exists := f.document.DirectiveArgumentValueByName(directiveRef, fieldsArgumentNameBytes) - if !exists { - continue - } - if value.Kind != ast.ValueKindString { - continue - } - - fieldsStr := f.document.StringValueContentString(value.Ref) - - return strings.Split(fieldsStr, " "), true - } - - return nil, false -} diff --git a/pkg/engine/plan/required_field_extractor_test.go b/pkg/engine/plan/required_field_extractor_test.go deleted file mode 100644 index f50b16849..000000000 --- a/pkg/engine/plan/required_field_extractor_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package plan - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func TestRequiredFieldExtractor_GetAllFieldRequires(t *testing.T) { - run := func(t *testing.T, SDL string, expected FieldConfigurations) { - document := unsafeparser.ParseGraphqlDocumentString(SDL) - extractor := &RequiredFieldExtractor{document: &document} - got := extractor.GetAllRequiredFields() - assert.Equal(t, expected, got) - } - - t.Run("non Entity object", func(t *testing.T) { - run(t, ` - type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! - } - `, nil) - }) - t.Run("non Entity object extension", func(t *testing.T) { - run(t, ` - type Review { - body: String! - } - - extend type Review { - title: String! - } - `, nil) - }) - t.Run("Entity with simple primary key", func(t *testing.T) { - run(t, ` - type Review @key(fields: "id"){ - id: Int! - body: String! - title: String - } - `, FieldConfigurations{ - {TypeName: "Review", FieldName: "body", RequiresFields: []string{"id"}}, - {TypeName: "Review", FieldName: "title", RequiresFields: []string{"id"}}, - }) - }) - t.Run("Entity with composed primary key", func(t *testing.T) { - run(t, ` - type Review @key(fields: "id author"){ - id: Int! - body: String! - title: String - author: String! - } - `, FieldConfigurations{ - {TypeName: "Review", FieldName: "body", RequiresFields: []string{"id", "author"}}, - {TypeName: "Review", FieldName: "title", RequiresFields: []string{"id", "author"}}, - }) - }) - t.Run("Entity object extension without non-primary external fields", func(t *testing.T) { - run(t, ` - extend type Review @key(fields: "id"){ - id: Int! @external - author: String! - } - `, FieldConfigurations{ - {TypeName: "Review", FieldName: "author", RequiresFields: []string{"id"}}, - }) - }) - t.Run("Entity object extension with \"requires\" directive", func(t *testing.T) { - run(t, ` - extend type Review @key(fields: "id"){ - id: Int! @external - title: String! @external - author: String! @external - slug: String @requires(fields: "title author") - } - `, FieldConfigurations{ - {TypeName: "Review", FieldName: "slug", RequiresFields: []string{"id", "title", "author"}}, - }) - }) -} diff --git a/pkg/engine/resolve/dataloader.go b/pkg/engine/resolve/dataloader.go deleted file mode 100644 index e37e08540..000000000 --- a/pkg/engine/resolve/dataloader.go +++ /dev/null @@ -1,517 +0,0 @@ -package resolve - -import ( - "fmt" - "sync" - - "github.com/buger/jsonparser" - - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" -) - -const ( - initialValueID = -1 - arrayElementKey = "@" -) - -// dataLoaderFactory is responsible for creating dataloader and provides different pools (e.g, bufPair, -// bufPairSlice, waitGroup pools). -type dataLoaderFactory struct { - dataloaderPool sync.Pool - muPool sync.Pool - waitGroupPool sync.Pool - bufPairPool sync.Pool - bufPairSlicePool sync.Pool - - fetcher *Fetcher -} - -func (df *dataLoaderFactory) getWaitGroup() *sync.WaitGroup { - return df.waitGroupPool.Get().(*sync.WaitGroup) -} - -func (df *dataLoaderFactory) freeWaitGroup(wg *sync.WaitGroup) { - df.waitGroupPool.Put(wg) -} - -func (df *dataLoaderFactory) getBufPairSlicePool() *[]*BufPair { - return df.bufPairSlicePool.Get().(*[]*BufPair) -} - -func (df *dataLoaderFactory) freeBufPairSlice(slice *[]*BufPair) { - for i := range *slice { - df.freeBufPair((*slice)[i]) - } - *slice = (*slice)[:0] - df.bufPairSlicePool.Put(slice) -} - -func (df *dataLoaderFactory) getBufPair() *BufPair { - return df.bufPairPool.Get().(*BufPair) -} - -func (df *dataLoaderFactory) freeBufPair(pair *BufPair) { - pair.Data.Reset() - pair.Errors.Reset() - df.bufPairPool.Put(pair) -} - -func (df *dataLoaderFactory) getMutex() *sync.Mutex { - return df.muPool.Get().(*sync.Mutex) -} - -func (df *dataLoaderFactory) freeMutex(mu *sync.Mutex) { - df.muPool.Put(mu) -} - -func newDataloaderFactory(fetcher *Fetcher) *dataLoaderFactory { - return &dataLoaderFactory{ - muPool: sync.Pool{ - New: func() interface{} { - return &sync.Mutex{} - }, - }, - waitGroupPool: sync.Pool{ - New: func() interface{} { - return &sync.WaitGroup{} - }, - }, - bufPairPool: sync.Pool{ - New: func() interface{} { - pair := BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - } - return &pair - }, - }, - bufPairSlicePool: sync.Pool{ - New: func() interface{} { - slice := make([]*BufPair, 0, 24) - return &slice - }, - }, - dataloaderPool: sync.Pool{ - New: func() interface{} { - return &dataLoader{ - fetches: make(map[int]fetchState), - inUseBufPair: make([]*BufPair, 0, 8), - } - }, - }, - fetcher: fetcher, - } -} - -// newDataLoader returns new instance of dataLoader. -// initialValue represents data from subscription, initialValue will be saved with initialValueID id and could be used -// for further fetches. -func (df *dataLoaderFactory) newDataLoader(initialValue []byte) *dataLoader { - dataloader := df.dataloaderPool.Get().(*dataLoader) - - dataloader.mu = df.getMutex() - dataloader.resourceProvider = df - dataloader.fetcher = df.fetcher - - if initialValue != nil { - - buf := dataloader.getResultBufPair() - buf.Data.WriteBytes(initialValue) - - dataloader.fetches[initialValueID] = &batchFetchState{ - nextIdx: 0, - fetchError: nil, - results: []*BufPair{buf}, - } - } - - return dataloader -} - -func (df *dataLoaderFactory) freeDataLoader(d *dataLoader) { - for _, pair := range d.inUseBufPair { - d.resourceProvider.freeBufPair(pair) - } - - d.resourceProvider.freeMutex(d.mu) - - d.inUseBufPair = d.inUseBufPair[:0] - d.fetches = nil -} - -// dataLoader -type dataLoader struct { - fetches map[int]fetchState - mu *sync.Mutex - fetcher *Fetcher - resourceProvider *dataLoaderFactory - - inUseBufPair []*BufPair -} - -// Load fetches concurrently data for all siblings. -func (d *dataLoader) Load(ctx *Context, fetch *SingleFetch, responsePair *BufPair) (err error) { - var fetchResult fetchState - var resultPair *BufPair - - fetchResult, ok := d.getFetchState(fetch.BufferId) - if ok { - resultPair, err = fetchResult.next(ctx) - copyBufPair(responsePair, resultPair) - return - } - - fetchResult = &batchFetchState{} - - parentResult, ok := d.getFetchState(ctx.lastFetchID) - - if !ok { // it must be root query without subscription data - buf := d.resourceProvider.getBufPair() - defer d.resourceProvider.freeBufPair(buf) - - if err := fetch.InputTemplate.Render(ctx, nil, buf.Data); err != nil { - return err - } - - pair := d.getResultBufPair() - err = d.fetcher.Fetch(ctx, fetch, buf.Data, pair) - fetchResult = &singleFetchState{ - fetchErrors: []error{err}, - results: []*BufPair{pair}, - } - - d.setFetchState(fetchResult, fetch.BufferId) - - resultPair, err = fetchResult.next(ctx) - copyBufPair(responsePair, resultPair) - return - } - - fetchParams, err := d.selectedDataForFetch(parentResult.data(), ctx.responseElements...) - if err != nil { - return err - } - - if fetchResult, err = d.resolveSingleFetch(ctx, fetch, fetchParams); err != nil { - return err - } - - d.setFetchState(fetchResult, fetch.BufferId) - - resultPair, err = fetchResult.next(ctx) - copyBufPair(responsePair, resultPair) - - return -} - -// LoadBatch builds and resolve batch request for all siblings. -func (d *dataLoader) LoadBatch(ctx *Context, batchFetch *BatchFetch, responsePair *BufPair) (err error) { - var fetchResult fetchState - var resultPair *BufPair - fetchResult, ok := d.getFetchState(batchFetch.Fetch.BufferId) - if ok { - resultPair, err = fetchResult.next(ctx) - copyBufPair(responsePair, resultPair) - return - } - - fetchResult = &batchFetchState{} - - parentResult, ok := d.getFetchState(ctx.lastFetchID) - if !ok { - return fmt.Errorf("has not got fetch for %d", ctx.lastFetchID) - } - - fetchParams, err := d.selectedDataForFetch(parentResult.data(), ctx.responseElements...) - if err != nil { - return err - } - - if fetchResult, err = d.resolveBatchFetch(ctx, batchFetch, fetchParams); err != nil { - return err - } - - d.setFetchState(fetchResult, batchFetch.Fetch.BufferId) - - resultPair, err = fetchResult.next(ctx) - copyBufPair(responsePair, resultPair) - return -} - -func (d *dataLoader) resolveBatchFetch(ctx *Context, batchFetch *BatchFetch, fetchParams [][]byte) (fetchState *batchFetchState, err error) { - inputBufs := make([]*fastbuffer.FastBuffer, 0, len(fetchParams)) - - bufSlice := d.resourceProvider.getBufPairSlicePool() - defer d.resourceProvider.freeBufPairSlice(bufSlice) - - for i := range fetchParams { - bufPair := d.resourceProvider.getBufPair() - *bufSlice = append(*bufSlice, bufPair) - if err := batchFetch.Fetch.InputTemplate.Render(ctx, fetchParams[i], bufPair.Data); err != nil { - return nil, err - } - - inputBufs = append(inputBufs, bufPair.Data) - } - - outBuf := d.resourceProvider.getBufPair() - *bufSlice = append(*bufSlice, outBuf) - - results := make([]*BufPair, len(inputBufs)) - for i := range inputBufs { - results[i] = d.getResultBufPair() - } - - fetchState = &batchFetchState{} - - if err = d.fetcher.FetchBatch(ctx, batchFetch, inputBufs, results); err != nil { - fetchState.fetchError = err - return fetchState, nil - } - - fetchState.results = results - - return fetchState, nil -} - -func (d *dataLoader) resolveSingleFetch(ctx *Context, fetch *SingleFetch, fetchParams [][]byte) (fetchState *singleFetchState, err error) { - wg := d.resourceProvider.getWaitGroup() - defer d.resourceProvider.freeWaitGroup(wg) - - wg.Add(len(fetchParams)) - - type fetchResult struct { - result *BufPair - err error - pos int - } - - resultCh := make(chan fetchResult, len(fetchParams)) - - bufSlice := d.resourceProvider.getBufPairSlicePool() - defer d.resourceProvider.freeBufPairSlice(bufSlice) - - for i, val := range fetchParams { - bufPair := d.resourceProvider.getBufPair() - *bufSlice = append(*bufSlice, bufPair) - if err := fetch.InputTemplate.Render(ctx, val, bufPair.Data); err != nil { - return nil, err - } - - pair := d.getResultBufPair() - - go func(pos int, pair *BufPair) { - err := d.fetcher.Fetch(ctx, fetch, bufPair.Data, pair) - resultCh <- fetchResult{result: pair, err: err, pos: pos} - wg.Done() - }(i, pair) - } - - go func() { - wg.Wait() - close(resultCh) - }() - - fetchState = &singleFetchState{ - fetchErrors: make([]error, len(fetchParams)), - results: make([]*BufPair, len(fetchParams)), - } - - for res := range resultCh { - fetchState.fetchErrors[res.pos] = res.err - fetchState.results[res.pos] = res.result - } - - return fetchState, err -} - -func (d *dataLoader) getFetchState(fetchID int) (batchState fetchState, ok bool) { - d.mu.Lock() - defer d.mu.Unlock() - - batchState, ok = d.fetches[fetchID] - return -} - -func (d *dataLoader) setFetchState(batchState fetchState, fetchID int) { - d.mu.Lock() - defer d.mu.Unlock() - - d.fetches[fetchID] = batchState -} - -func (d *dataLoader) selectedDataForFetch(input [][]byte, path ...string) ([][]byte, error) { - if len(path) == 0 { - return input, nil - } - - current, rest := path[0], path[1:] - - if current == arrayElementKey { - return flatMap(input, func(val []byte) ([][]byte, error) { - var vals [][]byte - _, err := jsonparser.ArrayEach(val, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - vals = append(vals, value) - }) - if err != nil { // In case if array is null - return nil, nil - } - - return d.selectedDataForFetch(vals, rest...) - }) - } - - temp := make([][]byte, 0, len(input)) - - for i := range input { - el, dataType, _, err := jsonparser.Get(input[i], current) - if dataType == jsonparser.NotExist { - // The input has an object that doesn't contain the path component. - // This can happen in the following situation. Consider the - // following query: - // - // { - // someArrayWithInterfaceItem { - // ... on A { - // aField { - // id - // fieldFromAnotherService # <- this is federated - // } - // } - // ... on B { - // someOtherField - // } - // } - // } - // - // The result after fetching someArrayWithInterfaceItem might be: - // { - // "data": { - // "someArrayWithInterfaceItem": [ - // {"__typename": "A", "aField": {"id": 1}}, - // {"__typename": "B", "someOtherField": "hello"}, - // {"__typename": "A", "aField": {"id": 2}} - // ] - // } - // - // When resolving the fieldFromAnotherService field, we should - // only look at the type "A" inputs, since those are the only - // objects the someArrayWithInterfaceItem fetch applies to. In - // other words, inputs without "aField" are skipped. - continue - } - if err != nil { - return nil, err - } - temp = append(temp, el) - } - - return d.selectedDataForFetch(temp, rest...) -} - -func (d *dataLoader) getResultBufPair() (pair *BufPair) { - d.mu.Lock() - defer d.mu.Unlock() - - pair = d.resourceProvider.bufPairPool.Get().(*BufPair) - d.inUseBufPair = append(d.inUseBufPair, pair) - - return -} - -type fetchState interface { - data() [][]byte - next(ctx *Context) (*BufPair, error) -} - -type batchFetchState struct { - nextIdx int - - fetchError error - results []*BufPair -} - -func (b *batchFetchState) data() [][]byte { - dataSlice := make([][]byte, len(b.results)) - - for i := range b.results { - if b.results[i] != nil && b.results[i].HasData() { - dataSlice[i] = b.results[i].Data.Bytes() - } - } - - return dataSlice -} - -// next works correctly only with synchronous resolve strategy -// In case of asynchronous resolve strategy it's required to compute response position based on values from ctx (current path) -// But there is no reason for asynchronous resolve strategy, it's not useful, as all IO operations (fetching data) is be done by dataloader -func (b *batchFetchState) next(ctx *Context) (*BufPair, error) { - if b.fetchError != nil { - return nil, b.fetchError - } - - res := b.results[b.nextIdx] - - b.nextIdx++ - - return res, nil -} - -type singleFetchState struct { - nextIdx int - - fetchErrors []error - results []*BufPair -} - -func (b *singleFetchState) data() [][]byte { - dataSlice := make([][]byte, len(b.results)) - - for i := range b.results { - if b.results[i] != nil && b.results[i].HasData() { - dataSlice[i] = b.results[i].Data.Bytes() - } - } - - return dataSlice -} - -// next works correctly only with synchronous resolve strategy -// In case of asynchronous resolve strategy it's required to compute response position based on values from ctx (current path) -// But there is no reason for asynchronous resolve strategy, it's not useful, as all IO operations (fetching data) is be done by dataloader -func (b *singleFetchState) next(ctx *Context) (*BufPair, error) { - if b.fetchErrors[b.nextIdx] != nil { - return nil, b.fetchErrors[b.nextIdx] - } - - res := b.results[b.nextIdx] - - b.nextIdx++ - - return res, nil -} - -func flatMap(input [][]byte, f func(val []byte) ([][]byte, error)) ([][]byte, error) { - var result [][]byte - - for i := range input { - mapRes, err := f(input[i]) - if err != nil { - return nil, err - } - - result = append(result, mapRes...) - } - - return result, nil -} - -func copyBufPair(to, from *BufPair) { - if to == nil || from == nil { - return - } - - to.Data.WriteBytes(from.Data.Bytes()) - to.Errors.WriteBytes(from.Errors.Bytes()) -} diff --git a/pkg/engine/resolve/dataloader.md b/pkg/engine/resolve/dataloader.md deleted file mode 100644 index 36a482ff3..000000000 --- a/pkg/engine/resolve/dataloader.md +++ /dev/null @@ -1,201 +0,0 @@ -# This document describes current batching solution - -## Why do we need dataLoader ? - -DataLoader provides solutions for next problems: - -### 1. Batching - -Batching highly decrease number of network request to data sources. - -Resolver tries to resolve array of Products ```[Product1, Product2, Product3]```: - -**Before:** - -_fetch 1:_ -```json - { - "method":"POST", - "url":"http://localhost:4003", - "body":{ - "query": "query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}", - "variables":{"representations":[{"upc":"top-1","__typename":"Product"}] - } - } -``` - -_fetch 2:_ -```json -{ - "method":"POST", - "url":"http://localhost:4003", - "body":{ - "query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}", - "variables":{"representations":[{"upc":"top-2","__typename":"Product"}]} - } -} -``` - -_fetch 3:_ -```json -{ - "method":"POST", - "url":"http://localhost:4003", - "body":{ - "query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}", - "variables":{"representations":[{"upc":"top-3","__typename":"Product"}]} - } -} -``` - -**After:** - -_fetch 1:_ -```json -{ - "method":"POST", - "url":"http://localhost:4003", - "body":{ - "query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}", - "variables":{ - "representations":[ - {"upc":"top-1","__typename":"Product"}, - {"upc":"top-2","__typename":"Product"}, - {"upc":"top-3","__typename":"Product"} - ] - } - } -} -``` - -### 2. Request deduplication - -It allows requesting data for only uniq arguments set - -Resolver tries to resolve array of Products ```[Product1, Product2, Product1, Product3, Product2]```: - -**Batch without deduplication:** - -_fetch:_ -```json -{ - "method":"POST", - "url":"http://localhost:4003", - "body":{ - "query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}", - "variables": { - "representations":[ - {"upc":"top-1","__typename":"Product"}, - {"upc":"top-2","__typename":"Product"}, - {"upc":"top-1","__typename":"Product"}, - {"upc":"top-3","__typename":"Product"}, - {"upc":"top-2","__typename":"Product"} - ] - } - } -} -``` - -**Batch with deduplication:** - -fetch: -```json -{ - "method":"POST", - "url":"http://localhost:4003", - "body":{ - "query": "query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}", - "variables": { - "representations":[ - {"upc":"top-1","__typename":"Product"}, - {"upc":"top-2","__typename":"Product"}, - {"upc":"top-3","__typename":"Product"} - ] - } - } -} -``` - -## How does dataLoader work ? - -- dataLoader is request scope object. For every new graphql request (or every new Subscription message) it's required to create a new dataloader. -- resolve.Context keeps dataLoader for current request. -- resolve.Context keeps last(parent) `lastFetchID` for current request -- resolve.Context keeps `responsePath`, it's an array of all object.Path/Array.Path since `lastFetchID`, - in case if node is Array additionally add to `responsePath` special symbol - `@` (e.g., [topProducts, @ ]) -- current dataLoader implementation is based on synchronous resolve strategy. -- when Resolver tries to resolve fetch (SingleFetch/BatchFetch) for `fetchID`, dataLoader resolves fetch with `fetchID` for all siblings. -- in case SingleFetch dataLoaders (Load) concurrently resolve fetch for all siblings -- in case BatchFetch dataLoaders (LoadBatch) creates batch request for resolving fetches for all siblings -- for creating fetch input dataLoader selects from `lastFetchID` response data by `responsePath` (it's an array of all object.Path/Array.Path since `lastFetchID`) - -**Example:** - -_Query :_ -``` -query { - topProducts { - reviews { - body - author { - username - } - } - } - } -``` - - - -``` - |topProducts| FetchID=0 - | - | - | - |---------------------------|Array of Products|--------------------| - | | | - | | | - |Product A| |Product B| |Product C| - | | | - | | | - |----------|Array of Reviews|--------| |Array of Reviews| |-----|Array of Reviews|-----| FetchID=1;LastFetchID=0;responsePath=[topProducts @] - | | | | | | - | | | | | | - |Review A1| |Review A2| |Review A3| |Review B1| |Review C1| |Review C2| - | | | | | | - | | | | | | - |Author 1| |Author 2| |Author 3| |Author 4| |Author 5| |Author 6| FetchID=2;LastFetchID=1;responsePath=[reviews @ author] - - -``` - - 1. creates dataLoader - 1. resolve `topProducts`, fetch with `FetchID=0` is required, return an array of products - * set `lastFetchID` as `0`, - * add `topProducts` to `responsePath` - * save response with FetchID `0` - 1. enters `Array of Products` node, add `@` to the `responsePath`, no need to fetch - 1. enters `Product A` node, no need to fetch - 1. enters `Array of Reviews` node, fetch with `FetchID`= 1 is required - * dataLoader gets response `{"topProducts": [{"upc": "top1", ...}, {"upc": "top2", ...}, {"upc": "top3", ...}]}` from `lastFetchID` (it has been saved in step 2) - and builds fetch input for all `Array of Reviews` siblings (`selectedDataForFetch` method is responsible for finding all siblings) - * resolve all fetches from previous step (when fetch is SingleFetch - send N concurrent requests, when fetch is BatchFetch - compose all fetches to single Batch), - Planner is responsible to choose which type of Fetch to use (e.g., for graphql datasource it makes sense to use BatchFetch for resolving Entity) - * save response with FetchID `1` - * reset `responsePath` and add `reviews` and `@` to `responsePath` (`responsePath` = `["reviews", "@"]`) - * set `lastFetchID` as `1` - 1. enters `Review A1` node, no need to fetch - * add `author` to `responsePath` (`responsePath` = `["reviews", "@", "author"]`) - 1. enters `Author A1` node, fetch with `FetchID`=2 is required (actually, it's the last step that leads to fetching) - * dataLoader gets response `[{"reviews":[{review A1}, {review A2}, {review A3}]}, {"reviews": [{review B1}]}, {"reviews": [{review C1}, {review C2}]` from `lastFetchID` (it has been saved in step 5) - and builds fetch input for all `Author 1` siblings - * resolve all fetches from previous step (when fetch is SingleFetch - send N concurrent requests, when fetch is BatchFetch - compose all fetches to single Batch) - * save response with FetchID `2` - * reset `responsePath` - * set `lastFetchID` as `2` - 1. enters `Review A2` nodes, no need to fetch - 1. enters `Author A2` node, fetch with `FetchID=2` is required - * dataLoader has already requested required data (it's saved with `FetchID=2`), it just gets second element from response for `FetchID=2` - - 1. enters second `Array of Reviews` node, fetch with `FetchID`= 1 is required - * dataLoader has already requested required data (it's saved with `FetchID=1`), it just gets second element from response for `FetchID=1` diff --git a/pkg/engine/resolve/dataloader_test.go b/pkg/engine/resolve/dataloader_test.go deleted file mode 100644 index 650404707..000000000 --- a/pkg/engine/resolve/dataloader_test.go +++ /dev/null @@ -1,682 +0,0 @@ -package resolve - -import ( - "bytes" - "context" - "errors" - "io" - "strings" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" -) - -func newBufPair(data string, err string) *BufPair { - bufPair := NewBufPair() - - if data != "" { - bufPair.Data.WriteString(data) - } - - if err != "" { - bufPair.Errors.WriteString(err) - } - - return bufPair -} - -func TestDataLoader_Load(t *testing.T) { - testFn := func(initialState map[int]fetchState, fn func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string)) func(t *testing.T) { - ctrl := gomock.NewController(t) - dlFactory := newDataloaderFactory(NewFetcher(false)) - dl := dlFactory.newDataLoader(nil) - if initialState != nil { - dl.fetches = initialState - } - - fetch, ctx, expectedOutput := fn(t, ctrl) - - return func(t *testing.T) { - t.Helper() - - bufPair := NewBufPair() - err := dl.Load(ctx, fetch, bufPair) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, bufPair.Data.String()) - ctrl.Finish() - } - } - - testFnErr := func(initialState map[int]fetchState, fn func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedErr string)) func(t *testing.T) { - ctrl := gomock.NewController(t) - dlFactory := newDataloaderFactory(NewFetcher(false)) - dl := dlFactory.newDataLoader(nil) - if initialState != nil { - dl.fetches = initialState - } - - fetch, ctx, expectedErr := fn(t, ctrl) - - return func(t *testing.T) { - t.Helper() - - bufPair := NewBufPair() - err := dl.Load(ctx, fetch, bufPair) - assert.EqualError(t, err, expectedErr) - ctrl.Finish() - } - } - - t.Run("root request", testFn(nil, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"me": {"id": "1234","username": "Me","__typename": "User"}}`) - return writeGraphqlResponse(pair, w, false) - }). - Return(nil) - - return &SingleFetch{ - BufferId: 0, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, &Context{ctx: context.Background()}, `{"data":{"me": {"id": "1234","username": "Me","__typename": "User"}}}` - })) - - t.Run("requires nested request", testFn(map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: nil, - results: []*BufPair{newBufPair(`{"someProp": {"id": 11}}`, ``), newBufPair(`{"someProp": {"id": 22}}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Times(2). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - switch { - case strings.Contains(actual, "11"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"userId":11}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":11, "username": "Username 11"}}`) - return writeGraphqlResponse(pair, w, false) - case strings.Contains(actual, "22"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"userId":22}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":22, "username": "Username 22"}}`) - return writeGraphqlResponse(pair, w, false) - } - - return errors.New("unexpected call") - }). - Return(nil) - - return &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"number"}`), - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, `{"data":{"user": {"id":11, "username": "Username 11"}}}` - })) - - t.Run("fetch error", func(t *testing.T) { - ctrl := gomock.NewController(t) - dlFactory := newDataloaderFactory(NewFetcher(false)) - dl := dlFactory.newDataLoader(nil) - dl.fetches = map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: nil, - results: []*BufPair{newBufPair(`{"someProp": {"id": 11}}`, ``), newBufPair(`{"someProp": {"id": 22}}`, ``)}, - }, - } - - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Times(2). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - switch { - case strings.Contains(actual, "11"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":11}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":11, "username": "Username 11"}}`) - return writeGraphqlResponse(pair, w, false) - case strings.Contains(actual, "22"): - return errors.New("failed to access http://localhost:4001") - } - - return errors.New("unexpected call") - }). - Return(nil) - - bufPair := NewBufPair() - err := dl.Load( - &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, - &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"number"}`), - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, - bufPair, - ) - - assert.NoError(t, err) - expectedFetchState := map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: nil, - results: []*BufPair{newBufPair(`{"someProp": {"id": 11}}`, ``), newBufPair(`{"someProp": {"id": 22}}`, ``)}, - }, - 2: &singleFetchState{ - nextIdx: 0, - fetchErrors: []error{nil, errors.New("failed to access http://localhost:4001")}, - results: []*BufPair{newBufPair(`{"user": {"id":11, "username": "Username 11"}}`, ``), newBufPair(``, ``)}, - }, - } - assert.NoError(t, expectedFetchState[2].(*singleFetchState).fetchErrors[0]) - assert.EqualError(t, expectedFetchState[2].(*singleFetchState).fetchErrors[1], "failed to access http://localhost:4001") - }) - - t.Run("fetch error in non-corresponding call", testFn(map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: make([]error, 2), - results: []*BufPair{newBufPair(`{"user": {"id":11, "username": "Username 11"}}`, ``), newBufPair(`{"user": {"id":22, "username": "Username 22"}}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - return &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: nil, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, `{"user": {"id":11, "username": "Username 11"}}` - })) - - t.Run("fetch errors in corresponding call", testFnErr(map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 1, - fetchErrors: []error{nil, errors.New("someError")}, - results: []*BufPair{newBufPair(`{"user": {"id":11, "username": "Username 11"}}`, ``), newBufPair(``, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - return &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: nil, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, `someError` - })) - - t.Run("doesn't requires nested request", testFn(map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 1, - fetchErrors: make([]error, 2), - results: []*BufPair{newBufPair(`{"user": {"id":11, "username": "Username 11"}}`, ``), newBufPair(`{"user": {"id":22, "username": "Username 22"}}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - return &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: nil, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, `{"user": {"id":22, "username": "Username 22"}}` - })) - - t.Run("requires nested request with array in path", testFn(map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: nil, - results: []*BufPair{newBufPair(`{"someProp": [{"id": 11}, {"id": 22}]}`, ``), newBufPair(`{"someProp": [{"id": 11}, {"id": 22}]}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Times(4). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - switch { - case strings.Contains(actual, "11"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":11}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":11, "username": "Username 11"}}`) - return writeGraphqlResponse(pair, w, false) - case strings.Contains(actual, "22"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":22}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":22, "username": "Username 22"}}`) - return writeGraphqlResponse(pair, w, false) - } - - return errors.New("unexpected call") - }). - Return(nil) - - return &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"number"}`), - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp", arrayElementKey}}, `{"data":{"user": {"id":11, "username": "Username 11"}}}` - })) - - t.Run("requires nested request with null array in path", testFn(map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: nil, - results: []*BufPair{newBufPair(`{"someProp": null}`, ``), newBufPair(`{"someProp": [{"id": 11}, {"id": 22}]}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *SingleFetch, ctx *Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Times(2). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - switch { - case strings.Contains(actual, "11"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":11}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":11, "username": "Username 11"}}`) - return writeGraphqlResponse(pair, w, false) - case strings.Contains(actual, "22"): - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":22}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"user": {"id":22, "username": "Username 22"}}`) - return writeGraphqlResponse(pair, w, false) - } - - return errors.New("unexpected call") - }). - Return(nil) - - return &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"query($userId: ID!){user(id: $userId){ id username }","variables":{"$userId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"number"}`), - }, - { - Data: []byte(`}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp", arrayElementKey}}, `{"data":{"user": {"id":11, "username": "Username 11"}}}` - })) -} - -func TestDataLoader_LoadBatch(t *testing.T) { - testFn := func(initialState map[int]fetchState, fn func(t *testing.T, ctrl *gomock.Controller) (fetch *BatchFetch, ctx *Context, expectedOutput string)) func(t *testing.T) { - ctrl := gomock.NewController(t) - dlFactory := newDataloaderFactory(NewFetcher(false)) - dl := dlFactory.newDataLoader(nil) - if initialState != nil { - dl.fetches = initialState - } - - fetch, ctx, expectedOutput := fn(t, ctrl) - - return func(t *testing.T) { - bufPair := NewBufPair() - err := dl.LoadBatch(ctx, fetch, bufPair) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, bufPair.Data.String()) - ctrl.Finish() - } - } - - t.Run("requires nested request", testFn(map[int]fetchState{ - 1: &batchFetchState{ - nextIdx: 0, - fetchError: nil, - results: []*BufPair{newBufPair(`{"someProp": {"upc": "top-1"}}`, ``), newBufPair(`{"someProp": {"upc": "top-2"}}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *BatchFetch, ctx *Context, expectedOutput string) { - batchFactory := NewMockDataSourceBatchFactory(ctrl) - batchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - []resultedBufPair{ - {data: `{"name": "Trilby"}`}, - {data: `{"name": "Fedora"}`}, - }), nil) - - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`[{"name": "Trilby"},{"name": "Fedora"}]`) - return writeGraphqlResponse(pair, w, false) - }). - Return(nil) - - return &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, - BatchFactory: batchFactory, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, `{"name": "Trilby"}` - })) - - t.Run("deeply nested fetch with varying fields", testFn(map[int]fetchState{ - 1: &batchFetchState{ - nextIdx: 0, - fetchError: nil, - // The fetch is to fill in additional engine information. - results: []*BufPair{ - newBufPair(`{"vehicle": {"__typename": "Car", "color": "black", "engine": {"model": "x"}}}`, ``), - newBufPair(`{"vehicle": {"__typename": "Bicycle", "color": "yellow"}}`, ``), - newBufPair(`{"vehicle": {"__typename": "Car", "color": "black", "engine": {"model": "y"}}}`, ``), - }, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *BatchFetch, ctx *Context, expectedOutput string) { - batchFactory := NewMockDataSourceBatchFactory(ctrl) - batchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Engine {horsepower}}}","variables":{"representations":[{"model":"x","__typename":"Engine"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Engine {horsepower}}}","variables":{"representations":[{"model":"y","__typename":"Engine"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Engine {horsepower}}}","variables":{"representations":[{"model":"x","__typename":"Engine"},{"model":"y","__typename":"Engine"}]}}}`, - []resultedBufPair{ - {data: `{"horsepower": 200}`}, - {data: `{"horsepower": 400}`}, - }), nil) - - carService := NewMockDataSource(ctrl) - carService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Engine {horsepower}}}","variables":{"representations":[{"model":"x","__typename":"Engine"},{"model":"y","__typename":"Engine"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`[{"horsepower": 200},{"horsepower": 400}]`) - return writeGraphqlResponse(pair, w, false) - }). - Return(nil) - - return &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Engine {horsepower}}}","variables":{"representations":[{"model":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"model"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"Engine"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: carService, - }, - BatchFactory: batchFactory, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"vehicle", "engine"}}, `{"horsepower": 200}` - })) - - t.Run("doesn't requires nested request", testFn(map[int]fetchState{ - 1: &batchFetchState{ - nextIdx: 1, - fetchError: nil, - results: []*BufPair{newBufPair(`{"user": {"id":11, "username": "Username 11"}}`, ``), newBufPair(`{"user": {"id":22, "username": "Username 22"}}`, ``)}, - }, - }, func(t *testing.T, ctrl *gomock.Controller) (fetch *BatchFetch, ctx *Context, expectedOutput string) { - return &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - }, - { - Data: []byte(`","__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - }, - }, &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, `{"user": {"id":22, "username": "Username 22"}}` - })) - - t.Run("fetch error", func(t *testing.T) { - ctrl := gomock.NewController(t) - dlFactory := newDataloaderFactory(NewFetcher(false)) - dl := dlFactory.newDataLoader(nil) - dl.fetches = map[int]fetchState{ - 1: &singleFetchState{ - nextIdx: 0, - fetchErrors: nil, - results: []*BufPair{newBufPair(`{"someProp": {"upc": "top-1"}}`, ``), newBufPair(`{"someProp": {"upc": "top-2"}}`, ``)}, - }, - } - - expErr := errors.New("failed to access http://localhost:4003") - - batchFactory := NewMockDataSourceBatchFactory(ctrl) - batchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - []resultedBufPair{}), nil) - - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - return - }). - Return(expErr) - - err := dl.LoadBatch( - &Context{ctx: context.Background(), lastFetchID: 1, responseElements: []string{"someProp"}}, - &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - }, - BatchFactory: batchFactory, - }, - NewBufPair(), - ) - - assert.EqualError(t, err, expErr.Error()) - }) -} diff --git a/pkg/engine/resolve/defer_test.go b/pkg/engine/resolve/defer_test.go deleted file mode 100644 index 9060cf9ea..000000000 --- a/pkg/engine/resolve/defer_test.go +++ /dev/null @@ -1,447 +0,0 @@ -//go:build !windows - -package resolve - -import ( - "bytes" - "context" - "fmt" - "io" - "os" - "testing" - - jsonpatch "github.com/evanphx/json-patch/v5" - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestWithoutDefer(t *testing.T) { - - controller := gomock.NewController(t) - - userService := fakeService(t, controller, "user", "./testdata/users.json", - "") - postsService := fakeService(t, controller, "posts", "./testdata/posts.json", - "1", "2", - ) - - res := &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Item: &Object{ - Fetch: &SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewGraphQLVariableRenderer(`{"type":"number"}`), - }, - }, - }, - }, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("title"), - Value: &String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - ctx := NewContext(context.Background()) - - buf := &bytes.Buffer{} - - err := resolver.ResolveGraphQLResponse(ctx, res, nil, buf) - assert.NoError(t, err) - - expectedBytes, err := os.ReadFile("./testdata/response_without_defer.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expectedBytes), buf.String()) - if t.Failed() { - fmt.Println(buf.String()) - } -} - -func TestJsonPatch(t *testing.T) { - initialResponse, err := os.ReadFile("./testdata/defer_1.json") - assert.NoError(t, err) - patch1, err := os.ReadFile("./testdata/defer_2.json") - assert.NoError(t, err) - patch2, err := os.ReadFile("./testdata/defer_3.json") - assert.NoError(t, err) - - p1, err := jsonpatch.DecodePatch(patch1) - assert.NoError(t, err) - - p2, err := jsonpatch.DecodePatch(patch2) - assert.NoError(t, err) - - patched, err := p1.Apply(initialResponse) - assert.NoError(t, err) - - patched, err = p2.Apply(patched) - assert.NoError(t, err) - - expectedBytes, err := os.ReadFile("./testdata/response_without_defer.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expectedBytes), string(patched)) - if t.Failed() { - fmt.Println(string(patched)) - } -} - -type TestWriter struct { - flushed []string - buf bytes.Buffer -} - -func (t *TestWriter) Write(p []byte) (n int, err error) { - return t.buf.Write(p) -} - -func (t *TestWriter) Flush() { - t.flushed = append(t.flushed, t.buf.String()) - t.buf.Reset() -} - -func TestDefer(t *testing.T) { - - controller := gomock.NewController(t) - - userService := fakeService(t, controller, "user", "./testdata/users.json", - "") - postsService := fakeService(t, controller, "posts", "./testdata/posts.json", - "1", "2", - ) - - res := &GraphQLStreamingResponse{ - InitialResponse: &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("posts"), - Value: &Null{ - Defer: Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Fetch: &SingleFetch{ - DataSource: postsService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewGraphQLVariableRenderer(`{"type":"number"}`), - }, - }, - }, - }, - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("title"), - Value: &String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - ctx := NewContext(context.Background()) - - writer := &TestWriter{} - - err := resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - assert.NoError(t, err) - assert.Equal(t, 3, len(writer.flushed)) - - expectedBytes, err := os.ReadFile("./testdata/defer_1.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expectedBytes), writer.flushed[0]) - if t.Failed() { - fmt.Println(writer.flushed[0]) - } - - expectedBytes, err = os.ReadFile("./testdata/defer_2.json") - require.NoError(t, err) - assert.JSONEq(t, string(expectedBytes), writer.flushed[1]) - if t.Failed() { - fmt.Println(writer.flushed[1]) - } - - expectedBytes, err = os.ReadFile("./testdata/defer_3.json") - require.NoError(t, err) - assert.JSONEq(t, string(expectedBytes), writer.flushed[2]) - if t.Failed() { - fmt.Println(writer.flushed[2]) - } -} - -type DiscardFlushWriter struct { -} - -func (d *DiscardFlushWriter) Write(p []byte) (n int, err error) { - return -} - -func (d *DiscardFlushWriter) Flush() { - -} - -func BenchmarkDefer(b *testing.B) { - - userData, err := os.ReadFile("./testdata/users.json") - assert.NoError(b, err) - postsData, err := os.ReadFile("./testdata/posts.json") - assert.NoError(b, err) - - userService := FakeDataSource(string(userData)) - postsService := FakeDataSource(string(postsData)) - - res := &GraphQLStreamingResponse{ - InitialResponse: &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("posts"), - Value: &Null{ - Defer: Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Fetch: &SingleFetch{ - DataSource: postsService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewGraphQLVariableRenderer(`{"type":"number"}`), - }, - }, - }, - }, - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("title"), - Value: &String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - bgCtx := context.Background() - ctx := NewContext(bgCtx) - - writer := &DiscardFlushWriter{} - // writer := &TestFlushWriter{} - - expect1, err := os.ReadFile("./testdata/defer_1.json") - assert.NoError(b, err) - expect2, err := os.ReadFile("./testdata/defer_2.json") - assert.NoError(b, err) - expect3, err := os.ReadFile("./testdata/defer_3.json") - assert.NoError(b, err) - - _, _, _ = expect1, expect2, expect3 - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - /*err = resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - assert.NoError(b,err) - assert.Equal(b,3,len(writer.flushed)) - assert.JSONEq(b,string(expect1),writer.flushed[0]) - assert.JSONEq(b,string(expect2),writer.flushed[1]) - assert.JSONEq(b,string(expect3),writer.flushed[2])*/ - - _ = resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - - ctx.Free() - ctx.ctx = bgCtx - // writer.flushed = writer.flushed[:0] - } -} - -func fakeService(t *testing.T, controller *gomock.Controller, serviceName, responseFilePath string, expectedInput ...string) DataSource { - data, err := os.ReadFile(responseFilePath) - assert.NoError(t, err) - service := NewMockDataSource(controller) - for i := 0; i < len(expectedInput); i++ { - i := i - service.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - assert.Equal(t, expectedInput[i], string(input)) - _, err = w.Write(data) - return - }) - } - return service -} diff --git a/pkg/engine/resolve/engine.md b/pkg/engine/resolve/engine.md deleted file mode 100644 index 728968b66..000000000 --- a/pkg/engine/resolve/engine.md +++ /dev/null @@ -1,63 +0,0 @@ -# this document outlines the architecture for the GraphQL Engine - -## requirements - -- have multiple data sources to resolve an object (e.g. pass an ID to two functions and merge the result, similar to map reduce) -- resolves @defer: splits query into multiple serially executable statements, each emitting a response object to the client -- resolves @stream: splits query at the @stream directive to stream a list of objects to the client -- resolves __type & __schema queries -- injects variables correctly into GraphQL sub queries in case multiple GraphQL queries will be assembled -- can map from data source response objects to correct GraphQL object structure -- can map between upstream GraphQL Enums and downstream GraphQL Enums -- can filter results from upstream data source based on custom plugin/middleware or predefined rules -- resolves child data sources inside an array concurrently -- can pass custom configuration to individual data sources, e.g. setting Headers for HTTP based data sources -- can pass request data from the downstream client to an upstream server (e.g. Headers) -- can have static data sources -- can have streaming data sources, e.g. RabbitMQ, Kafka, NATS -- can have GraphQL and non GraphQL data sources nested into each other -- can have multiple root level fields attached to the same data source -- returns an internal error in case the error is not recoverable -- returns an external error to tell the user about the error -- might return both an internal as well as an external error -- there should be triggers which are similar to data sources in that they trigger a subscription but don't resolve it themselves, instead they hand over the resolving to a data source (this is useful e.g. when you want to trigger a subscription from mutations but the mutations don't contain the data to resolve the subscription so from the trigger a query needs to be fired to resolve the subscription) -- for subscriptions with a trigger there should be an idempotent mechanism (configurable) to ensure that each trigger only fires one event in case that's the desired behaviour (e.g. polling an upstream but only emit changes) -- object path selector for arguments should make use of existing mappings (planning) -- can skip data source invocation based on conditions (e.g. missing field on parent object) -- return number of nodes in response - -## implemented in execution - -- resolves operations containing unions & interfaces -- resolves flat queries/mutations -- can define __typename for individual objects returned by data sources (users should be able to set the __typename using a middleware/plugin or predefined rules) - -## implemented in planning - -query: -resolve() -> client - -subscription: -for { - resolve() -> client -} - -stream: -resolveUser() -> client -for i := range user.friends { - resolveFriend(i) -> client - resolvePet(friend) -> client -} - - -```go -package resolving -type Resolver interface { - Resolve(ctx context.Context,userID string, config, input []byte) (output []byte, err error) -} -``` - -QueryPlan: - ResolveOneUser() - ResolveUserFriends() - ResolveManyPets() \ No newline at end of file diff --git a/pkg/engine/resolve/fetcher.go b/pkg/engine/resolve/fetcher.go deleted file mode 100644 index 8f71b0df3..000000000 --- a/pkg/engine/resolve/fetcher.go +++ /dev/null @@ -1,196 +0,0 @@ -package resolve - -import ( - "hash" - "sync" - - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" - "github.com/wundergraph/graphql-go-tools/pkg/pool" -) - -type Fetcher struct { - EnableSingleFlightLoader bool - hash64Pool sync.Pool - inflightFetchPool sync.Pool - bufPairPool sync.Pool - inflightFetchMu *sync.Mutex - inflightFetches map[uint64]*inflightFetch -} - -func NewFetcher(enableSingleFlightLoader bool) *Fetcher { - return &Fetcher{ - EnableSingleFlightLoader: enableSingleFlightLoader, - hash64Pool: sync.Pool{ - New: func() interface{} { - return xxhash.New() - }, - }, - inflightFetchPool: sync.Pool{ - New: func() interface{} { - return &inflightFetch{ - bufPair: BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - }, - } - }, - }, - bufPairPool: sync.Pool{ - New: func() interface{} { - return NewBufPair() - }, - }, - inflightFetchMu: &sync.Mutex{}, - inflightFetches: map[uint64]*inflightFetch{}, - } -} - -func (f *Fetcher) Fetch(ctx *Context, fetch *SingleFetch, preparedInput *fastbuffer.FastBuffer, buf *BufPair) (err error) { - dataBuf := pool.BytesBuffer.Get() - defer pool.BytesBuffer.Put(dataBuf) - - if ctx.beforeFetchHook != nil { - ctx.beforeFetchHook.OnBeforeFetch(f.hookCtx(ctx), preparedInput.Bytes()) - } - - if !f.EnableSingleFlightLoader || fetch.DisallowSingleFlight { - err = fetch.DataSource.Load(ctx.Context(), preparedInput.Bytes(), dataBuf) - extractResponse(dataBuf.Bytes(), buf, fetch.ProcessResponseConfig) - - if ctx.afterFetchHook != nil { - if buf.HasData() { - ctx.afterFetchHook.OnData(f.hookCtx(ctx), buf.Data.Bytes(), false) - } - if buf.HasErrors() { - ctx.afterFetchHook.OnError(f.hookCtx(ctx), buf.Errors.Bytes(), false) - } - } - return - } - - hash64 := f.getHash64() - _, _ = hash64.Write(preparedInput.Bytes()) - fetchID := hash64.Sum64() - f.putHash64(hash64) - - f.inflightFetchMu.Lock() - inflight, ok := f.inflightFetches[fetchID] - if ok { - inflight.waitFree.Add(1) - defer inflight.waitFree.Done() - f.inflightFetchMu.Unlock() - inflight.waitLoad.Wait() - if inflight.bufPair.HasData() { - if ctx.afterFetchHook != nil { - ctx.afterFetchHook.OnData(f.hookCtx(ctx), inflight.bufPair.Data.Bytes(), true) - } - buf.Data.WriteBytes(inflight.bufPair.Data.Bytes()) - } - if inflight.bufPair.HasErrors() { - if ctx.afterFetchHook != nil { - ctx.afterFetchHook.OnError(f.hookCtx(ctx), inflight.bufPair.Errors.Bytes(), true) - } - buf.Errors.WriteBytes(inflight.bufPair.Errors.Bytes()) - } - return inflight.err - } - - inflight = f.getInflightFetch() - inflight.waitLoad.Add(1) - f.inflightFetches[fetchID] = inflight - - f.inflightFetchMu.Unlock() - - err = fetch.DataSource.Load(ctx.Context(), preparedInput.Bytes(), dataBuf) - extractResponse(dataBuf.Bytes(), &inflight.bufPair, fetch.ProcessResponseConfig) - inflight.err = err - - if inflight.bufPair.HasData() { - if ctx.afterFetchHook != nil { - ctx.afterFetchHook.OnData(f.hookCtx(ctx), inflight.bufPair.Data.Bytes(), false) - } - buf.Data.WriteBytes(inflight.bufPair.Data.Bytes()) - } - - if inflight.bufPair.HasErrors() { - if ctx.afterFetchHook != nil { - ctx.afterFetchHook.OnError(f.hookCtx(ctx), inflight.bufPair.Errors.Bytes(), true) - } - buf.Errors.WriteBytes(inflight.bufPair.Errors.Bytes()) - } - - inflight.waitLoad.Done() - - f.inflightFetchMu.Lock() - delete(f.inflightFetches, fetchID) - f.inflightFetchMu.Unlock() - - go func() { - inflight.waitFree.Wait() - f.freeInflightFetch(inflight) - }() - - return -} - -func (f *Fetcher) FetchBatch(ctx *Context, fetch *BatchFetch, preparedInputs []*fastbuffer.FastBuffer, bufs []*BufPair) (err error) { - inputs := make([][]byte, len(preparedInputs)) - for i := range preparedInputs { - inputs[i] = preparedInputs[i].Bytes() - } - - batch, err := fetch.BatchFactory.CreateBatch(inputs) - if err != nil { - return err - } - - buf := f.getBufPair() - defer f.freeBufPair(buf) - - if err = f.Fetch(ctx, fetch.Fetch, batch.Input(), buf); err != nil { - return err - } - - if err = batch.Demultiplex(buf, bufs); err != nil { - return err - } - - return -} - -func (f *Fetcher) getBufPair() *BufPair { - return f.bufPairPool.Get().(*BufPair) -} - -func (f *Fetcher) freeBufPair(buf *BufPair) { - buf.Reset() - f.bufPairPool.Put(buf) -} - -func (f *Fetcher) getInflightFetch() *inflightFetch { - return f.inflightFetchPool.Get().(*inflightFetch) -} - -func (f *Fetcher) freeInflightFetch(inflightFetch *inflightFetch) { - inflightFetch.bufPair.Data.Reset() - inflightFetch.bufPair.Errors.Reset() - inflightFetch.err = nil - f.inflightFetchPool.Put(inflightFetch) -} - -func (f *Fetcher) hookCtx(ctx *Context) HookContext { - return HookContext{ - CurrentPath: ctx.path(), - } -} - -func (f *Fetcher) getHash64() hash.Hash64 { - return f.hash64Pool.Get().(hash.Hash64) -} - -func (f *Fetcher) putHash64(h hash.Hash64) { - h.Reset() - f.hash64Pool.Put(h) -} diff --git a/pkg/engine/resolve/inputtemplate.go b/pkg/engine/resolve/inputtemplate.go deleted file mode 100644 index 8bd5789f0..000000000 --- a/pkg/engine/resolve/inputtemplate.go +++ /dev/null @@ -1,144 +0,0 @@ -package resolve - -import ( - "context" - "errors" - "fmt" - - "github.com/buger/jsonparser" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type SegmentType int - -const ( - StaticSegmentType SegmentType = iota + 1 - VariableSegmentType -) - -type TemplateSegment struct { - SegmentType SegmentType - Data []byte - VariableKind VariableKind - VariableSourcePath []string - Renderer VariableRenderer -} - -type InputTemplate struct { - Segments []TemplateSegment - // SetTemplateOutputToNullOnVariableNull will safely return "null" if one of the template variables renders to null - // This is the case, e.g. when using batching and one sibling is null, resulting in a null value for one batch item - // Returning null in this case tells the batch implementation to skip this item - SetTemplateOutputToNullOnVariableNull bool -} - -var setTemplateOutputNull = errors.New("set to null") - -func (i *InputTemplate) Render(ctx *Context, data []byte, preparedInput *fastbuffer.FastBuffer) error { - var undefinedVariables []string - - for _, segment := range i.Segments { - var err error - switch segment.SegmentType { - case StaticSegmentType: - preparedInput.WriteBytes(segment.Data) - case VariableSegmentType: - switch segment.VariableKind { - case ObjectVariableKind: - err = i.renderObjectVariable(ctx.Context(), data, segment, preparedInput) - case ContextVariableKind: - var undefined bool - undefined, err = i.renderContextVariable(ctx, segment, preparedInput) - if undefined { - undefinedVariables = append(undefinedVariables, segment.VariableSourcePath[0]) - } - case HeaderVariableKind: - err = i.renderHeaderVariable(ctx, segment.VariableSourcePath, preparedInput) - default: - err = fmt.Errorf("InputTemplate.Render: cannot resolve variable of kind: %d", segment.VariableKind) - } - if err != nil { - if errors.Is(err, setTemplateOutputNull) { - preparedInput.Reset() - preparedInput.WriteBytes(literal.NULL) - return nil - } - return err - } - } - } - - if len(undefinedVariables) > 0 { - output := httpclient.SetUndefinedVariables(preparedInput.Bytes(), undefinedVariables) - // The returned slice might be different, we need to copy back the data - preparedInput.Reset() - preparedInput.WriteBytes(output) - } - return nil -} - -func (i *InputTemplate) renderObjectVariable(ctx context.Context, variables []byte, segment TemplateSegment, preparedInput *fastbuffer.FastBuffer) error { - value, valueType, offset, err := jsonparser.Get(variables, segment.VariableSourcePath...) - if err != nil || valueType == jsonparser.Null { - if i.SetTemplateOutputToNullOnVariableNull { - return setTemplateOutputNull - } - preparedInput.WriteBytes(literal.NULL) - return nil - } - if valueType == jsonparser.String { - value = variables[offset-len(value)-2 : offset] - switch segment.Renderer.GetKind() { - case VariableRendererKindPlain, VariableRendererKindPlanWithValidation: - if plainRenderer, ok := (segment.Renderer).(*PlainVariableRenderer); ok { - plainRenderer.rootValueType.Value = valueType - } - } - } - return segment.Renderer.RenderVariable(ctx, value, preparedInput) -} - -func (i *InputTemplate) renderContextVariable(ctx *Context, segment TemplateSegment, preparedInput *fastbuffer.FastBuffer) (variableWasUndefined bool, err error) { - value, valueType, offset, err := jsonparser.Get(ctx.Variables, segment.VariableSourcePath...) - if err != nil || valueType == jsonparser.Null { - if err == jsonparser.KeyPathNotFoundError { - preparedInput.WriteBytes(literal.NULL) - return true, nil - } - return false, segment.Renderer.RenderVariable(ctx.Context(), value, preparedInput) - } - if valueType == jsonparser.String { - value = ctx.Variables[offset-len(value)-2 : offset] - switch segment.Renderer.GetKind() { - case VariableRendererKindPlain, VariableRendererKindPlanWithValidation: - if plainRenderer, ok := (segment.Renderer).(*PlainVariableRenderer); ok { - plainRenderer.rootValueType.Value = valueType - } - } - } - return false, segment.Renderer.RenderVariable(ctx.Context(), value, preparedInput) -} - -func (i *InputTemplate) renderHeaderVariable(ctx *Context, path []string, preparedInput *fastbuffer.FastBuffer) error { - if len(path) != 1 { - return errHeaderPathInvalid - } - value := ctx.Request.Header.Values(path[0]) - if len(value) == 0 { - return nil - } - if len(value) == 1 { - preparedInput.WriteString(value[0]) - return nil - } - for j := range value { - if j != 0 { - preparedInput.WriteBytes(literal.COMMA) - } - preparedInput.WriteString(value[j]) - } - return nil -} diff --git a/pkg/engine/resolve/inputtemplate_test.go b/pkg/engine/resolve/inputtemplate_test.go deleted file mode 100644 index 1992d374e..000000000 --- a/pkg/engine/resolve/inputtemplate_test.go +++ /dev/null @@ -1,413 +0,0 @@ -package resolve - -import ( - "context" - "net/http" - "testing" - - "github.com/buger/jsonparser" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" -) - -func TestInputTemplate_Render(t *testing.T) { - runTest := func(t *testing.T, initRenderer initTestVariableRenderer, variables string, sourcePath []string, jsonSchema string, expectErr bool, expected string) { - t.Helper() - - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: sourcePath, - Renderer: initRenderer(jsonSchema), - }, - }, - } - ctx := &Context{ - Variables: []byte(variables), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - if expectErr { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - out := buf.String() - assert.Equal(t, expected, out) - } - - t.Run("plain renderer", func(t *testing.T) { - renderer := useTestPlainVariableRenderer() - t.Run("string scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":"bar"}`, []string{"foo"}, `{"type":"string"}`, false, `bar`) - }) - t.Run("boolean scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":true}`, []string{"foo"}, `{"type":"boolean"}`, false, "true") - }) - t.Run("nested string", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":"value"}}`, []string{"foo", "bar"}, `{"type":"string"}`, false, `value`) - }) - t.Run("json object pass through", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":"baz"}}`, []string{"foo"}, `{"type":"object","properties":{"bar":{"type":"string"}}}`, false, `{"bar":"baz"}`) - }) - t.Run("json object as graphql object", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":"baz"}}`, []string{"foo"}, `{"type":"object","properties":{"bar":{"type":"string"}}}`, false, `{"bar":"baz"}`) - }) - t.Run("json object as graphql object with null on required type", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":["string"]}`, true, ``) - }) - t.Run("json object as graphql object with null", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":["string","null"]}`, false, `null`) - }) - t.Run("json object as graphql object with number", func(t *testing.T) { - runTest(t, renderer, `{"foo":123}`, []string{"foo"}, `{"type":"integer"}`, false, `123`) - }) - t.Run("json object as graphql object with invalid number", func(t *testing.T) { - runTest(t, renderer, `{"foo":123}`, []string{"foo"}, `{"type":"string"}`, true, "") - }) - t.Run("json object as graphql object with boolean", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":true}}`, []string{"foo"}, `{"type":"object","properties":{"bar":{"type":"boolean"}}}`, false, `{"bar":true}`) - }) - t.Run("json object as graphql object with number", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":123}}`, []string{"foo"}, `{"type":"object","properties":{"bar":{"type":"integer"}}}`, false, `{"bar":123}`) - }) - t.Run("json object as graphql object with float", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":1.23}}`, []string{"foo"}, `{"type":"object","properties":{"bar":{"type":"number"}}}`, false, `{"bar":1.23}`) - }) - t.Run("json object as graphql object with nesting", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":{"baz":"bat"}}}`, []string{"foo"}, `{"type":"object","properties":{"bar":{"type":"object","properties":{"baz":{"type":"string"}}}}}`, false, `{"bar":{"baz":"bat"}}`) - }) - t.Run("json object as graphql object with single array", func(t *testing.T) { - runTest(t, renderer, `{"foo":["bar"]}`, []string{"foo"}, `{"type":"array","item":{"type":"string"}}`, false, `["bar"]`) - }) - t.Run("json object as graphql object with array", func(t *testing.T) { - runTest(t, renderer, `{"foo":["bar","baz"]}`, []string{"foo"}, `{"type":"array","item":{"type":"string"}}`, false, `["bar","baz"]`) - }) - t.Run("json object as graphql object with object array", func(t *testing.T) { - runTest(t, renderer, `{"foo":[{"bar":"baz"},{"bar":"bat"}]}`, []string{"foo"}, `{"type":"array","item":{"type":"object","properties":{"bar":{"type":"string"}}}}`, false, `[{"bar":"baz"},{"bar":"bat"}]`) - }) - }) - - t.Run("json renderer", func(t *testing.T) { - renderer := useTestJSONVariableRenderer() - t.Run("string scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":"bar"}`, []string{"foo"}, `{"type":"string"}`, false, `"bar"`) - }) - t.Run("boolean scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":true}`, []string{"foo"}, `{"type":"boolean"}`, false, "true") - }) - t.Run("number scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":1}`, []string{"foo"}, `{"type":"number"}`, false, "1") - }) - t.Run("nested string", func(t *testing.T) { - runTest(t, renderer, `{"foo":{"bar":"value"}}`, []string{"foo", "bar"}, `{"type":"string"}`, false, `"value"`) - }) - t.Run("on required scalars", func(t *testing.T) { - t.Run("error on required string scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":"string"}`, true, ``) - }) - t.Run("error on required int scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":"integer"}`, true, ``) - }) - t.Run("error on required float scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":"number"}`, true, ``) - }) - t.Run("error on required boolean scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":"boolean"}`, true, ``) - }) - }) - t.Run("on non-required scalars", func(t *testing.T) { - t.Run("null on non-required string scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":["string","null"]}`, false, `null`) - }) - t.Run("null on non-required int scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":["integer","null"]}`, false, `null`) - }) - t.Run("null on non-required float scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":["number","null"]}`, false, `null`) - }) - t.Run("null on non-required boolean scalar", func(t *testing.T) { - runTest(t, renderer, `{"foo":null}`, []string{"foo"}, `{"type":["boolean","null"]}`, false, `null`) - }) - }) - }) - - t.Run("array with csv render string", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"a"}, - Renderer: NewCSVVariableRenderer(JsonRootType{Value: jsonparser.String, Kind: JsonRootTypeKindSingle}), - }, - }, - } - ctx := &Context{ - Variables: []byte(`{"a":["foo","bar"]}`), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, "foo,bar", out) - }) - t.Run("array with csv render int", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"a"}, - Renderer: NewCSVVariableRenderer(JsonRootType{Value: jsonparser.Number}), - }, - }, - } - ctx := &Context{ - Variables: []byte(`{"a":[1,2,3]}`), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, "1,2,3", out) - }) - t.Run("array with default render int", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"a"}, - Renderer: NewGraphQLVariableRenderer(`{"type":"array","items":{"type":"number"}}`), - }, - }, - } - ctx := &Context{ - Variables: []byte(`{"a":[1,2,3]}`), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, "[1,2,3]", out) - }) - - t.Run("header variable", func(t *testing.T) { - t.Run("missing value for header variable - results into empty segment", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":"`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: HeaderVariableKind, - VariableSourcePath: []string{"Auth"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`"}`), - }, - }, - } - ctx := &Context{ - Variables: []byte(""), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `{"key":""}`, out) - }) - - t.Run("renders single value", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":"`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: HeaderVariableKind, - VariableSourcePath: []string{"Auth"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`"}`), - }, - }, - } - ctx := &Context{ - Variables: []byte(""), - Request: Request{ - Header: http.Header{"Auth": []string{"value"}}, - }, - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `{"key":"value"}`, out) - }) - - t.Run("renders multi value", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":"`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: HeaderVariableKind, - VariableSourcePath: []string{"Auth"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`"}`), - }, - }, - } - ctx := &Context{ - Variables: []byte(""), - Request: Request{ - Header: http.Header{"Auth": []string{"value1", "value2"}}, - }, - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `{"key":"value1,value2"}`, out) - }) - }) - - t.Run("JSONVariableRenderer", func(t *testing.T) { - t.Run("missing value for context variable - renders segment to null", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"a"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}`), - }, - }, - } - ctx := &Context{ - ctx: context.Background(), - Variables: []byte(""), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `{"undefined":["a"],"key":null}`, out) - }) - - t.Run("when SetTemplateOutputToNullOnVariableNull: true", func(t *testing.T) { - t.Run("null value for object variable - renders whole template as null", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}`), - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - } - ctx := &Context{ - Variables: []byte(""), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `null`, out) - }) - - t.Run("null value for context variable - renders segment as null", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"x"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":["string","null"]}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}`), - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - } - ctx := &Context{ - Variables: []byte(`{"x":null}`), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `{"key":null}`, out) - }) - - t.Run("missing value for header variable - results into empty segment", func(t *testing.T) { - template := InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"key":"`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: HeaderVariableKind, - VariableSourcePath: []string{"Auth"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`"}`), - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - } - ctx := &Context{ - Variables: []byte(""), - } - buf := fastbuffer.New() - err := template.Render(ctx, nil, buf) - assert.NoError(t, err) - out := buf.String() - assert.Equal(t, `{"key":""}`, out) - }) - }) - }) -} diff --git a/pkg/engine/resolve/resolve.go b/pkg/engine/resolve/resolve.go deleted file mode 100644 index f6b93a08a..000000000 --- a/pkg/engine/resolve/resolve.go +++ /dev/null @@ -1,1843 +0,0 @@ -//go:generate mockgen --build_flags=--mod=mod -self_package=github.com/wundergraph/graphql-go-tools/pkg/engine/resolve -destination=resolve_mock_test.go -package=resolve . DataSource,BeforeFetchHook,AfterFetchHook,DataSourceBatch,DataSourceBatchFactory - -package resolve - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "net/http" - "strconv" - "sync" - "time" - - "github.com/buger/jsonparser" - "github.com/cespare/xxhash/v2" - "github.com/tidwall/gjson" - - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/pool" -) - -var ( - lBrace = []byte("{") - rBrace = []byte("}") - lBrack = []byte("[") - rBrack = []byte("]") - comma = []byte(",") - colon = []byte(":") - quote = []byte("\"") - quotedComma = []byte(`","`) - null = []byte("null") - literalData = []byte("data") - literalErrors = []byte("errors") - literalMessage = []byte("message") - literalLocations = []byte("locations") - literalLine = []byte("line") - literalColumn = []byte("column") - literalPath = []byte("path") - literalExtensions = []byte("extensions") - - unableToResolveMsg = []byte("unable to resolve") - emptyArray = []byte("[]") -) - -var ( - errNonNullableFieldValueIsNull = errors.New("non Nullable field value is null") - errTypeNameSkipped = errors.New("skipped because of __typename condition") - errHeaderPathInvalid = errors.New("invalid header path: header variables must be of this format: .request.header.{{ key }} ") - - ErrUnableToResolve = errors.New("unable to resolve operation") -) - -var ( - responsePaths = [][]string{ - {"errors"}, - {"data"}, - } - errorPaths = [][]string{ - {"message"}, - {"locations"}, - {"path"}, - {"extensions"}, - } - entitiesPath = []string{"_entities"} -) - -const ( - rootErrorsPathIndex = 0 - rootDataPathIndex = 1 - - errorsMessagePathIndex = 0 - errorsLocationsPathIndex = 1 - errorsPathPathIndex = 2 - errorsExtensionsPathIndex = 3 -) - -type Node interface { - NodeKind() NodeKind -} - -type NodeKind int -type FetchKind int - -const ( - NodeKindObject NodeKind = iota + 1 - NodeKindEmptyObject - NodeKindArray - NodeKindEmptyArray - NodeKindNull - NodeKindString - NodeKindBoolean - NodeKindInteger - NodeKindFloat - NodeKindBigInt - NodeKindCustom - - FetchKindSingle FetchKind = iota + 1 - FetchKindParallel - FetchKindBatch -) - -type HookContext struct { - CurrentPath []byte -} - -type BeforeFetchHook interface { - OnBeforeFetch(ctx HookContext, input []byte) -} - -type AfterFetchHook interface { - OnData(ctx HookContext, output []byte, singleFlight bool) - OnError(ctx HookContext, output []byte, singleFlight bool) -} - -type Context struct { - ctx context.Context - Variables []byte - Request Request - pathElements [][]byte - responseElements []string - lastFetchID int - patches []patch - usedBuffers []*bytes.Buffer - currentPatch int - maxPatch int - pathPrefix []byte - dataLoader *dataLoader - beforeFetchHook BeforeFetchHook - afterFetchHook AfterFetchHook - position Position - RenameTypeNames []RenameTypeName -} - -type Request struct { - Header http.Header -} - -func NewContext(ctx context.Context) *Context { - if ctx == nil { - panic("nil context.Context") - } - return &Context{ - ctx: ctx, - Variables: make([]byte, 0, 4096), - pathPrefix: make([]byte, 0, 4096), - pathElements: make([][]byte, 0, 16), - patches: make([]patch, 0, 48), - usedBuffers: make([]*bytes.Buffer, 0, 48), - currentPatch: -1, - maxPatch: -1, - position: Position{}, - dataLoader: nil, - } -} - -func (c *Context) Context() context.Context { - return c.ctx -} - -func (c *Context) WithContext(ctx context.Context) *Context { - if ctx == nil { - panic("nil context.Context") - } - cpy := *c - cpy.ctx = ctx - return &cpy -} - -func (c *Context) clone() Context { - variables := make([]byte, len(c.Variables)) - copy(variables, c.Variables) - pathPrefix := make([]byte, len(c.pathPrefix)) - copy(pathPrefix, c.pathPrefix) - pathElements := make([][]byte, len(c.pathElements)) - for i := range pathElements { - pathElements[i] = make([]byte, len(c.pathElements[i])) - copy(pathElements[i], c.pathElements[i]) - } - patches := make([]patch, len(c.patches)) - for i := range patches { - patches[i] = patch{ - path: make([]byte, len(c.patches[i].path)), - extraPath: make([]byte, len(c.patches[i].extraPath)), - data: make([]byte, len(c.patches[i].data)), - index: c.patches[i].index, - } - copy(patches[i].path, c.patches[i].path) - copy(patches[i].extraPath, c.patches[i].extraPath) - copy(patches[i].data, c.patches[i].data) - } - return Context{ - ctx: c.ctx, - Variables: variables, - Request: c.Request, - pathElements: pathElements, - patches: patches, - usedBuffers: make([]*bytes.Buffer, 0, 48), - currentPatch: c.currentPatch, - maxPatch: c.maxPatch, - pathPrefix: pathPrefix, - beforeFetchHook: c.beforeFetchHook, - afterFetchHook: c.afterFetchHook, - position: c.position, - } -} - -func (c *Context) Free() { - c.ctx = nil - c.Variables = c.Variables[:0] - c.pathPrefix = c.pathPrefix[:0] - c.pathElements = c.pathElements[:0] - c.patches = c.patches[:0] - for i := range c.usedBuffers { - pool.BytesBuffer.Put(c.usedBuffers[i]) - } - c.usedBuffers = c.usedBuffers[:0] - c.currentPatch = -1 - c.maxPatch = -1 - c.beforeFetchHook = nil - c.afterFetchHook = nil - c.Request.Header = nil - c.position = Position{} - c.dataLoader = nil - c.RenameTypeNames = nil -} - -func (c *Context) SetBeforeFetchHook(hook BeforeFetchHook) { - c.beforeFetchHook = hook -} - -func (c *Context) SetAfterFetchHook(hook AfterFetchHook) { - c.afterFetchHook = hook -} - -func (c *Context) setPosition(position Position) { - c.position = position -} - -func (c *Context) addResponseElements(elements []string) { - c.responseElements = append(c.responseElements, elements...) -} - -func (c *Context) addResponseArrayElements(elements []string) { - c.responseElements = append(c.responseElements, elements...) - c.responseElements = append(c.responseElements, arrayElementKey) -} - -func (c *Context) removeResponseLastElements(elements []string) { - c.responseElements = c.responseElements[:len(c.responseElements)-len(elements)] -} -func (c *Context) removeResponseArrayLastElements(elements []string) { - c.responseElements = c.responseElements[:len(c.responseElements)-(len(elements)+1)] -} - -func (c *Context) resetResponsePathElements() { - c.responseElements = nil -} - -func (c *Context) addPathElement(elem []byte) { - c.pathElements = append(c.pathElements, elem) -} - -func (c *Context) addIntegerPathElement(elem int) { - b := unsafebytes.StringToBytes(strconv.Itoa(elem)) - c.pathElements = append(c.pathElements, b) -} - -func (c *Context) removeLastPathElement() { - c.pathElements = c.pathElements[:len(c.pathElements)-1] -} - -func (c *Context) path() []byte { - buf := pool.BytesBuffer.Get() - c.usedBuffers = append(c.usedBuffers, buf) - if len(c.pathPrefix) != 0 { - buf.Write(c.pathPrefix) - } else { - buf.Write(literal.SLASH) - buf.Write(literal.DATA) - } - for i := range c.pathElements { - if i == 0 && bytes.Equal(literal.DATA, c.pathElements[0]) { - continue - } - _, _ = buf.Write(literal.SLASH) - _, _ = buf.Write(c.pathElements[i]) - } - return buf.Bytes() -} - -func (c *Context) addPatch(index int, path, extraPath, data []byte) { - next := patch{path: path, extraPath: extraPath, data: data, index: index} - c.patches = append(c.patches, next) - c.maxPatch++ -} - -func (c *Context) popNextPatch() (patch patch, ok bool) { - c.currentPatch++ - if c.currentPatch > c.maxPatch { - return patch, false - } - return c.patches[c.currentPatch], true -} - -type patch struct { - path, extraPath, data []byte - index int -} - -type Fetch interface { - FetchKind() FetchKind -} - -type Fetches []Fetch - -type DataSourceBatchFactory interface { - CreateBatch(inputs [][]byte) (DataSourceBatch, error) -} - -type DataSourceBatch interface { - Demultiplex(responseBufPair *BufPair, outputBuffers []*BufPair) (err error) - Input() *fastbuffer.FastBuffer -} - -type DataSource interface { - Load(ctx context.Context, input []byte, w io.Writer) (err error) -} - -type SubscriptionDataSource interface { - Start(ctx context.Context, input []byte, next chan<- []byte) error -} - -type Resolver struct { - ctx context.Context - dataLoaderEnabled bool - resultSetPool sync.Pool - byteSlicesPool sync.Pool - waitGroupPool sync.Pool - bufPairPool sync.Pool - bufPairSlicePool sync.Pool - errChanPool sync.Pool - hash64Pool sync.Pool - dataloaderFactory *dataLoaderFactory - fetcher *Fetcher -} - -type inflightFetch struct { - waitLoad sync.WaitGroup - waitFree sync.WaitGroup - err error - bufPair BufPair -} - -// New returns a new Resolver, ctx.Done() is used to cancel all active subscriptions & streams -func New(ctx context.Context, fetcher *Fetcher, enableDataLoader bool) *Resolver { - return &Resolver{ - ctx: ctx, - resultSetPool: sync.Pool{ - New: func() interface{} { - return &resultSet{ - buffers: make(map[int]*BufPair, 8), - } - }, - }, - byteSlicesPool: sync.Pool{ - New: func() interface{} { - slice := make([][]byte, 0, 24) - return &slice - }, - }, - waitGroupPool: sync.Pool{ - New: func() interface{} { - return &sync.WaitGroup{} - }, - }, - bufPairPool: sync.Pool{ - New: func() interface{} { - pair := BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - } - return &pair - }, - }, - bufPairSlicePool: sync.Pool{ - New: func() interface{} { - slice := make([]*BufPair, 0, 24) - return &slice - }, - }, - errChanPool: sync.Pool{ - New: func() interface{} { - return make(chan error, 1) - }, - }, - hash64Pool: sync.Pool{ - New: func() interface{} { - return xxhash.New() - }, - }, - dataloaderFactory: newDataloaderFactory(fetcher), - fetcher: fetcher, - dataLoaderEnabled: enableDataLoader, - } -} - -func (r *Resolver) resolveNode(ctx *Context, node Node, data []byte, bufPair *BufPair) (err error) { - switch n := node.(type) { - case *Object: - return r.resolveObject(ctx, n, data, bufPair) - case *Array: - return r.resolveArray(ctx, n, data, bufPair) - case *Null: - if n.Defer.Enabled { - r.preparePatch(ctx, n.Defer.PatchIndex, nil, data) - } - r.resolveNull(bufPair.Data) - return - case *String: - return r.resolveString(ctx, n, data, bufPair) - case *Boolean: - return r.resolveBoolean(ctx, n, data, bufPair) - case *Integer: - return r.resolveInteger(ctx, n, data, bufPair) - case *Float: - return r.resolveFloat(ctx, n, data, bufPair) - case *BigInt: - return r.resolveBigInt(ctx, n, data, bufPair) - case *EmptyObject: - r.resolveEmptyObject(bufPair.Data) - return - case *EmptyArray: - r.resolveEmptyArray(bufPair.Data) - return - case *CustomNode: - return r.resolveCustom(ctx, n, data, bufPair) - default: - return - } -} - -func (r *Resolver) validateContext(ctx *Context) (err error) { - if ctx.maxPatch != -1 || ctx.currentPatch != -1 { - return fmt.Errorf("Context must be resetted using Free() before re-using it") - } - return nil -} - -func extractResponse(responseData []byte, bufPair *BufPair, cfg ProcessResponseConfig) { - if len(responseData) == 0 { - return - } - - if !cfg.ExtractGraphqlResponse { - bufPair.Data.WriteBytes(responseData) - return - } - - jsonparser.EachKey(responseData, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) { - switch i { - case rootErrorsPathIndex: - _, _ = jsonparser.ArrayEach(bytes, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - var ( - message, locations, path, extensions []byte - ) - jsonparser.EachKey(value, func(i int, bytes []byte, valueType jsonparser.ValueType, err error) { - switch i { - case errorsMessagePathIndex: - message = bytes - case errorsLocationsPathIndex: - locations = bytes - case errorsPathPathIndex: - path = bytes - case errorsExtensionsPathIndex: - extensions = bytes - } - }, errorPaths...) - if message != nil { - bufPair.WriteErr(message, locations, path, extensions) - } - }) - case rootDataPathIndex: - if cfg.ExtractFederationEntities { - data, _, _, _ := jsonparser.Get(bytes, entitiesPath...) - bufPair.Data.WriteBytes(data) - return - } - bufPair.Data.WriteBytes(bytes) - } - }, responsePaths...) -} - -func (r *Resolver) ResolveGraphQLResponse(ctx *Context, response *GraphQLResponse, data []byte, writer io.Writer) (err error) { - - buf := r.getBufPair() - defer r.freeBufPair(buf) - - if data != nil { - ctx.lastFetchID = initialValueID - } - - if r.dataLoaderEnabled { - ctx.dataLoader = r.dataloaderFactory.newDataLoader(data) - defer func() { - r.dataloaderFactory.freeDataLoader(ctx.dataLoader) - ctx.dataLoader = nil - }() - } - - ignoreData := false - err = r.resolveNode(ctx, response.Data, data, buf) - if err != nil { - if !errors.Is(err, errNonNullableFieldValueIsNull) { - return - } - ignoreData = true - } - - return writeGraphqlResponse(buf, writer, ignoreData) -} - -func (r *Resolver) resolveGraphQLSubscriptionResponse(ctx *Context, response *GraphQLResponse, subscriptionData *BufPair, writer io.Writer) (err error) { - - buf := r.getBufPair() - defer r.freeBufPair(buf) - - if subscriptionData.HasData() { - ctx.lastFetchID = initialValueID - } - - if r.dataLoaderEnabled { - ctx.dataLoader = r.dataloaderFactory.newDataLoader(subscriptionData.Data.Bytes()) - defer func() { - r.dataloaderFactory.freeDataLoader(ctx.dataLoader) - ctx.dataLoader = nil - }() - } - - ignoreData := false - err = r.resolveNode(ctx, response.Data, subscriptionData.Data.Bytes(), buf) - if err != nil { - if !errors.Is(err, errNonNullableFieldValueIsNull) { - return - } - ignoreData = true - } - if subscriptionData.HasErrors() { - r.MergeBufPairErrors(subscriptionData, buf) - } - - return writeGraphqlResponse(buf, writer, ignoreData) -} - -func writeAndFlush(writer FlushWriter, msg []byte) error { - _, err := writer.Write(msg) - if err != nil { - return err - } - writer.Flush() - return nil -} - -func (r *Resolver) ResolveGraphQLSubscription(ctx *Context, subscription *GraphQLSubscription, writer FlushWriter) (err error) { - - buf := r.getBufPair() - err = subscription.Trigger.InputTemplate.Render(ctx, nil, buf.Data) - if err != nil { - return - } - rendered := buf.Data.Bytes() - subscriptionInput := make([]byte, len(rendered)) - copy(subscriptionInput, rendered) - r.freeBufPair(buf) - - c, cancel := context.WithCancel(ctx.Context()) - defer cancel() - resolverDone := r.ctx.Done() - - next := make(chan []byte) - if subscription.Trigger.Source == nil { - msg := []byte(`{"errors":[{"message":"no data source found"}]}`) - return writeAndFlush(writer, msg) - } - - err = subscription.Trigger.Source.Start(c, subscriptionInput, next) - if err != nil { - if errors.Is(err, ErrUnableToResolve) { - msg := []byte(`{"errors":[{"message":"unable to resolve"}]}`) - return writeAndFlush(writer, msg) - } - return err - } - - responseBuf := r.getBufPair() - defer r.freeBufPair(responseBuf) - - for { - select { - case <-resolverDone: - return nil - case data, ok := <-next: - if !ok { - return nil - } - responseBuf.Reset() - extractResponse(data, responseBuf, subscription.Trigger.ProcessResponseConfig) - err = r.resolveGraphQLSubscriptionResponse(ctx, subscription.Response, responseBuf, writer) - if err != nil { - return err - } - writer.Flush() - } - } -} - -func (r *Resolver) ResolveGraphQLStreamingResponse(ctx *Context, response *GraphQLStreamingResponse, data []byte, writer FlushWriter) (err error) { - - if err := r.validateContext(ctx); err != nil { - return err - } - - err = r.ResolveGraphQLResponse(ctx, response.InitialResponse, data, writer) - if err != nil { - return err - } - writer.Flush() - - nextFlush := time.Now().Add(time.Millisecond * time.Duration(response.FlushInterval)) - - buf := pool.BytesBuffer.Get() - defer pool.BytesBuffer.Put(buf) - - buf.Write(literal.LBRACK) - - done := ctx.Context().Done() - -Loop: - for { - select { - case <-done: - return - default: - patch, ok := ctx.popNextPatch() - if !ok { - break Loop - } - - if patch.index > len(response.Patches)-1 { - continue - } - - if buf.Len() != 1 { - buf.Write(literal.COMMA) - } - - preparedPatch := response.Patches[patch.index] - err = r.ResolveGraphQLResponsePatch(ctx, preparedPatch, patch.data, patch.path, patch.extraPath, buf) - if err != nil { - return err - } - - now := time.Now() - if now.After(nextFlush) { - buf.Write(literal.RBRACK) - _, err = writer.Write(buf.Bytes()) - if err != nil { - return err - } - writer.Flush() - buf.Reset() - buf.Write(literal.LBRACK) - nextFlush = time.Now().Add(time.Millisecond * time.Duration(response.FlushInterval)) - } - } - } - - if buf.Len() != 1 { - buf.Write(literal.RBRACK) - _, err = writer.Write(buf.Bytes()) - if err != nil { - return err - } - writer.Flush() - } - - return -} - -func (r *Resolver) ResolveGraphQLResponsePatch(ctx *Context, patch *GraphQLResponsePatch, data, path, extraPath []byte, writer io.Writer) (err error) { - - buf := r.getBufPair() - defer r.freeBufPair(buf) - - ctx.pathPrefix = append(path, extraPath...) - - if patch.Fetch != nil { - set := r.getResultSet() - defer r.freeResultSet(set) - err = r.resolveFetch(ctx, patch.Fetch, data, set) - if err != nil { - return err - } - _, ok := set.buffers[0] - if ok { - r.MergeBufPairErrors(set.buffers[0], buf) - data = set.buffers[0].Data.Bytes() - } - } - - err = r.resolveNode(ctx, patch.Value, data, buf) - if err != nil { - return - } - - hasErrors := buf.Errors.Len() != 0 - hasData := buf.Data.Len() != 0 - - if hasErrors { - return - } - - if hasData { - if hasErrors { - err = writeSafe(err, writer, comma) - } - err = writeSafe(err, writer, lBrace) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, literal.OP) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, colon) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, patch.Operation) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, comma) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, literal.PATH) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, colon) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, path) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, comma) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, literal.VALUE) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, colon) - _, err = writer.Write(buf.Data.Bytes()) - err = writeSafe(err, writer, rBrace) - } - - return -} - -func (r *Resolver) resolveEmptyArray(b *fastbuffer.FastBuffer) { - b.WriteBytes(lBrack) - b.WriteBytes(rBrack) -} - -func (r *Resolver) resolveEmptyObject(b *fastbuffer.FastBuffer) { - b.WriteBytes(lBrace) - b.WriteBytes(rBrace) -} - -func (r *Resolver) resolveArray(ctx *Context, array *Array, data []byte, arrayBuf *BufPair) (err error) { - if len(array.Path) != 0 { - data, _, _, _ = jsonparser.Get(data, array.Path...) - } - - if bytes.Equal(data, emptyArray) { - r.resolveEmptyArray(arrayBuf.Data) - return - } - - arrayItems := r.byteSlicesPool.Get().(*[][]byte) - defer func() { - *arrayItems = (*arrayItems)[:0] - r.byteSlicesPool.Put(arrayItems) - }() - - _, _ = jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - if err == nil && dataType == jsonparser.String { - value = data[offset-2 : offset+len(value)] // add quotes to string values - } - - *arrayItems = append(*arrayItems, value) - }) - - if len(*arrayItems) == 0 { - if !array.Nullable { - r.resolveEmptyArray(arrayBuf.Data) - return errNonNullableFieldValueIsNull - } - r.resolveNull(arrayBuf.Data) - return nil - } - - ctx.addResponseArrayElements(array.Path) - defer func() { ctx.removeResponseArrayLastElements(array.Path) }() - - if array.ResolveAsynchronous && !array.Stream.Enabled && !r.dataLoaderEnabled { - return r.resolveArrayAsynchronous(ctx, array, arrayItems, arrayBuf) - } - return r.resolveArraySynchronous(ctx, array, arrayItems, arrayBuf) -} - -func (r *Resolver) resolveArraySynchronous(ctx *Context, array *Array, arrayItems *[][]byte, arrayBuf *BufPair) (err error) { - - itemBuf := r.getBufPair() - defer r.freeBufPair(itemBuf) - - arrayBuf.Data.WriteBytes(lBrack) - var ( - hasPreviousItem bool - dataWritten int - ) - for i := range *arrayItems { - - if array.Stream.Enabled { - if i > array.Stream.InitialBatchSize-1 { - ctx.addIntegerPathElement(i) - r.preparePatch(ctx, array.Stream.PatchIndex, nil, (*arrayItems)[i]) - ctx.removeLastPathElement() - continue - } - } - - ctx.addIntegerPathElement(i) - err = r.resolveNode(ctx, array.Item, (*arrayItems)[i], itemBuf) - ctx.removeLastPathElement() - if err != nil { - if errors.Is(err, errNonNullableFieldValueIsNull) && array.Nullable { - arrayBuf.Data.Reset() - r.resolveNull(arrayBuf.Data) - return nil - } - if errors.Is(err, errTypeNameSkipped) { - err = nil - continue - } - return - } - dataWritten += itemBuf.Data.Len() - r.MergeBufPairs(itemBuf, arrayBuf, hasPreviousItem) - if !hasPreviousItem && dataWritten != 0 { - hasPreviousItem = true - } - } - - arrayBuf.Data.WriteBytes(rBrack) - return -} - -func (r *Resolver) resolveArrayAsynchronous(ctx *Context, array *Array, arrayItems *[][]byte, arrayBuf *BufPair) (err error) { - - arrayBuf.Data.WriteBytes(lBrack) - - bufSlice := r.getBufPairSlice() - defer r.freeBufPairSlice(bufSlice) - - wg := r.getWaitGroup() - defer r.freeWaitGroup(wg) - - errCh := r.getErrChan() - defer r.freeErrChan(errCh) - - wg.Add(len(*arrayItems)) - - for i := range *arrayItems { - itemBuf := r.getBufPair() - *bufSlice = append(*bufSlice, itemBuf) - itemData := (*arrayItems)[i] - cloned := ctx.clone() - go func(ctx Context, i int) { - ctx.addPathElement([]byte(strconv.Itoa(i))) - if e := r.resolveNode(&ctx, array.Item, itemData, itemBuf); e != nil && !errors.Is(e, errTypeNameSkipped) { - select { - case errCh <- e: - default: - } - } - ctx.Free() - wg.Done() - }(cloned, i) - } - - wg.Wait() - - select { - case err = <-errCh: - default: - } - - if err != nil { - if errors.Is(err, errNonNullableFieldValueIsNull) && array.Nullable { - arrayBuf.Data.Reset() - r.resolveNull(arrayBuf.Data) - return nil - } - return - } - - var ( - hasPreviousItem bool - dataWritten int - ) - for i := range *bufSlice { - dataWritten += (*bufSlice)[i].Data.Len() - r.MergeBufPairs((*bufSlice)[i], arrayBuf, hasPreviousItem) - if !hasPreviousItem && dataWritten != 0 { - hasPreviousItem = true - } - } - - arrayBuf.Data.WriteBytes(rBrack) - return -} - -func (r *Resolver) exportField(ctx *Context, export *FieldExport, value []byte) { - if export == nil { - return - } - if export.AsString { - value = append(literal.QUOTE, append(value, literal.QUOTE...)...) - } - ctx.Variables, _ = jsonparser.Set(ctx.Variables, value, export.Path...) -} - -func (r *Resolver) resolveInteger(ctx *Context, integer *Integer, data []byte, integerBuf *BufPair) error { - value, dataType, _, err := jsonparser.Get(data, integer.Path...) - if err != nil || dataType != jsonparser.Number { - if !integer.Nullable { - return errNonNullableFieldValueIsNull - } - r.resolveNull(integerBuf.Data) - return nil - } - integerBuf.Data.WriteBytes(value) - r.exportField(ctx, integer.Export, value) - return nil -} - -func (r *Resolver) resolveFloat(ctx *Context, floatValue *Float, data []byte, floatBuf *BufPair) error { - value, dataType, _, err := jsonparser.Get(data, floatValue.Path...) - if err != nil || dataType != jsonparser.Number { - if !floatValue.Nullable { - return errNonNullableFieldValueIsNull - } - r.resolveNull(floatBuf.Data) - return nil - } - floatBuf.Data.WriteBytes(value) - r.exportField(ctx, floatValue.Export, value) - return nil -} - -func (r *Resolver) resolveBigInt(ctx *Context, bigIntValue *BigInt, data []byte, bigIntBuf *BufPair) error { - value, valueType, _, err := jsonparser.Get(data, bigIntValue.Path...) - switch { - case err != nil, valueType == jsonparser.Null: - if !bigIntValue.Nullable { - return errNonNullableFieldValueIsNull - } - r.resolveNull(bigIntBuf.Data) - return nil - case valueType == jsonparser.Number: - bigIntBuf.Data.WriteBytes(value) - case valueType == jsonparser.String: - bigIntBuf.Data.WriteBytes(quote) - bigIntBuf.Data.WriteBytes(value) - bigIntBuf.Data.WriteBytes(quote) - default: - return fmt.Errorf("invalid value type '%s' for path %s, expecting number or string, got: %v", valueType, string(ctx.path()), string(value)) - - } - r.exportField(ctx, bigIntValue.Export, value) - return nil -} - -func (r *Resolver) resolveCustom(ctx *Context, customValue *CustomNode, data []byte, customBuf *BufPair) error { - value, dataType, _, _ := jsonparser.Get(data, customValue.Path...) - if dataType == jsonparser.Null && !customValue.Nullable { - return errNonNullableFieldValueIsNull - } - resolvedValue, err := customValue.Resolve(value) - if err != nil { - return fmt.Errorf("failed to resolve value type %s for path %s via custom resolver", dataType, string(ctx.path())) - } - customBuf.Data.WriteBytes(resolvedValue) - return nil -} - -func (r *Resolver) resolveBoolean(ctx *Context, boolean *Boolean, data []byte, booleanBuf *BufPair) error { - value, valueType, _, err := jsonparser.Get(data, boolean.Path...) - if err != nil || valueType != jsonparser.Boolean { - if !boolean.Nullable { - return errNonNullableFieldValueIsNull - } - r.resolveNull(booleanBuf.Data) - return nil - } - booleanBuf.Data.WriteBytes(value) - r.exportField(ctx, boolean.Export, value) - return nil -} - -func (r *Resolver) resolveString(ctx *Context, str *String, data []byte, stringBuf *BufPair) error { - var ( - value []byte - valueType jsonparser.ValueType - err error - ) - - value, valueType, _, err = jsonparser.Get(data, str.Path...) - if err != nil || valueType != jsonparser.String { - if err == nil && str.UnescapeResponseJson { - switch valueType { - case jsonparser.Object, jsonparser.Array, jsonparser.Boolean, jsonparser.Number, jsonparser.Null: - stringBuf.Data.WriteBytes(value) - return nil - } - } - if value != nil && valueType != jsonparser.Null { - return fmt.Errorf("invalid value type '%s' for path %s, expecting string, got: %v. You can fix this by configuring this field as Int/Float/JSON Scalar", valueType, string(ctx.path()), string(value)) - } - if !str.Nullable { - return errNonNullableFieldValueIsNull - } - r.resolveNull(stringBuf.Data) - return nil - } - - if value == nil && !str.Nullable { - return errNonNullableFieldValueIsNull - } - - if str.UnescapeResponseJson { - value = bytes.ReplaceAll(value, []byte(`\"`), []byte(`"`)) - - // Do not modify values which was strings - // When the original value from upstream response was a plain string value `"hello"`, `"true"`, `"1"`, `"2.0"`, - // after getting it via jsonparser.Get we will get unquoted values `hello`, `true`, `1`, `2.0` - // which is not string anymore, so we need to quote it again - if !(bytes.ContainsAny(value, `{}[]`) && gjson.ValidBytes(value)) { - // wrap value in quotes to make it valid json - value = append(literal.QUOTE, append(value, literal.QUOTE...)...) - } - - stringBuf.Data.WriteBytes(value) - r.exportField(ctx, str.Export, value) - return nil - } - - value = r.renameTypeName(ctx, str, value) - - stringBuf.Data.WriteBytes(quote) - stringBuf.Data.WriteBytes(value) - stringBuf.Data.WriteBytes(quote) - r.exportField(ctx, str.Export, value) - return nil -} - -func (r *Resolver) renameTypeName(ctx *Context, str *String, typeName []byte) []byte { - if !str.IsTypeName { - return typeName - } - for i := range ctx.RenameTypeNames { - if bytes.Equal(ctx.RenameTypeNames[i].From, typeName) { - return ctx.RenameTypeNames[i].To - } - } - return typeName -} - -func (r *Resolver) preparePatch(ctx *Context, patchIndex int, extraPath, data []byte) { - buf := pool.BytesBuffer.Get() - ctx.usedBuffers = append(ctx.usedBuffers, buf) - _, _ = buf.Write(data) - path, data := ctx.path(), buf.Bytes() - ctx.addPatch(patchIndex, path, extraPath, data) -} - -func (r *Resolver) resolveNull(b *fastbuffer.FastBuffer) { - b.WriteBytes(null) -} - -func (r *Resolver) addResolveError(ctx *Context, objectBuf *BufPair) { - locations, path := pool.BytesBuffer.Get(), pool.BytesBuffer.Get() - defer pool.BytesBuffer.Put(locations) - defer pool.BytesBuffer.Put(path) - - var pathBytes []byte - - locations.Write(lBrack) - locations.Write(lBrace) - locations.Write(quote) - locations.Write(literalLine) - locations.Write(quote) - locations.Write(colon) - locations.Write([]byte(strconv.Itoa(int(ctx.position.Line)))) - locations.Write(comma) - locations.Write(quote) - locations.Write(literalColumn) - locations.Write(quote) - locations.Write(colon) - locations.Write([]byte(strconv.Itoa(int(ctx.position.Column)))) - locations.Write(rBrace) - locations.Write(rBrack) - - if len(ctx.pathElements) > 0 { - path.Write(lBrack) - path.Write(quote) - path.Write(bytes.Join(ctx.pathElements, quotedComma)) - path.Write(quote) - path.Write(rBrack) - - pathBytes = path.Bytes() - } - - objectBuf.WriteErr(unableToResolveMsg, locations.Bytes(), pathBytes, nil) -} - -func (r *Resolver) resolveObject(ctx *Context, object *Object, data []byte, objectBuf *BufPair) (err error) { - if len(object.Path) != 0 { - data, _, _, _ = jsonparser.Get(data, object.Path...) - - if len(data) == 0 || bytes.Equal(data, literal.NULL) { - // we will not traverse the children if the object is null - // therefore, we must "pop" the null element from the batch - r.recursivelySkipBatchResults(ctx, object, data) - if object.Nullable { - r.resolveNull(objectBuf.Data) - return - } - - r.addResolveError(ctx, objectBuf) - return errNonNullableFieldValueIsNull - } - - ctx.addResponseElements(object.Path) - defer ctx.removeResponseLastElements(object.Path) - } - - if object.UnescapeResponseJson { - data = bytes.ReplaceAll(data, []byte(`\"`), []byte(`"`)) - } - - var set *resultSet - if object.Fetch != nil { - set = r.getResultSet() - defer r.freeResultSet(set) - err = r.resolveFetch(ctx, object.Fetch, data, set) - if err != nil { - return - } - for i := range set.buffers { - r.MergeBufPairErrors(set.buffers[i], objectBuf) - } - } - - fieldBuf := r.getBufPair() - defer r.freeBufPair(fieldBuf) - - responseElements := ctx.responseElements - lastFetchID := ctx.lastFetchID - - typeNameSkip := false - first := true - skipCount := 0 - for i := range object.Fields { - if object.Fields[i].SkipDirectiveDefined { - skip, err := jsonparser.GetBoolean(ctx.Variables, object.Fields[i].SkipVariableName) - if err == nil && skip { - skipCount++ - continue - } - } - - if object.Fields[i].IncludeDirectiveDefined { - include, err := jsonparser.GetBoolean(ctx.Variables, object.Fields[i].IncludeVariableName) - if err != nil || !include { - skipCount++ - continue - } - } - - var fieldData []byte - if set != nil && object.Fields[i].HasBuffer { - buffer, ok := set.buffers[object.Fields[i].BufferID] - if ok { - fieldData = buffer.Data.Bytes() - ctx.resetResponsePathElements() - ctx.lastFetchID = object.Fields[i].BufferID - } - } else { - fieldData = data - } - - if object.Fields[i].OnTypeNames != nil { - typeName, _, _, _ := jsonparser.Get(fieldData, "__typename") - hasMatch := false - for _, onTypeName := range object.Fields[i].OnTypeNames { - if bytes.Equal(typeName, onTypeName) { - hasMatch = true - break - } - } - if !hasMatch { - typeNameSkip = true - // Restore the response elements that may have been reset above. - ctx.responseElements = responseElements - ctx.lastFetchID = lastFetchID - continue - } - } - - if first { - objectBuf.Data.WriteBytes(lBrace) - first = false - } else { - objectBuf.Data.WriteBytes(comma) - } - objectBuf.Data.WriteBytes(quote) - objectBuf.Data.WriteBytes(object.Fields[i].Name) - objectBuf.Data.WriteBytes(quote) - objectBuf.Data.WriteBytes(colon) - ctx.addPathElement(object.Fields[i].Name) - ctx.setPosition(object.Fields[i].Position) - err = r.resolveNode(ctx, object.Fields[i].Value, fieldData, fieldBuf) - ctx.removeLastPathElement() - ctx.responseElements = responseElements - ctx.lastFetchID = lastFetchID - if err != nil { - if errors.Is(err, errTypeNameSkipped) { - objectBuf.Data.Reset() - r.resolveEmptyObject(objectBuf.Data) - return nil - } - if errors.Is(err, errNonNullableFieldValueIsNull) { - objectBuf.Data.Reset() - r.MergeBufPairErrors(fieldBuf, objectBuf) - - if object.Nullable { - r.resolveNull(objectBuf.Data) - return nil - } - - // if fied is of object type than we should not add resolve error here - if _, ok := object.Fields[i].Value.(*Object); !ok { - r.addResolveError(ctx, objectBuf) - } - } - - return - } - r.MergeBufPairs(fieldBuf, objectBuf, false) - } - allSkipped := len(object.Fields) != 0 && len(object.Fields) == skipCount - if allSkipped { - // return empty object if all fields have been skipped - objectBuf.Data.WriteBytes(lBrace) - objectBuf.Data.WriteBytes(rBrace) - return - } - if first { - if typeNameSkip && !object.Nullable { - return errTypeNameSkipped - } - if !object.Nullable { - r.addResolveError(ctx, objectBuf) - return errNonNullableFieldValueIsNull - } - r.resolveNull(objectBuf.Data) - return - } - objectBuf.Data.WriteBytes(rBrace) - return -} - -// recursivelySkipBatchResults traverses an object and skips all batch results by triggering fetch -// when a fetch is attached to an object using batch fetch, only the first object will actually trigger the fetch -// subsequent objects (siblings) will load the result from the cache, filled by the first sibling -// if one sibling has no data (null), we have to "pop" the null result (generated by the batch resolver) from the cache -// this is because the "null" sibling will not trigger a fetch by itself, as it has no data and will not resolve any fields -func (r *Resolver) recursivelySkipBatchResults(ctx *Context, object *Object, data []byte) { - if object.Fetch != nil && object.Fetch.FetchKind() == FetchKindBatch { - set := r.getResultSet() - defer r.freeResultSet(set) - _ = r.resolveFetch(ctx, object.Fetch, data, set) - } - for i := range object.Fields { - value := object.Fields[i].Value - switch v := value.(type) { - case *Object: - r.recursivelySkipBatchResults(ctx, v, data) - case *Array: - switch av := v.Item.(type) { - case *Object: - r.recursivelySkipBatchResults(ctx, av, data) - } - } - } -} - -func (r *Resolver) freeResultSet(set *resultSet) { - for i := range set.buffers { - set.buffers[i].Reset() - r.bufPairPool.Put(set.buffers[i]) - delete(set.buffers, i) - } - r.resultSetPool.Put(set) -} - -func (r *Resolver) resolveFetch(ctx *Context, fetch Fetch, data []byte, set *resultSet) (err error) { - // if context is cancelled, we should not resolve the fetch - if errors.Is(ctx.Context().Err(), context.Canceled) { - return nil - } - - switch f := fetch.(type) { - case *SingleFetch: - preparedInput := r.getBufPair() - defer r.freeBufPair(preparedInput) - err = r.prepareSingleFetch(ctx, f, data, set, preparedInput.Data) - if err != nil { - return err - } - err = r.resolveSingleFetch(ctx, f, preparedInput.Data, set.buffers[f.BufferId]) - case *BatchFetch: - preparedInput := r.getBufPair() - defer r.freeBufPair(preparedInput) - err = r.prepareSingleFetch(ctx, f.Fetch, data, set, preparedInput.Data) - if err != nil { - return err - } - err = r.resolveBatchFetch(ctx, f, preparedInput.Data, set.buffers[f.Fetch.BufferId]) - case *ParallelFetch: - err = r.resolveParallelFetch(ctx, f, data, set) - } - return -} - -func (r *Resolver) resolveParallelFetch(ctx *Context, fetch *ParallelFetch, data []byte, set *resultSet) (err error) { - preparedInputs := r.getBufPairSlice() - defer r.freeBufPairSlice(preparedInputs) - - resolvers := make([]func() error, 0, len(fetch.Fetches)) - - wg := r.getWaitGroup() - defer r.freeWaitGroup(wg) - - for i := range fetch.Fetches { - wg.Add(1) - switch f := fetch.Fetches[i].(type) { - case *SingleFetch: - preparedInput := r.getBufPair() - err = r.prepareSingleFetch(ctx, f, data, set, preparedInput.Data) - if err != nil { - return err - } - *preparedInputs = append(*preparedInputs, preparedInput) - buf := set.buffers[f.BufferId] - resolvers = append(resolvers, func() error { - return r.resolveSingleFetch(ctx, f, preparedInput.Data, buf) - }) - case *BatchFetch: - preparedInput := r.getBufPair() - err = r.prepareSingleFetch(ctx, f.Fetch, data, set, preparedInput.Data) - if err != nil { - return err - } - *preparedInputs = append(*preparedInputs, preparedInput) - buf := set.buffers[f.Fetch.BufferId] - resolvers = append(resolvers, func() error { - return r.resolveBatchFetch(ctx, f, preparedInput.Data, buf) - }) - } - } - - for _, resolver := range resolvers { - go func(r func() error) { - _ = r() - wg.Done() - }(resolver) - } - - wg.Wait() - - return -} - -func (r *Resolver) prepareSingleFetch(ctx *Context, fetch *SingleFetch, data []byte, set *resultSet, preparedInput *fastbuffer.FastBuffer) (err error) { - err = fetch.InputTemplate.Render(ctx, data, preparedInput) - buf := r.getBufPair() - set.buffers[fetch.BufferId] = buf - return -} - -func (r *Resolver) resolveBatchFetch(ctx *Context, fetch *BatchFetch, preparedInput *fastbuffer.FastBuffer, buf *BufPair) error { - if r.dataLoaderEnabled { - return ctx.dataLoader.LoadBatch(ctx, fetch, buf) - } - - if err := r.fetcher.FetchBatch(ctx, fetch, []*fastbuffer.FastBuffer{preparedInput}, []*BufPair{buf}); err != nil { - return err - } - - return nil -} - -func (r *Resolver) resolveSingleFetch(ctx *Context, fetch *SingleFetch, preparedInput *fastbuffer.FastBuffer, buf *BufPair) error { - if r.dataLoaderEnabled && !fetch.DisableDataLoader { - return ctx.dataLoader.Load(ctx, fetch, buf) - } - return r.fetcher.Fetch(ctx, fetch, preparedInput, buf) -} - -type Object struct { - Nullable bool - Path []string - Fields []*Field - Fetch Fetch - UnescapeResponseJson bool `json:"unescape_response_json,omitempty"` -} - -func (_ *Object) NodeKind() NodeKind { - return NodeKindObject -} - -type EmptyObject struct{} - -func (_ *EmptyObject) NodeKind() NodeKind { - return NodeKindEmptyObject -} - -type EmptyArray struct{} - -func (_ *EmptyArray) NodeKind() NodeKind { - return NodeKindEmptyArray -} - -type Field struct { - Name []byte - Value Node - Position Position - Defer *DeferField - Stream *StreamField - HasBuffer bool - BufferID int - OnTypeNames [][]byte - SkipDirectiveDefined bool - SkipVariableName string - IncludeDirectiveDefined bool - IncludeVariableName string -} - -type Position struct { - Line uint32 - Column uint32 -} - -type StreamField struct { - InitialBatchSize int -} - -type DeferField struct{} - -type Null struct { - Defer Defer -} - -type Defer struct { - Enabled bool - PatchIndex int -} - -func (_ *Null) NodeKind() NodeKind { - return NodeKindNull -} - -type resultSet struct { - buffers map[int]*BufPair -} - -type SingleFetch struct { - BufferId int - Input string - DataSource DataSource - Variables Variables - // DisallowSingleFlight is used for write operations like mutations, POST, DELETE etc. to disable singleFlight - // By default SingleFlight for fetches is disabled and needs to be enabled on the Resolver first - // If the resolver allows SingleFlight it's up to each individual DataSource Planner to decide whether an Operation - // should be allowed to use SingleFlight - DisallowSingleFlight bool - DisableDataLoader bool - InputTemplate InputTemplate - DataSourceIdentifier []byte - ProcessResponseConfig ProcessResponseConfig - // SetTemplateOutputToNullOnVariableNull will safely return "null" if one of the template variables renders to null - // This is the case, e.g. when using batching and one sibling is null, resulting in a null value for one batch item - // Returning null in this case tells the batch implementation to skip this item - SetTemplateOutputToNullOnVariableNull bool -} - -type ProcessResponseConfig struct { - ExtractGraphqlResponse bool - ExtractFederationEntities bool -} - -func (_ *SingleFetch) FetchKind() FetchKind { - return FetchKindSingle -} - -type ParallelFetch struct { - Fetches []Fetch -} - -func (_ *ParallelFetch) FetchKind() FetchKind { - return FetchKindParallel -} - -type BatchFetch struct { - Fetch *SingleFetch - BatchFactory DataSourceBatchFactory -} - -func (_ *BatchFetch) FetchKind() FetchKind { - return FetchKindBatch -} - -// FieldExport takes the value of the field during evaluation (rendering of the field) -// and stores it in the variables using the Path as JSON pointer. -type FieldExport struct { - Path []string - AsString bool -} - -type String struct { - Path []string - Nullable bool - Export *FieldExport `json:"export,omitempty"` - UnescapeResponseJson bool `json:"unescape_response_json,omitempty"` - IsTypeName bool `json:"is_type_name,omitempty"` -} - -func (_ *String) NodeKind() NodeKind { - return NodeKindString -} - -type CustomResolve interface { - Resolve(value []byte) ([]byte, error) -} - -type CustomNode struct { - CustomResolve - Nullable bool - Path []string -} - -func (_ *CustomNode) NodeKind() NodeKind { - return NodeKindCustom -} - -type Boolean struct { - Path []string - Nullable bool - Export *FieldExport `json:"export,omitempty"` -} - -func (_ *Boolean) NodeKind() NodeKind { - return NodeKindBoolean -} - -type Float struct { - Path []string - Nullable bool - Export *FieldExport `json:"export,omitempty"` -} - -func (_ *Float) NodeKind() NodeKind { - return NodeKindFloat -} - -type Integer struct { - Path []string - Nullable bool - Export *FieldExport `json:"export,omitempty"` -} - -func (_ *Integer) NodeKind() NodeKind { - return NodeKindInteger -} - -type BigInt struct { - Path []string - Nullable bool - Export *FieldExport `json:"export,omitempty"` -} - -func (BigInt) NodeKind() NodeKind { - return NodeKindBigInt -} - -type Array struct { - Path []string - Nullable bool - ResolveAsynchronous bool - Item Node - Stream Stream -} - -type Stream struct { - Enabled bool - InitialBatchSize int - PatchIndex int -} - -func (_ *Array) NodeKind() NodeKind { - return NodeKindArray -} - -type GraphQLSubscription struct { - Trigger GraphQLSubscriptionTrigger - Response *GraphQLResponse -} - -type GraphQLSubscriptionTrigger struct { - Input []byte - InputTemplate InputTemplate - Variables Variables - Source SubscriptionDataSource - ProcessResponseConfig ProcessResponseConfig -} - -type FlushWriter interface { - io.Writer - Flush() -} - -type GraphQLResponse struct { - Data Node - RenameTypeNames []RenameTypeName -} - -type RenameTypeName struct { - From, To []byte -} - -type GraphQLStreamingResponse struct { - InitialResponse *GraphQLResponse - Patches []*GraphQLResponsePatch - FlushInterval int64 -} - -type GraphQLResponsePatch struct { - Value Node - Fetch Fetch - Operation []byte -} - -type BufPair struct { - Data *fastbuffer.FastBuffer - Errors *fastbuffer.FastBuffer -} - -func NewBufPair() *BufPair { - return &BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - } -} - -func (b *BufPair) HasData() bool { - return b.Data.Len() != 0 -} - -func (b *BufPair) HasErrors() bool { - return b.Errors.Len() != 0 -} - -func (b *BufPair) Reset() { - b.Data.Reset() - b.Errors.Reset() -} - -func (b *BufPair) writeErrors(data []byte) { - b.Errors.WriteBytes(data) -} - -func (b *BufPair) WriteErr(message, locations, path, extensions []byte) { - if b.HasErrors() { - b.writeErrors(comma) - } - b.writeErrors(lBrace) - b.writeErrors(quote) - b.writeErrors(literalMessage) - b.writeErrors(quote) - b.writeErrors(colon) - b.writeErrors(quote) - b.writeErrors(message) - b.writeErrors(quote) - - if locations != nil { - b.writeErrors(comma) - b.writeErrors(quote) - b.writeErrors(literalLocations) - b.writeErrors(quote) - b.writeErrors(colon) - b.writeErrors(locations) - } - - if path != nil { - b.writeErrors(comma) - b.writeErrors(quote) - b.writeErrors(literalPath) - b.writeErrors(quote) - b.writeErrors(colon) - b.writeErrors(path) - } - - if extensions != nil { - b.writeErrors(comma) - b.writeErrors(quote) - b.writeErrors(literalExtensions) - b.writeErrors(quote) - b.writeErrors(colon) - b.writeErrors(extensions) - } - - b.writeErrors(rBrace) -} - -func (r *Resolver) MergeBufPairs(from, to *BufPair, prefixDataWithComma bool) { - r.MergeBufPairData(from, to, prefixDataWithComma) - r.MergeBufPairErrors(from, to) -} - -func (r *Resolver) MergeBufPairData(from, to *BufPair, prefixDataWithComma bool) { - if !from.HasData() { - return - } - if prefixDataWithComma { - to.Data.WriteBytes(comma) - } - to.Data.WriteBytes(from.Data.Bytes()) - from.Data.Reset() -} - -func (r *Resolver) MergeBufPairErrors(from, to *BufPair) { - if !from.HasErrors() { - return - } - if to.HasErrors() { - to.Errors.WriteBytes(comma) - } - to.Errors.WriteBytes(from.Errors.Bytes()) - from.Errors.Reset() -} - -func (r *Resolver) freeBufPair(pair *BufPair) { - pair.Data.Reset() - pair.Errors.Reset() - r.bufPairPool.Put(pair) -} - -func (r *Resolver) getResultSet() *resultSet { - return r.resultSetPool.Get().(*resultSet) -} - -func (r *Resolver) getBufPair() *BufPair { - return r.bufPairPool.Get().(*BufPair) -} - -func (r *Resolver) getBufPairSlice() *[]*BufPair { - return r.bufPairSlicePool.Get().(*[]*BufPair) -} - -func (r *Resolver) freeBufPairSlice(slice *[]*BufPair) { - for i := range *slice { - r.freeBufPair((*slice)[i]) - } - *slice = (*slice)[:0] - r.bufPairSlicePool.Put(slice) -} - -func (r *Resolver) getErrChan() chan error { - return r.errChanPool.Get().(chan error) -} - -func (r *Resolver) freeErrChan(ch chan error) { - r.errChanPool.Put(ch) -} - -func (r *Resolver) getWaitGroup() *sync.WaitGroup { - return r.waitGroupPool.Get().(*sync.WaitGroup) -} - -func (r *Resolver) freeWaitGroup(wg *sync.WaitGroup) { - r.waitGroupPool.Put(wg) -} - -func writeGraphqlResponse(buf *BufPair, writer io.Writer, ignoreData bool) (err error) { - hasErrors := buf.Errors.Len() != 0 - hasData := buf.Data.Len() != 0 && !ignoreData - - err = writeSafe(err, writer, lBrace) - - if hasErrors { - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, literalErrors) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, colon) - err = writeSafe(err, writer, lBrack) - err = writeSafe(err, writer, buf.Errors.Bytes()) - err = writeSafe(err, writer, rBrack) - err = writeSafe(err, writer, comma) - } - - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, literalData) - err = writeSafe(err, writer, quote) - err = writeSafe(err, writer, colon) - - if hasData { - _, err = writer.Write(buf.Data.Bytes()) - } else { - err = writeSafe(err, writer, literal.NULL) - } - err = writeSafe(err, writer, rBrace) - - return err -} - -func writeSafe(err error, writer io.Writer, data []byte) error { - if err != nil { - return err - } - _, err = writer.Write(data) - return err -} diff --git a/pkg/engine/resolve/resolve_mock_test.go b/pkg/engine/resolve/resolve_mock_test.go deleted file mode 100644 index 7f185d187..000000000 --- a/pkg/engine/resolve/resolve_mock_test.go +++ /dev/null @@ -1,222 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/wundergraph/graphql-go-tools/pkg/engine/resolve (interfaces: DataSource,BeforeFetchHook,AfterFetchHook,DataSourceBatch,DataSourceBatchFactory) - -// Package resolve is a generated GoMock package. -package resolve - -import ( - context "context" - io "io" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - fastbuffer "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" -) - -// MockDataSource is a mock of DataSource interface. -type MockDataSource struct { - ctrl *gomock.Controller - recorder *MockDataSourceMockRecorder -} - -// MockDataSourceMockRecorder is the mock recorder for MockDataSource. -type MockDataSourceMockRecorder struct { - mock *MockDataSource -} - -// NewMockDataSource creates a new mock instance. -func NewMockDataSource(ctrl *gomock.Controller) *MockDataSource { - mock := &MockDataSource{ctrl: ctrl} - mock.recorder = &MockDataSourceMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDataSource) EXPECT() *MockDataSourceMockRecorder { - return m.recorder -} - -// Load mocks base method. -func (m *MockDataSource) Load(arg0 context.Context, arg1 []byte, arg2 io.Writer) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Load", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// Load indicates an expected call of Load. -func (mr *MockDataSourceMockRecorder) Load(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Load", reflect.TypeOf((*MockDataSource)(nil).Load), arg0, arg1, arg2) -} - -// MockBeforeFetchHook is a mock of BeforeFetchHook interface. -type MockBeforeFetchHook struct { - ctrl *gomock.Controller - recorder *MockBeforeFetchHookMockRecorder -} - -// MockBeforeFetchHookMockRecorder is the mock recorder for MockBeforeFetchHook. -type MockBeforeFetchHookMockRecorder struct { - mock *MockBeforeFetchHook -} - -// NewMockBeforeFetchHook creates a new mock instance. -func NewMockBeforeFetchHook(ctrl *gomock.Controller) *MockBeforeFetchHook { - mock := &MockBeforeFetchHook{ctrl: ctrl} - mock.recorder = &MockBeforeFetchHookMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockBeforeFetchHook) EXPECT() *MockBeforeFetchHookMockRecorder { - return m.recorder -} - -// OnBeforeFetch mocks base method. -func (m *MockBeforeFetchHook) OnBeforeFetch(arg0 HookContext, arg1 []byte) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnBeforeFetch", arg0, arg1) -} - -// OnBeforeFetch indicates an expected call of OnBeforeFetch. -func (mr *MockBeforeFetchHookMockRecorder) OnBeforeFetch(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnBeforeFetch", reflect.TypeOf((*MockBeforeFetchHook)(nil).OnBeforeFetch), arg0, arg1) -} - -// MockAfterFetchHook is a mock of AfterFetchHook interface. -type MockAfterFetchHook struct { - ctrl *gomock.Controller - recorder *MockAfterFetchHookMockRecorder -} - -// MockAfterFetchHookMockRecorder is the mock recorder for MockAfterFetchHook. -type MockAfterFetchHookMockRecorder struct { - mock *MockAfterFetchHook -} - -// NewMockAfterFetchHook creates a new mock instance. -func NewMockAfterFetchHook(ctrl *gomock.Controller) *MockAfterFetchHook { - mock := &MockAfterFetchHook{ctrl: ctrl} - mock.recorder = &MockAfterFetchHookMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockAfterFetchHook) EXPECT() *MockAfterFetchHookMockRecorder { - return m.recorder -} - -// OnData mocks base method. -func (m *MockAfterFetchHook) OnData(arg0 HookContext, arg1 []byte, arg2 bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnData", arg0, arg1, arg2) -} - -// OnData indicates an expected call of OnData. -func (mr *MockAfterFetchHookMockRecorder) OnData(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnData", reflect.TypeOf((*MockAfterFetchHook)(nil).OnData), arg0, arg1, arg2) -} - -// OnError mocks base method. -func (m *MockAfterFetchHook) OnError(arg0 HookContext, arg1 []byte, arg2 bool) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "OnError", arg0, arg1, arg2) -} - -// OnError indicates an expected call of OnError. -func (mr *MockAfterFetchHookMockRecorder) OnError(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OnError", reflect.TypeOf((*MockAfterFetchHook)(nil).OnError), arg0, arg1, arg2) -} - -// MockDataSourceBatch is a mock of DataSourceBatch interface. -type MockDataSourceBatch struct { - ctrl *gomock.Controller - recorder *MockDataSourceBatchMockRecorder -} - -// MockDataSourceBatchMockRecorder is the mock recorder for MockDataSourceBatch. -type MockDataSourceBatchMockRecorder struct { - mock *MockDataSourceBatch -} - -// NewMockDataSourceBatch creates a new mock instance. -func NewMockDataSourceBatch(ctrl *gomock.Controller) *MockDataSourceBatch { - mock := &MockDataSourceBatch{ctrl: ctrl} - mock.recorder = &MockDataSourceBatchMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDataSourceBatch) EXPECT() *MockDataSourceBatchMockRecorder { - return m.recorder -} - -// Demultiplex mocks base method. -func (m *MockDataSourceBatch) Demultiplex(arg0 *BufPair, arg1 []*BufPair) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Demultiplex", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// Demultiplex indicates an expected call of Demultiplex. -func (mr *MockDataSourceBatchMockRecorder) Demultiplex(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Demultiplex", reflect.TypeOf((*MockDataSourceBatch)(nil).Demultiplex), arg0, arg1) -} - -// Input mocks base method. -func (m *MockDataSourceBatch) Input() *fastbuffer.FastBuffer { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Input") - ret0, _ := ret[0].(*fastbuffer.FastBuffer) - return ret0 -} - -// Input indicates an expected call of Input. -func (mr *MockDataSourceBatchMockRecorder) Input() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Input", reflect.TypeOf((*MockDataSourceBatch)(nil).Input)) -} - -// MockDataSourceBatchFactory is a mock of DataSourceBatchFactory interface. -type MockDataSourceBatchFactory struct { - ctrl *gomock.Controller - recorder *MockDataSourceBatchFactoryMockRecorder -} - -// MockDataSourceBatchFactoryMockRecorder is the mock recorder for MockDataSourceBatchFactory. -type MockDataSourceBatchFactoryMockRecorder struct { - mock *MockDataSourceBatchFactory -} - -// NewMockDataSourceBatchFactory creates a new mock instance. -func NewMockDataSourceBatchFactory(ctrl *gomock.Controller) *MockDataSourceBatchFactory { - mock := &MockDataSourceBatchFactory{ctrl: ctrl} - mock.recorder = &MockDataSourceBatchFactoryMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockDataSourceBatchFactory) EXPECT() *MockDataSourceBatchFactoryMockRecorder { - return m.recorder -} - -// CreateBatch mocks base method. -func (m *MockDataSourceBatchFactory) CreateBatch(arg0 [][]byte) (DataSourceBatch, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateBatch", arg0) - ret0, _ := ret[0].(DataSourceBatch) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateBatch indicates an expected call of CreateBatch. -func (mr *MockDataSourceBatchFactoryMockRecorder) CreateBatch(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBatch", reflect.TypeOf((*MockDataSourceBatchFactory)(nil).CreateBatch), arg0) -} diff --git a/pkg/engine/resolve/resolve_test.go b/pkg/engine/resolve/resolve_test.go deleted file mode 100644 index fbc4a6a3a..000000000 --- a/pkg/engine/resolve/resolve_test.go +++ /dev/null @@ -1,4541 +0,0 @@ -package resolve - -// go:generate mockgen -package resolve -destination resolve_mock_test.go . DataSource,BeforeFetchHook,AfterFetchHook,DataSourceBatch,DataSourceBatchFactory - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "net/http" - "sync" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" -) - -type _fakeDataSource struct { - data []byte - artificialLatency time.Duration -} - -func (f *_fakeDataSource) Load(ctx context.Context, input []byte, w io.Writer) (err error) { - if f.artificialLatency != 0 { - time.Sleep(f.artificialLatency) - } - _, err = w.Write(f.data) - return -} - -func FakeDataSource(data string) *_fakeDataSource { - return &_fakeDataSource{ - data: []byte(data), - } -} - -type _fakeDataSourceBatch struct { - resultedInput *fastbuffer.FastBuffer - bufPairs []*BufPair -} - -func (f *_fakeDataSourceBatch) Input() *fastbuffer.FastBuffer { - return f.resultedInput -} - -func (f *_fakeDataSourceBatch) Demultiplex(responseBufPair *BufPair, bufPairs []*BufPair) (err error) { - for i := range bufPairs { - bufPairs[i].Data.WriteBytes(f.bufPairs[i].Data.Bytes()) - bufPairs[i].Errors.WriteBytes(f.bufPairs[i].Errors.Bytes()) - } - - return nil -} - -type resultedBufPair struct { - data string - err string -} - -func NewFakeDataSourceBatch(resultedInput string, resultedBufPairs []resultedBufPair) *_fakeDataSourceBatch { - bufInput := fastbuffer.New() - bufInput.WriteString(resultedInput) - - bufPairs := make([]*BufPair, len(resultedBufPairs)) - for i, v := range resultedBufPairs { - bufPair := NewBufPair() - bufPair.Data.WriteString(v.data) - if v.err != "" { - bufPair.WriteErr([]byte(v.err), nil, nil, nil) - } - - bufPairs[i] = bufPair - } - - return &_fakeDataSourceBatch{ - resultedInput: bufInput, - bufPairs: bufPairs, - } -} - -type _byteMatchter struct { - data []byte -} - -func (b _byteMatchter) Matches(x interface{}) bool { - return bytes.Equal(b.data, x.([]byte)) -} - -func (b _byteMatchter) String() string { - return "bytes: " + string(b.data) -} - -func matchBytes(bytes string) *_byteMatchter { - return &_byteMatchter{data: []byte(bytes)} -} - -type gotBytesFormatter struct { -} - -func (g gotBytesFormatter) Got(got interface{}) string { - return "bytes: " + string(got.([]byte)) -} - -func newResolver(ctx context.Context, enableSingleFlight bool, enableDataLoader bool) *Resolver { - return New(ctx, NewFetcher(enableSingleFlight), enableDataLoader) -} - -type customResolver struct{} - -func (customResolver) Resolve(value []byte) ([]byte, error) { - return value, nil -} - -type customErrResolve struct{} - -func (customErrResolve) Resolve(value []byte) ([]byte, error) { - return nil, errors.New("custom error") -} - -func TestResolver_ResolveNode(t *testing.T) { - testFn := func(enableSingleFlight bool, enableDataLoader bool, fn func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string)) func(t *testing.T) { - ctrl := gomock.NewController(t) - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - r := newResolver(rCtx, enableSingleFlight, enableDataLoader) - node, ctx, expectedOutput := fn(t, ctrl) - return func(t *testing.T) { - buf := &BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - } - err := r.resolveNode(&ctx, node, nil, buf) - assert.Equal(t, buf.Errors.String(), "", "want error buf to be empty") - assert.NoError(t, err) - assert.Equal(t, expectedOutput, buf.Data.String()) - ctrl.Finish() - } - } - - testErrFn := func(fn func(t *testing.T, r *Resolver, ctrl *gomock.Controller) (node Node, ctx Context, expectedErr string)) func(t *testing.T) { - t.Helper() - - ctrl := gomock.NewController(t) - c, cancel := context.WithCancel(context.Background()) - defer cancel() - r := newResolver(c, false, false) - node, ctx, expectedErr := fn(t, r, ctrl) - return func(t *testing.T) { - t.Helper() - - buf := &BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - } - err := r.resolveNode(&ctx, node, nil, buf) - assert.EqualError(t, err, expectedErr) - ctrl.Finish() - } - } - - t.Run("Nullable empty object", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Nullable: true, - }, Context{ctx: context.Background()}, `null` - })) - t.Run("empty object", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &EmptyObject{}, Context{ctx: context.Background()}, `{}` - })) - t.Run("BigInt", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"n": 12345, "ns_small": "12346", "ns_big": "1152921504606846976"`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("n"), - Value: &BigInt{ - Path: []string{"n"}, - Nullable: false, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("ns_small"), - Value: &BigInt{ - Path: []string{"ns_small"}, - Nullable: false, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("ns_big"), - Value: &BigInt{ - Path: []string{"ns_big"}, - Nullable: false, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"n":12345,"ns_small":"12346","ns_big":"1152921504606846976"}` - })) - t.Run("object with null field", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("foo"), - Value: &Null{}, - }, - }, - }, Context{ctx: context.Background()}, `{"foo":null}` - })) - t.Run("default graphql object", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Nullable: true, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"data":null}` - })) - t.Run("graphql object with simple data source", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}}}` - })) - t.Run("skip single field should resolve to empty response", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"skip":true}`)}, `{"data":{"user":{}}}` - })) - t.Run("skip multiple fields should resolve to empty response", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"skip":true}`)}, `{"data":{"user":{}}}` - })) - t.Run("skip __typename field be possible", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__typename"), - Value: &String{ - Path: []string{"__typename"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"skip":true}`)}, `{"data":{"user":{"id":"1"}}}` - })) - t.Run("include __typename field be possible", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"},"__typename":"User"}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__typename"), - Value: &String{ - Path: []string{"__typename"}, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"include":true}`)}, `{"data":{"user":{"id":"1","__typename":"User"}}}` - })) - t.Run("include __typename field with false value", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"},"__typename":"User"}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("__typename"), - Value: &String{ - Path: []string{"__typename"}, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"include":false}`)}, `{"data":{"user":{"id":"1"}}}` - })) - t.Run("skip field when skip variable is true", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"skip":true}`)}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky"}}}}` - })) - t.Run("don't skip field when skip variable is false", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"skip":false}`)}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}}}` - })) - t.Run("don't skip field when skip variable is missing", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - SkipDirectiveDefined: true, - SkipVariableName: "skip", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{}`)}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}}}` - })) - t.Run("include field when include variable is true", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"include":true}`)}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}}}` - })) - t.Run("exclude field when include variable is false", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"include":false}`)}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky"}}}}` - })) - t.Run("exclude field when include variable is missing", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - IncludeDirectiveDefined: true, - IncludeVariableName: "include", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{}`)}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky"}}}}` - })) - t.Run("fetch with context variable resolver", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - mockDataSource := NewMockDataSource(ctrl) - mockDataSource.EXPECT(). - Load(gomock.Any(), []byte(`{"id":1}`), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - _, err = w.Write([]byte(`{"name":"Jens"}`)) - return - }). - Return(nil) - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: mockDataSource, - Input: `{"id":$$0$$}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"id":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"number"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}`), - }, - }, - }, - Variables: NewVariables(&ContextVariable{ - Path: []string{"id"}, - }), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"id":1}`)}, `{"name":"Jens"}` - })) - t.Run("resolve array of strings", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"strings": ["Alex", "true", "123"]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("strings"), - Value: &Array{ - Path: []string{"strings"}, - Item: &String{ - Nullable: false, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"strings":["Alex","true","123"]}` - })) - t.Run("resolve array of mixed scalar types", testErrFn(func(t *testing.T, r *Resolver, ctrl *gomock.Controller) (node Node, ctx Context, expectedErr string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"strings": ["Alex", "true", 123]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("strings"), - Value: &Array{ - Path: []string{"strings"}, - Item: &String{ - Nullable: false, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `invalid value type 'number' for path /data/strings/2, expecting string, got: 123. You can fix this by configuring this field as Int/Float/JSON Scalar` - })) - t.Run("resolve array items", func(t *testing.T) { - t.Run("with unescape json enabled", func(t *testing.T) { - t.Run("json encoded input", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"jsonList":["{\"field\":\"value\"}"]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("jsonList"), - Value: &Array{ - Path: []string{"jsonList"}, - Item: &String{ - Nullable: false, - UnescapeResponseJson: true, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"jsonList":[{"field":"value"}]}` - })) - t.Run("json input", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"jsonList":[{"field":"value"}]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("jsonList"), - Value: &Array{ - Path: []string{"jsonList"}, - Item: &String{ - Nullable: false, - UnescapeResponseJson: true, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"jsonList":[{"field":"value"}]}` - })) - }) - t.Run("with unescape json disabled", func(t *testing.T) { - t.Run("json encoded input", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"jsonList":["{\"field\":\"value\"}"]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("jsonList"), - Value: &Array{ - Path: []string{"jsonList"}, - Item: &String{ - Nullable: false, - UnescapeResponseJson: false, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"jsonList":["{\"field\":\"value\"}"]}` - })) - t.Run("json input", testErrFn(func(t *testing.T, r *Resolver, ctrl *gomock.Controller) (node Node, ctx Context, expectedErr string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"jsonList":[{"field":"value"}]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("jsonList"), - Value: &Array{ - Path: []string{"jsonList"}, - Item: &String{ - Nullable: false, - UnescapeResponseJson: false, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `invalid value type 'object' for path /data/jsonList/0, expecting string, got: {"field":"value"}. You can fix this by configuring this field as Int/Float/JSON Scalar` - })) - }) - }) - t.Run("resolve arrays", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"friends":[{"id":1,"name":"Alex"},{"id":2,"name":"Patric"}],"strings":["foo","bar","baz"],"integers":[123,456,789],"floats":[1.2,3.4,5.6],"booleans":[true,false,true]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("synchronousFriends"), - Value: &Array{ - Path: []string{"friends"}, - ResolveAsynchronous: false, - Nullable: true, - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("asynchronousFriends"), - Value: &Array{ - Path: []string{"friends"}, - ResolveAsynchronous: true, - Nullable: true, - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("nullableFriends"), - Value: &Array{ - Path: []string{"nonExistingField"}, - Nullable: true, - Item: &Object{}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("strings"), - Value: &Array{ - Path: []string{"strings"}, - ResolveAsynchronous: false, - Nullable: true, - Item: &String{ - Nullable: false, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("integers"), - Value: &Array{ - Path: []string{"integers"}, - ResolveAsynchronous: false, - Nullable: true, - Item: &Integer{ - Nullable: false, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("floats"), - Value: &Array{ - Path: []string{"floats"}, - ResolveAsynchronous: false, - Nullable: true, - Item: &Float{ - Nullable: false, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("booleans"), - Value: &Array{ - Path: []string{"booleans"}, - ResolveAsynchronous: false, - Nullable: true, - Item: &Boolean{ - Nullable: false, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"synchronousFriends":[{"id":1,"name":"Alex"},{"id":2,"name":"Patric"}],"asynchronousFriends":[{"id":1,"name":"Alex"},{"id":2,"name":"Patric"}],"nullableFriends":null,"strings":["foo","bar","baz"],"integers":[123,456,789],"floats":[1.2,3.4,5.6],"booleans":[true,false,true]}` - })) - t.Run("array response from data source", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`[{"__typename":"Dog","name":"Woofie"},{"__typename":"Cat","name":"Mietzie"}]`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pets"), - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - OnTypeNames: [][]byte{[]byte("Dog")}, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `{"pets":[{"name":"Woofie"}]}` - })) - t.Run("non null object with field condition can be null", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"__typename":"Dog","name":"Woofie"}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("cat"), - Value: &Object{ - Nullable: false, - Fields: []*Field{ - { - OnTypeNames: [][]byte{[]byte("Cat")}, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `{}` - })) - t.Run("object with multiple type conditions", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"data":{"namespaceCreate":{"__typename":"Error","code":"UserAlreadyHasPersonalNamespace","message":""}}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("data"), - Value: &Object{ - Nullable: false, - Path: []string{"data"}, - Fields: []*Field{ - { - Name: []byte("namespaceCreate"), - Value: &Object{ - Path: []string{"namespaceCreate"}, - Fields: []*Field{ - { - Name: []byte("namespace"), - OnTypeNames: [][]byte{[]byte("NamespaceCreated")}, - Value: &Object{ - Path: []string{"namespace"}, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Nullable: false, - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Nullable: false, - Path: []string{"name"}, - }, - }, - }, - }, - }, - { - Name: []byte("code"), - OnTypeNames: [][]byte{[]byte("Error")}, - Value: &String{ - Nullable: false, - Path: []string{"code"}, - }, - }, - { - Name: []byte("message"), - OnTypeNames: [][]byte{[]byte("Error")}, - Value: &String{ - Nullable: false, - Path: []string{"message"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `{"data":{"namespaceCreate":{"code":"UserAlreadyHasPersonalNamespace","message":""}}}` - })) - t.Run("resolve fieldsets based on __typename", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"pets":[{"__typename":"Dog","name":"Woofie"},{"__typename":"Cat","name":"Mietzie"}]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pets"), - Value: &Array{ - Path: []string{"pets"}, - Item: &Object{ - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - OnTypeNames: [][]byte{[]byte("Dog")}, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `{"pets":[{"name":"Woofie"}]}` - })) - - t.Run("resolve fieldsets based on __typename when field is Nullable", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"pet":{"id": "1", "detail": null}}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: false, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: false, - Name: []byte("detail"), - Value: &Object{ - Path: []string{"detail"}, - Nullable: true, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: false, - OnTypeNames: [][]byte{[]byte("Dog")}, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `{"pet":{"id":"1","detail":null}}` - })) - - t.Run("resolve fieldsets asynchronous based on __typename", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"pets":[{"__typename":"Dog","name":"Woofie"},{"__typename":"Cat","name":"Mietzie"}]}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pets"), - Value: &Array{ - ResolveAsynchronous: true, - Path: []string{"pets"}, - Item: &Object{ - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - OnTypeNames: [][]byte{[]byte("Dog")}, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, - `{"pets":[{"name":"Woofie"}]}` - })) - t.Run("parent object variables", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - mockDataSource := NewMockDataSource(ctrl) - mockDataSource.EXPECT(). - Load(gomock.Any(), gomock.GotFormatterAdapter(gotBytesFormatter{}, matchBytes(`{"id":1}`)), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - _, err = w.Write([]byte(`{"name":"Woofie"}`)) - return - }). - Return(nil) - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":1,"name":"Jens"}`), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("pet"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: mockDataSource, - Input: `{"id":$$0$$}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"id":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewGraphQLVariableRenderer(`{"type":"number"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}`), - }, - }, - }, - Variables: NewVariables(&ObjectVariable{ - Path: []string{"id"}, - }), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"id":1,"name":"Jens","pet":{"name":"Woofie"}}` - })) - t.Run("with unescape json enabled", func(t *testing.T) { - t.Run("json object within a string", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON object within a string - DataSource: FakeDataSource(`{"data":"{ \"hello\": \"world\", \"numberAsString\": \"1\", \"number\": 1, \"bool\": true, \"null\": null, \"array\": [1,2,3], \"object\": {\"key\": \"value\"} }"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a JSON object - }, Context{ctx: context.Background()}, `{"data":{ "hello": "world", "numberAsString": "1", "number": 1, "bool": true, "null": null, "array": [1,2,3], "object": {"key": "value"} }}` - })) - t.Run("json array within a string", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON array within a string - DataSource: FakeDataSource(`{"data": "[1, 2, 3]"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a JSON array - }, Context{ctx: context.Background()}, `{"data":[1, 2, 3]}` - })) - t.Run("string with array and objects brackets", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a string with array and object brackets - DataSource: FakeDataSource(`{"data":"hi[1beep{2}]"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a string - }, Context{ctx: context.Background()}, `{"data":"hi[1beep{2}]"}` - })) - t.Run("plain scalar values within a string", func(t *testing.T) { - t.Run("boolean", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON boolean within a string - DataSource: FakeDataSource(`{"data": "true"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - HasBuffer: true, - }, - }, - // expected output is a string - }, Context{ctx: context.Background()}, `{"data":"true"}` - })) - t.Run("int", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON number within a string - DataSource: FakeDataSource(`{"data": "1"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a string - }, Context{ctx: context.Background()}, `{"data":"1"}` - })) - t.Run("float", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON number within a string - DataSource: FakeDataSource(`{"data": "2.0"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a string - }, Context{ctx: context.Background()}, `{"data":"2.0"}` - })) - t.Run("null", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON number within a string - DataSource: FakeDataSource(`{"data": "null"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a string - }, Context{ctx: context.Background()}, `{"data":"null"}` - })) - t.Run("string", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"data": "hello world"}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expect data value to be valid JSON string - }, Context{ctx: context.Background()}, `{"data":"hello world"}` - })) - }) - t.Run("plain scalar values as is", func(t *testing.T) { - t.Run("boolean", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON boolean within a string - DataSource: FakeDataSource(`{"data": true}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - HasBuffer: true, - }, - }, - // expected output is a JSON boolean - }, Context{ctx: context.Background()}, `{"data":true}` - })) - t.Run("int", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON number within a string - DataSource: FakeDataSource(`{"data": 1}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a JSON boolean - }, Context{ctx: context.Background()}, `{"data":1}` - })) - t.Run("float", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - // Datasource returns a JSON number within a string - DataSource: FakeDataSource(`{"data": 2.0}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expected output is a JSON boolean - }, Context{ctx: context.Background()}, `{"data":2.0}` - })) - t.Run("null", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"data": null}`), - }, - Nullable: false, - Fields: []*Field{ - { - Name: []byte("data"), - // Value is a string and unescape json is enabled - Value: &String{ - Path: []string{"data"}, - Nullable: true, - UnescapeResponseJson: true, - IsTypeName: false, - }, - Position: Position{ - Line: 2, - Column: 3, - }, - HasBuffer: true, - }, - }, - // expect data value to be valid JSON string - }, Context{ctx: context.Background()}, `{"data":null}` - })) - }) - }) - - t.Run("custom", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id": "1"}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &CustomNode{ - CustomResolve: customResolver{}, - Path: []string{"id"}, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"id":1}` - })) - t.Run("custom nullable", testErrFn(func(t *testing.T, r *Resolver, ctrl *gomock.Controller) (node Node, ctx Context, expectedErr string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id": null}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &CustomNode{ - CustomResolve: customErrResolve{}, - Path: []string{"id"}, - Nullable: false, - }, - }, - }, - }, Context{ctx: context.Background()}, errNonNullableFieldValueIsNull.Error() - })) - t.Run("custom error", testErrFn(func(t *testing.T, r *Resolver, ctrl *gomock.Controller) (node Node, ctx Context, expectedErr string) { - return &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id": "1"}`), - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &CustomNode{ - CustomResolve: customErrResolve{}, - Path: []string{"id"}, - }, - }, - }, - }, Context{ctx: context.Background()}, `failed to resolve value type string for path /data/id via custom resolver` - })) -} - -func TestResolver_WithHooks(t *testing.T) { - testFn := func(enableSingleFlight bool, enableDataLoader bool, fn func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string)) func(t *testing.T) { - ctrl := gomock.NewController(t) - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - r := newResolver(rCtx, enableSingleFlight, enableDataLoader) - node, ctx, expectedOutput := fn(t, ctrl) - return func(t *testing.T) { - buf := &BufPair{ - Data: fastbuffer.New(), - Errors: fastbuffer.New(), - } - err := r.resolveNode(&ctx, node, nil, buf) - assert.Equal(t, buf.Errors.String(), "", "want error buf to be empty") - assert.NoError(t, err) - assert.Equal(t, expectedOutput, buf.Data.String()) - ctrl.Finish() - } - } - t.Run("resolve with hooks", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node Node, ctx Context, expectedOutput string) { - - pathEq := func(expected string) gomock.Matcher { - return hookContextPathMatcher{path: expected} - } - - beforeFetch := NewMockBeforeFetchHook(ctrl) - beforeFetch.EXPECT().OnBeforeFetch(pathEq("/data/user"), []byte("fakeInput")).Return() - afterFetch := NewMockAfterFetchHook(ctrl) - afterFetch.EXPECT().OnData(pathEq("/data/user"), []byte(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), false).Return() - return &Object{ - Fields: []*Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}`), - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte("fakeInput"), - }, - }, - }, - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("registered"), - Value: &Boolean{ - Path: []string{"registered"}, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("pet"), - Value: &Object{ - Path: []string{"pet"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("kind"), - Value: &String{ - Path: []string{"kind"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), beforeFetchHook: beforeFetch, afterFetchHook: afterFetch}, `{"data":{"user":{"id":"1","name":"Jens","registered":true,"pet":{"name":"Barky","kind":"Dog"}}}}` - })) - -} - -func TestResolver_ResolveGraphQLResponse(t *testing.T) { - testFn := func(enableSingleFlight bool, enableDataLoader bool, fn func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string)) func(t *testing.T) { - t.Helper() - - ctrl := gomock.NewController(t) - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - r := newResolver(rCtx, enableSingleFlight, enableDataLoader) - node, ctx, expectedOutput := fn(t, ctrl) - return func(t *testing.T) { - t.Helper() - - buf := &bytes.Buffer{} - err := r.ResolveGraphQLResponse(&ctx, node, nil, buf) - assert.NoError(t, err) - assert.Equal(t, expectedOutput, buf.String()) - ctrl.Finish() - } - } - testFnWithError := func(enableSingleFlight bool, enableDataLoader bool, fn func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedErrorMessage string)) func(t *testing.T) { - t.Helper() - - ctrl := gomock.NewController(t) - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - r := newResolver(rCtx, enableSingleFlight, enableDataLoader) - node, ctx, expectedOutput := fn(t, ctrl) - return func(t *testing.T) { - t.Helper() - - buf := &bytes.Buffer{} - err := r.ResolveGraphQLResponse(&ctx, node, nil, buf) - assert.Error(t, err, expectedOutput) - ctrl.Finish() - } - } - t.Run("empty graphql response", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: true, - }, - }, Context{ctx: context.Background()}, `{"data":null}` - })) - t.Run("__typename without renaming", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":1,"name":"Jannik","__typename":"User","rewritten":"User"}`), - }, - Fields: []*Field{ - { - Name: []byte("id"), - HasBuffer: true, - BufferID: 0, - Value: &Integer{ - Path: []string{"id"}, - Nullable: false, - }, - }, - { - Name: []byte("name"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"name"}, - Nullable: false, - }, - }, - { - Name: []byte("__typename"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("aliased"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("rewritten"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"rewritten"}, - Nullable: false, - IsTypeName: true, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"data":{"user":{"id":1,"name":"Jannik","__typename":"User","aliased":"User","rewritten":"User"}}}` - })) - t.Run("__typename with renaming", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Fields: []*Field{ - { - Name: []byte("user"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":1,"name":"Jannik","__typename":"User","rewritten":"User"}`), - }, - Fields: []*Field{ - { - Name: []byte("id"), - HasBuffer: true, - BufferID: 0, - Value: &Integer{ - Path: []string{"id"}, - Nullable: false, - }, - }, - { - Name: []byte("name"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"name"}, - Nullable: false, - }, - }, - { - Name: []byte("__typename"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("aliased"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"__typename"}, - Nullable: false, - IsTypeName: true, - }, - }, - { - Name: []byte("rewritten"), - HasBuffer: true, - BufferID: 0, - Value: &String{ - Path: []string{"rewritten"}, - Nullable: false, - IsTypeName: true, - }, - }, - }, - }, - }, - }, - }, - }, Context{ - ctx: context.Background(), - RenameTypeNames: []RenameTypeName{ - { - From: []byte("User"), - To: []byte("namespaced_User"), - }, - }, - }, `{"data":{"user":{"id":1,"name":"Jannik","__typename":"namespaced_User","aliased":"namespaced_User","rewritten":"namespaced_User"}}}` - })) - t.Run("empty graphql response for not nullable query field", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("country"), - Position: Position{ - Line: 3, - Column: 4, - }, - Value: &Object{ - Nullable: false, - Path: []string{"country"}, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Nullable: true, - Path: []string{"name"}, - }, - Position: Position{ - Line: 4, - Column: 5, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"errors":[{"message":"unable to resolve","locations":[{"line":3,"column":4}],"path":["country"]}],"data":null}` - })) - t.Run("fetch with simple error", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - mockDataSource := NewMockDataSource(ctrl) - mockDataSource.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - pair := NewBufPair() - pair.WriteErr([]byte("errorMessage"), nil, nil, nil) - return writeGraphqlResponse(pair, w, false) - }) - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: mockDataSource, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"errors":[{"message":"errorMessage"}],"data":{"name":null}}` - })) - t.Run("nested fetch error for non-nullable field", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - mockDataSource := NewMockDataSource(ctrl) - mockDataSource.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - pair := NewBufPair() - pair.WriteErr([]byte("errorMessage"), nil, nil, nil) - return writeGraphqlResponse(pair, w, false) - }) - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"id":1}`), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nestedObject"), - Value: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 1, - DataSource: mockDataSource, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 1, - Name: []byte("foo"), - Value: &String{ - Path: []string{"foo"}, - Nullable: false, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"errors":[{"message":"errorMessage"},{"message":"unable to resolve","locations":[{"line":0,"column":0}],"path":["nestedObject"]}],"data":null}` - })) - t.Run("fetch with two Errors", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - mockDataSource := NewMockDataSource(ctrl) - mockDataSource.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - pair := NewBufPair() - pair.WriteErr([]byte("errorMessage1"), nil, nil, nil) - pair.WriteErr([]byte("errorMessage2"), nil, nil, nil) - return writeGraphqlResponse(pair, w, false) - }). - Return(nil) - return &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: mockDataSource, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - Nullable: true, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"errors":[{"message":"errorMessage1"},{"message":"errorMessage2"}],"data":{"name":null}}` - })) - t.Run("not nullable object in nullable field", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"nullable_field": null}`), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nullableField"), - Value: &Object{ - Nullable: true, - Path: []string{"nullable_field"}, - Fields: []*Field{ - { - Name: []byte("notNullableField"), - Value: &Object{ - Nullable: false, - Path: []string{"not_nullable_field"}, - Fields: []*Field{ - { - Name: []byte("someField"), - Value: &String{ - Nullable: false, - Path: []string{"some_field"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"data":{"nullableField":null}}` - })) - t.Run("null field should bubble up to parent with error", testFnWithError(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: true, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`[{"id":1},{"id":2},{"id":3}]`), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("stringObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("stringField"), - Value: &String{ - Nullable: false, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("integerObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("integerField"), - Value: &Integer{ - Nullable: false, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("floatObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("floatField"), - Value: &Float{ - Nullable: false, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("booleanObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("booleanField"), - Value: &Boolean{ - Nullable: false, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("objectObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("objectField"), - Value: &Object{ - Nullable: false, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("arrayObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("arrayField"), - Value: &Array{ - Nullable: false, - Item: &String{ - Nullable: false, - Path: []string{"nonExisting"}, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("asynchronousArrayObject"), - Value: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("arrayField"), - Value: &Array{ - Nullable: false, - ResolveAsynchronous: true, - Item: &String{ - Nullable: false, - Path: []string{"nonExisting"}, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nullableArray"), - Value: &Array{ - Nullable: true, - Item: &String{ - Nullable: false, - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `invalid value type 'array' for path /data/stringObject/stringField, expecting string, got: [{"id":1},{"id":2},{"id":3}]. You can fix this by configuring this field as Int/Float Scalar` - })) - t.Run("empty nullable array should resolve correctly", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: true, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`[]`), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nullableArray"), - Value: &Array{ - Nullable: true, - Item: &Object{ - Nullable: false, - Fields: []*Field{ - { - Name: []byte("foo"), - Value: &String{ - Nullable: false, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"data":{"nullableArray":[]}}` - })) - t.Run("empty not nullable array should resolve correctly", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"some_path": []}`), - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("notNullableArray"), - Value: &Array{ - Path: []string{"some_path"}, - Nullable: false, - Item: &Object{ - Nullable: false, - Fields: []*Field{ - { - Name: []byte("foo"), - Value: &String{ - Nullable: false, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"data":{"notNullableArray":[]}}` - })) - t.Run("when data null not nullable array should resolve to data null and errors", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource(`{"data":null}`), - ProcessResponseConfig: ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nonNullArray"), - Value: &Array{ - Nullable: false, - Item: &Object{ - Nullable: false, - Fields: []*Field{ - { - Name: []byte("foo"), - Value: &String{ - Nullable: false, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 0, - Name: []byte("nullableArray"), - Value: &Array{ - Nullable: true, - Item: &Object{ - Nullable: false, - Fields: []*Field{ - { - Name: []byte("foo"), - Value: &String{ - Nullable: false, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"errors":[{"message":"unable to resolve","locations":[{"line":0,"column":0}]}],"data":null}` - })) - t.Run("when data null and errors present not nullable array should result to null data upstream error and resolve error", testFn(false, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - return &GraphQLResponse{ - Data: &Object{ - Nullable: false, - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: FakeDataSource( - `{"errors":[{"message":"Could not get a name","locations":[{"line":3,"column":5}],"path":["todos",0,"name"]}],"data":null}`), - ProcessResponseConfig: ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("todos"), - Value: &Array{ - Nullable: false, - Item: &Object{ - Nullable: false, - Fields: []*Field{ - { - Name: []byte("name"), - Value: &String{ - Nullable: false, - }, - Position: Position{ - Line: 100, - Column: 777, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background()}, `{"errors":[{"message":"Could not get a name","locations":[{"line":3,"column":5}],"path":["todos",0,"name"]},{"message":"unable to resolve","locations":[{"line":0,"column":0}]}],"data":null}` - })) - t.Run("complex GraphQL Server plan", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - serviceOne := NewMockDataSource(ctrl) - serviceOne.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"url":"https://service.one","body":{"query":"query($firstArg: String, $thirdArg: Int){serviceOne(serviceOneArg: $firstArg){fieldOne} anotherServiceOne(anotherServiceOneArg: $thirdArg){fieldOne} reusingServiceOne(reusingServiceOneArg: $firstArg){fieldOne}}","variables":{"thirdArg":123,"firstArg":"firstArgValue"}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"serviceOne":{"fieldOne":"fieldOneValue"},"anotherServiceOne":{"fieldOne":"anotherFieldOneValue"},"reusingServiceOne":{"fieldOne":"reUsingFieldOneValue"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - serviceTwo := NewMockDataSource(ctrl) - serviceTwo.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"url":"https://service.two","body":{"query":"query($secondArg: Boolean, $fourthArg: Float){serviceTwo(serviceTwoArg: $secondArg){fieldTwo} secondServiceTwo(secondServiceTwoArg: $fourthArg){fieldTwo}}","variables":{"fourthArg":12.34,"secondArg":true}}}` - assert.Equal(t, expected, actual) - - pair := NewBufPair() - pair.Data.WriteString(`{"serviceTwo":{"fieldTwo":"fieldTwoValue"},"secondServiceTwo":{"fieldTwo":"secondFieldTwoValue"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - nestedServiceOne := NewMockDataSource(ctrl) - nestedServiceOne.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"url":"https://service.one","body":{"query":"{serviceOne {fieldOne}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"serviceOne":{"fieldOne":"fieldOneValue"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - return &GraphQLResponse{ - Data: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - BufferId: 0, - Input: `{"url":"https://service.one","body":{"query":"query($firstArg: String, $thirdArg: Int){serviceOne(serviceOneArg: $firstArg){fieldOne} anotherServiceOne(anotherServiceOneArg: $thirdArg){fieldOne} reusingServiceOne(reusingServiceOneArg: $firstArg){fieldOne}}","variables":{"thirdArg":$$1$$,"firstArg":$$0$$}}}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"url":"https://service.one","body":{"query":"query($firstArg: String, $thirdArg: Int){serviceOne(serviceOneArg: $firstArg){fieldOne} anotherServiceOne(anotherServiceOneArg: $thirdArg){fieldOne} reusingServiceOne(reusingServiceOneArg: $firstArg){fieldOne}}","variables":{"thirdArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"thirdArg"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"number"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`,"firstArg":"`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"firstArg"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"string"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`"}}}`), - }, - }, - }, - DataSource: serviceOne, - Variables: NewVariables( - &ContextVariable{ - Path: []string{"firstArg"}, - }, - &ContextVariable{ - Path: []string{"thirdArg"}, - }, - ), - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - &SingleFetch{ - BufferId: 1, - Input: `{"url":"https://service.two","body":{"query":"query($secondArg: Boolean, $fourthArg: Float){serviceTwo(serviceTwoArg: $secondArg){fieldTwo} secondServiceTwo(secondServiceTwoArg: $fourthArg){fieldTwo}}","variables":{"fourthArg":$$1$$,"secondArg":$$0$$}}}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"url":"https://service.two","body":{"query":"query($secondArg: Boolean, $fourthArg: Float){serviceTwo(serviceTwoArg: $secondArg){fieldTwo} secondServiceTwo(secondServiceTwoArg: $fourthArg){fieldTwo}}","variables":{"fourthArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"fourthArg"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"number"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`,"secondArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"secondArg"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"boolean"}`), - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}}}`), - }, - }, - }, - DataSource: serviceTwo, - Variables: NewVariables( - &ContextVariable{ - Path: []string{"secondArg"}, - }, - &ContextVariable{ - Path: []string{"fourthArg"}, - }, - ), - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - }, - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("serviceOne"), - Value: &Object{ - Path: []string{"serviceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - { - BufferID: 1, - HasBuffer: true, - Name: []byte("serviceTwo"), - Value: &Object{ - Path: []string{"serviceTwo"}, - Fetch: &SingleFetch{ - BufferId: 2, - Input: `{"url":"https://service.one","body":{"query":"{serviceOne {fieldOne}}"}}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"url":"https://service.one","body":{"query":"{serviceOne {fieldOne}}"}}`), - }, - }, - }, - DataSource: nestedServiceOne, - Variables: Variables{}, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - Name: []byte("fieldTwo"), - Value: &String{ - Path: []string{"fieldTwo"}, - }, - }, - { - BufferID: 2, - HasBuffer: true, - Name: []byte("serviceOneResponse"), - Value: &Object{ - Path: []string{"serviceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("anotherServiceOne"), - Value: &Object{ - Path: []string{"anotherServiceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - { - BufferID: 1, - HasBuffer: true, - Name: []byte("secondServiceTwo"), - Value: &Object{ - Path: []string{"secondServiceTwo"}, - Fields: []*Field{ - { - Name: []byte("fieldTwo"), - Value: &String{ - Path: []string{"fieldTwo"}, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("reusingServiceOne"), - Value: &Object{ - Path: []string{"reusingServiceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"firstArg":"firstArgValue","thirdArg":123,"secondArg": true, "fourthArg": 12.34}`)}, `{"data":{"serviceOne":{"fieldOne":"fieldOneValue"},"serviceTwo":{"fieldTwo":"fieldTwoValue","serviceOneResponse":{"fieldOne":"fieldOneValue"}},"anotherServiceOne":{"fieldOne":"anotherFieldOneValue"},"secondServiceTwo":{"fieldTwo":"secondFieldTwoValue"},"reusingServiceOne":{"fieldOne":"reUsingFieldOneValue"}}}` - })) - t.Run("federation", testFn(true, false, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"me": {"id": "1234","username": "Me","__typename": "User"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - reviewsService := NewMockDataSource(ctrl) - reviewsService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"reviews": [{"body": "A highly effective form of birth control.","product": {"upc": "top-1","__typename": "Product"}},{"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product": {"upc": "top-1","__typename": "Product"}}]}`) - return writeGraphqlResponse(pair, w, false) - }) - - productServiceCallCount := 0 - - productService := NewMockDataSource(ctrl) - productService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - productServiceCallCount++ - switch productServiceCallCount { - case 1: - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"name": "Trilby"}`) - return writeGraphqlResponse(pair, w, false) - case 2: - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"name": "Trilby"}`) - return writeGraphqlResponse(pair, w, false) - } - return - }). - Return(nil).Times(2) - - return &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"User"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: reviewsService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &String{ - Path: []string{"username"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &Object{ - Path: []string{"product"}, - Fetch: &SingleFetch{ - BufferId: 2, - DataSource: productService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - Name: []byte("upc"), - Value: &String{ - Path: []string{"upc"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: nil}, `{"data":{"me":{"id":"1234","username":"Me","reviews":[{"body":"A highly effective form of birth control.","product":{"upc":"top-1","name":"Trilby"}},{"body":"Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product":{"upc":"top-1","name":"Trilby"}}]}}}` - })) - t.Run("federation with enabled dataloader", testFn(true, true, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"me": {"id": "1234","username": "Me","__typename": "User"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - reviewBatchFactory := NewMockDataSourceBatchFactory(ctrl) - reviewBatchFactory.EXPECT(). - CreateBatch([][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}`), - }). - Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}`, - []resultedBufPair{ - {data: `{"reviews": [{"body": "A highly effective form of birth control.","product": {"upc": "top-1","__typename": "Product"}},{"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product": {"upc": "top-2","__typename": "Product"}}]}`}, - }), nil) - reviewsService := NewMockDataSource(ctrl) - reviewsService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"reviews": [{"body": "A highly effective form of birth control.","product": {"upc": "top-1","__typename": "Product"}},{"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product": {"upc": "top-2","__typename": "Product"}}]}`) - return writeGraphqlResponse(pair, w, false) - }) - - productBatchFactory := NewMockDataSourceBatchFactory(ctrl) - productBatchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - []resultedBufPair{ - {data: `{"name": "Trilby"}`}, - {data: `{"name": "Fedora"}`}, - }), nil) - productService := NewMockDataSource(ctrl) - productService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`[{"name": "Trilby"},{"name": "Fedora"}]`) - return writeGraphqlResponse(pair, w, false) - }) - - return &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &Object{ - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"User"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: reviewsService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - BatchFactory: reviewBatchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &String{ - Path: []string{"username"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &Object{ - Path: []string{"product"}, - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - DataSource: productService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - BatchFactory: productBatchFactory, - }, - Fields: []*Field{ - { - Name: []byte("upc"), - Value: &String{ - Path: []string{"upc"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: nil}, `{"data":{"me":{"id":"1234","username":"Me","reviews":[{"body":"A highly effective form of birth control.","product":{"upc":"top-1","name":"Trilby"}},{"body":"Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product":{"upc":"top-2","name":"Fedora"}}]}}}` - })) - t.Run("federation with null response", testFn(true, true, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"me": {"id": "1234","username": "Me","__typename": "User"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - reviewBatchFactory := NewMockDataSourceBatchFactory(ctrl) - reviewBatchFactory.EXPECT(). - CreateBatch([][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}`), - }). - Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}`, - []resultedBufPair{ - {data: `{"reviews":[{"body":"foo","product":{"upc":"top-1","__typename":"Product"}},{"body":"bar","product":{"upc":"top-2","__typename":"Product"}},{"body":"baz","product":null},{"body":"bat","product":{"upc":"top-4","__typename":"Product"}},{"body":"bal","product":{"upc":"top-5","__typename":"Product"}},{"body":"ban","product":{"upc":"top-6","__typename":"Product"}}]}`}, - }), nil) - reviewsService := NewMockDataSource(ctrl) - reviewsService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"reviews": [ - {"body": "foo","product": {"upc": "top-1","__typename": "Product"}}, - {"body": "bar","product": {"upc": "top-2","__typename": "Product"}}, - {"body": "baz","product": null}, - {"body": "bat","product": {"upc": "top-4","__typename": "Product"}}, - {"body": "bal","product": {"upc": "top-5","__typename": "Product"}}, - {"body": "ban","product": {"upc": "top-6","__typename": "Product"}} -]}`) - return writeGraphqlResponse(pair, w, false) - }) - - productBatchFactory := NewMockDataSourceBatchFactory(ctrl) - productBatchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`), - []byte("null"), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-4","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-5","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-6","__typename":"Product"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"},{"upc":"top-4","__typename":"Product"},{"upc":"top-5","__typename":"Product"},{"upc":"top-6","__typename":"Product"}]}}}`, - []resultedBufPair{ - {data: `{"name": "Trilby"}`}, - {data: `{"name": "Fedora"}`}, - {data: `null`}, - {data: `{"name": "Boater"}`}, - {data: `{"name": "Top Hat"}`}, - {data: `{"name": "Bowler"}`}, - }), nil) - productService := NewMockDataSource(ctrl) - productService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"},{"upc":"top-4","__typename":"Product"},{"upc":"top-5","__typename":"Product"},{"upc":"top-6","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`[{"name":"Trilby"},{"name":"Fedora"},{"name":"Boater"},{"name":"Top Hat"},{"name":"Bowler"}]`) - return writeGraphqlResponse(pair, w, false) - }) - - return &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &Object{ - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"User"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - DataSource: reviewsService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - BatchFactory: reviewBatchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &String{ - Path: []string{"username"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &Object{ - Nullable: true, - Path: []string{"product"}, - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - DataSource: productService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`,"__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - BatchFactory: productBatchFactory, - }, - Fields: []*Field{ - { - Name: []byte("upc"), - Value: &String{ - Path: []string{"upc"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, // ... `{"data":{"me":{"id":"1234","username":"Me","reviews":[{"body":"foo","product":{"upc":"top-1","name":"Trilby"}},{"body":"bar","product":{"upc":"top-2","name":"Fedora"}},{"body":"baz","product":null},{"body":"bat","product":null},{"body":"bal","product":{"upc":"top-5","name":"Boater"}},{"body":"ban","product":{"upc":"top-6","name":"Top Hat"}}]}}} - }, Context{ctx: context.Background(), Variables: nil}, `{"data":{"me":{"id":"1234","username":"Me","reviews":[{"body":"foo","product":{"upc":"top-1","name":"Trilby"}},{"body":"bar","product":{"upc":"top-2","name":"Fedora"}},{"body":"baz","product":null},{"body":"bat","product":{"upc":"top-4","name":"Boater"}},{"body":"bal","product":{"upc":"top-5","name":"Top Hat"}},{"body":"ban","product":{"upc":"top-6","name":"Bowler"}}]}}}` - })) - t.Run("federation with enabled dataloader and fetch error ", testFn(true, true, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"me": {"id": "1234","username": "Me","__typename": "User"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - reviewBatchFactory := NewMockDataSourceBatchFactory(ctrl) - reviewBatchFactory.EXPECT(). - CreateBatch([][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}`), - }). - Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}`, - []resultedBufPair{ - {data: `{"reviews": [{"body": "A highly effective form of birth control.","product": {"upc": "top-1","__typename": "Product"}},{"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product": {"upc": "top-2","__typename": "Product"}}]}`}, - }), nil) - reviewsService := NewMockDataSource(ctrl) - reviewsService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"1234","__typename":"User"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"reviews": [{"body": "A highly effective form of birth control.","product": {"upc": "top-1","__typename": "Product"}},{"body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product": {"upc": "top-2","__typename": "Product"}}]}`) - return writeGraphqlResponse(pair, w, false) - }) - - productBatchFactory := NewMockDataSourceBatchFactory(ctrl) - productBatchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"}]}}}`), - []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-2","__typename":"Product"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}`, - []resultedBufPair{{data: `null`, err: "errorMessage"}, {data: `null`}}), nil) - productService := NewMockDataSource(ctrl) - productService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"top-1","__typename":"Product"},{"upc":"top-2","__typename":"Product"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.WriteErr([]byte("errorMessage"), nil, nil, nil) - return writeGraphqlResponse(pair, w, false) - }) - - return &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &Object{ - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`","__typename":"User"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: reviewsService, - }, - BatchFactory: reviewBatchFactory, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &String{ - Path: []string{"username"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &Object{ - Path: []string{"product"}, - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - DataSource: productService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - Renderer: NewPlainVariableRendererWithValidation(`{"type":"string"}`), - }, - { - Data: []byte(`","__typename":"Product"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - BatchFactory: productBatchFactory, - }, - Fields: []*Field{ - { - Name: []byte("upc"), - Value: &String{ - Path: []string{"upc"}, - }, - }, - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: nil}, `{"errors":[{"message":"errorMessage"},{"message":"unable to resolve","locations":[{"line":0,"column":0}],"path":["me","reviews","0","product"]},{"message":"unable to resolve","locations":[{"line":0,"column":0}],"path":["me","reviews","1","product"]}],"data":{"me":{"id":"1234","username":"Me","reviews":[null,null]}}}` - })) - t.Run("federation with optional variable", testFn(true, true, func(t *testing.T, ctrl *gomock.Controller) (node *GraphQLResponse, ctx Context, expectedOutput string) { - userService := NewMockDataSource(ctrl) - userService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:8080/query","body":{"query":"{me {id}}"}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"me":{"id":"1234","__typename":"User"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - employeeBatchFactory := NewMockDataSourceBatchFactory(ctrl) - employeeBatchFactory.EXPECT(). - CreateBatch([][]byte{ - []byte(`{"method":"POST","url":"http://localhost:8081/query","body":{"query":"query($representations: [_Any!]!, $companyId: ID!){_entities(representations: $representations){... on User {employment(companyId: $companyId){id}}}}","variables":{"companyId":"abc123","representations":[{"id":"1234","__typename":"User"}]}}}`), - }). - Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:8081/query","body":{"query":"query($representations: [_Any!]!, $companyId: ID!){_entities(representations: $representations){... on User {employment(companyId: $companyId){id}}}}","variables":{"companyId":"abc123","representations":[{"id":"1234","__typename":"User"}]}}}`, - []resultedBufPair{ - {data: `{"employment": {"id": "xyz987"}}`}, - }), nil) - employeeService := NewMockDataSource(ctrl) - employeeService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:8081/query","body":{"query":"query($representations: [_Any!]!, $companyId: ID!){_entities(representations: $representations){... on User {employment(companyId: $companyId){id}}}}","variables":{"companyId":"abc123","representations":[{"id":"1234","__typename":"User"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"employment": {"id": "xyz987"}}`) - return writeGraphqlResponse(pair, w, false) - }) - - timeBatchFactory := NewMockDataSourceBatchFactory(ctrl) - timeBatchFactory.EXPECT(). - CreateBatch( - [][]byte{ - []byte(`{"method":"POST","url":"http://localhost:8082/query","body":{"query":"query($representations: [_Any!]!, $date: LocalTime){_entities(representations: $representations){... on Employee {times(date: $date){id employee {id} start end}}}}","variables":{"date":null,"representations":[{"id":"xyz987","__typename":"Employee"}]}}}`), - }, - ).Return(NewFakeDataSourceBatch( - `{"method":"POST","url":"http://localhost:8082/query","body":{"query":"query($representations: [_Any!]!, $date: LocalTime){_entities(representations: $representations){... on Employee {times(date: $date){id employee {id} start end}}}}","variables":{"date":null,"representations":[{"id":"xyz987","__typename":"Employee"}]}}}`, - []resultedBufPair{ - {data: `{"times":[{"id": "t1","employee":{"id":"xyz987"},"start":"2022-11-02T08:00:00","end":"2022-11-02T12:00:00"}]}`}, - }), nil) - timeService := NewMockDataSource(ctrl) - timeService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - DoAndReturn(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - expected := `{"method":"POST","url":"http://localhost:8082/query","body":{"query":"query($representations: [_Any!]!, $date: LocalTime){_entities(representations: $representations){... on Employee {times(date: $date){id employee {id} start end}}}}","variables":{"date":null,"representations":[{"id":"xyz987","__typename":"Employee"}]}}}` - assert.Equal(t, expected, actual) - pair := NewBufPair() - pair.Data.WriteString(`{"times":[{"id": "t1","employee":{"id":"xyz987"},"start":"2022-11-02T08:00:00","end":"2022-11-02T12:00:00"}]}`) - return writeGraphqlResponse(pair, w, false) - }) - - return &GraphQLResponse{ - Data: &Object{ - Fields: []*Field{ - { - Name: []byte("me"), - Value: &Object{ - Nullable: false, - Path: []string{"me"}, - Fields: []*Field{ - { - Name: []byte("employment"), - Value: &Object{ - Nullable: false, - Path: []string{"employment"}, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - Nullable: false, - }, - }, - { - Name: []byte("times"), - Value: &Array{ - Path: []string{"times"}, - Nullable: false, - Item: &Object{ - Nullable: true, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{Path: []string{"id"}}, - }, - { - Name: []byte("employee"), - Value: &Object{ - Path: []string{"employee"}, - Fields: []*Field{ - { - Name: []byte("id"), - Value: &String{ - Path: []string{"id"}, - }, - }, - }, - }, - }, - { - Name: []byte("start"), - Value: &String{Path: []string{"start"}}, - }, - { - Name: []byte("end"), - Value: &String{ - Path: []string{"end"}, - Nullable: true, - }, - }, - }, - }, - Stream: Stream{ - Enabled: false, - }, - }, - HasBuffer: true, - BufferID: 2, - }, - }, - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 2, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:8082/query","body":{"query":"query($representations: [_Any!]!, $date: LocalTime){_entities(representations: $representations){... on Employee {times(date: $date){id employee {id} start end}}}}","variables":{"date":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"date"}, - Renderer: NewJSONVariableRendererWithValidation(`{}`), - }, - { - Data: []byte(`,"representations":[{"id":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - { - Data: []byte(`,"__typename":"Employee"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - DataSource: timeService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - BatchFactory: timeBatchFactory, - }, - }, - HasBuffer: true, - BufferID: 1, - }, - }, - Fetch: &BatchFetch{ - Fetch: &SingleFetch{ - BufferId: 1, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:8081/query","body":{"query":"query($representations: [_Any!]!, $companyId: ID!){_entities(representations: $representations){... on User {employment(companyId: $companyId){id}}}}","variables":{"companyId":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"companyId"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - { - Data: []byte(`,"representations":[{"id":`), - SegmentType: StaticSegmentType, - }, - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewJSONVariableRendererWithValidation(`{"type":["string","integer"]}`), - }, - { - Data: []byte(`,"__typename":"User"}]}}}`), - SegmentType: StaticSegmentType, - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - DataSource: employeeService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - BatchFactory: employeeBatchFactory, - }, - }, - HasBuffer: true, - BufferID: 0, - }, - }, - Fetch: &SingleFetch{ - BufferId: 0, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:8080/query","body":{"query":"{me {id}}"}}`), - SegmentType: StaticSegmentType, - }, - }, - }, - DataSource: userService, - ProcessResponseConfig: ProcessResponseConfig{ - ExtractGraphqlResponse: true, - }, - }, - }, - }, Context{ctx: context.Background(), Variables: []byte(`{"companyId":"abc123","date":null}`)}, `{"data":{"me":{"employment":{"id":"xyz987","times":[{"id":"t1","employee":{"id":"xyz987"},"start":"2022-11-02T08:00:00","end":"2022-11-02T12:00:00"}]}}}}` - })) -} - -func TestResolver_WithHeader(t *testing.T) { - cases := []struct { - name, header, variable string - }{ - {"header and variable are of equal case", "Authorization", "Authorization"}, - {"header is downcased and variable is uppercased", "authorization", "AUTHORIZATION"}, - {"header is uppercasesed and variable is downcased", "AUTHORIZATION", "authorization"}, - } - - for _, tc := range cases { - t.Run(tc.name, func(t *testing.T) { - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - resolver := newResolver(rCtx, false, false) - - header := make(http.Header) - header.Set(tc.header, "foo") - ctx := &Context{ - ctx: context.Background(), - Request: Request{ - Header: header, - }, - } - - ctrl := gomock.NewController(t) - fakeService := NewMockDataSource(ctrl) - fakeService.EXPECT(). - Load(gomock.Any(), gomock.Any(), gomock.AssignableToTypeOf(&bytes.Buffer{})). - Do(func(ctx context.Context, input []byte, w io.Writer) (err error) { - actual := string(input) - assert.Equal(t, "foo", actual) - _, err = w.Write([]byte(`{"bar":"baz"}`)) - return - }). - Return(nil) - - out := &bytes.Buffer{} - res := &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - BufferId: 0, - DataSource: fakeService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: HeaderVariableKind, - VariableSourcePath: []string{tc.variable}, - }, - }, - }, - }, - Fields: []*Field{ - { - Name: []byte("bar"), - Value: &String{ - Path: []string{"bar"}, - }, - HasBuffer: true, - BufferID: 0, - }, - }, - }, - } - err := resolver.ResolveGraphQLResponse(ctx, res, nil, out) - assert.NoError(t, err) - assert.Equal(t, `{"data":{"bar":"baz"}}`, out.String()) - }) - } -} - -type TestFlushWriter struct { - flushed []string - buf bytes.Buffer -} - -func (t *TestFlushWriter) Write(p []byte) (n int, err error) { - return t.buf.Write(p) -} - -func (t *TestFlushWriter) Flush() { - t.flushed = append(t.flushed, t.buf.String()) - t.buf.Reset() -} - -func FakeStream(cancelFunc func(), messageFunc func(count int) (message string, ok bool)) *_fakeStream { - return &_fakeStream{ - cancel: cancelFunc, - messageFunc: messageFunc, - } -} - -type _fakeStream struct { - cancel context.CancelFunc - messageFunc func(counter int) (message string, ok bool) -} - -func (f *_fakeStream) Start(ctx context.Context, input []byte, next chan<- []byte) error { - go func() { - time.Sleep(time.Millisecond) - count := 0 - for { - if count == 3 { - f.cancel() - return - } - message, ok := f.messageFunc(count) - next <- []byte(message) - if !ok { - f.cancel() - return - } - count++ - } - }() - return nil -} - -func TestResolver_ResolveGraphQLSubscription(t *testing.T) { - - setup := func(ctx context.Context, stream SubscriptionDataSource) (*Resolver, *GraphQLSubscription, *TestFlushWriter) { - plan := &GraphQLSubscription{ - Trigger: GraphQLSubscriptionTrigger{ - Source: stream, - ProcessResponseConfig: ProcessResponseConfig{ExtractGraphqlResponse: true}, - }, - Response: &GraphQLResponse{ - Data: &Object{ - Fields: []*Field{ - { - Name: []byte("counter"), - Value: &Integer{ - Path: []string{"counter"}, - }, - }, - }, - }, - }, - } - - out := &TestFlushWriter{ - buf: bytes.Buffer{}, - } - - return newResolver(ctx, false, false), plan, out - } - - t.Run("should return errors if the upstream data has errors", func(t *testing.T) { - c, cancel := context.WithCancel(context.Background()) - defer cancel() - - fakeStream := FakeStream(cancel, func(count int) (message string, ok bool) { - return `{"errors":[{"message":"Validation error occurred","locations":[{"line":1,"column":1}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"data":null}`, false - }) - - resolver, plan, out := setup(c, fakeStream) - - ctx := Context{ - ctx: c, - } - - err := resolver.ResolveGraphQLSubscription(&ctx, plan, out) - assert.NoError(t, err) - assert.Equal(t, 1, len(out.flushed)) - assert.Equal(t, `{"errors":[{"message":"unable to resolve","locations":[{"line":0,"column":0}]},{"message":"Validation error occurred","locations":[{"line":1,"column":1}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}],"data":null}`, out.flushed[0]) - }) - - t.Run("should return an error if the data source has not been defined", func(t *testing.T) { - c, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver, plan, out := setup(c, nil) - - ctx := Context{ - ctx: c, - } - - err := resolver.ResolveGraphQLSubscription(&ctx, plan, out) - assert.NoError(t, err) - assert.Equal(t, 1, len(out.flushed)) - assert.Equal(t, `{"errors":[{"message":"no data source found"}]}`, out.flushed[0]) - }) - - t.Run("should successfully get result from upstream", func(t *testing.T) { - c, cancel := context.WithCancel(context.Background()) - defer cancel() - - fakeStream := FakeStream(cancel, func(count int) (message string, ok bool) { - return fmt.Sprintf(`{"data":{"counter":%d}}`, count), true - }) - - resolver, plan, out := setup(c, fakeStream) - - ctx := Context{ - ctx: c, - } - - err := resolver.ResolveGraphQLSubscription(&ctx, plan, out) - assert.NoError(t, err) - assert.Equal(t, 3, len(out.flushed)) - assert.Equal(t, `{"data":{"counter":0}}`, out.flushed[0]) - assert.Equal(t, `{"data":{"counter":1}}`, out.flushed[1]) - assert.Equal(t, `{"data":{"counter":2}}`, out.flushed[2]) - }) -} - -func BenchmarkResolver_ResolveNode(b *testing.B) { - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := newResolver(rCtx, true, false) - - serviceOneDS := FakeDataSource(`{"serviceOne":{"fieldOne":"fieldOneValue"},"anotherServiceOne":{"fieldOne":"anotherFieldOneValue"},"reusingServiceOne":{"fieldOne":"reUsingFieldOneValue"}}`) - serviceTwoDS := FakeDataSource(`{"serviceTwo":{"fieldTwo":"fieldTwoValue"},"secondServiceTwo":{"fieldTwo":"secondFieldTwoValue"}}`) - nestedServiceOneDS := FakeDataSource(`{"serviceOne":{"fieldOne":"fieldOneValue"}}`) - - plan := &GraphQLResponse{ - Data: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - BufferId: 0, - Input: `{"url":"https://service.one","body":{"query":"query($firstArg: String, $thirdArg: Int){serviceOne(serviceOneArg: $firstArg){fieldOne} anotherServiceOne(anotherServiceOneArg: $thirdArg){fieldOne} reusingServiceOne(reusingServiceOneArg: $firstArg){fieldOne}}","variables":{"thirdArg":$$1$$,"firstArg":$$0$$}}}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"url":"https://service.one","body":{"query":"query($firstArg: String, $thirdArg: Int){serviceOne(serviceOneArg: $firstArg){fieldOne} anotherServiceOne(anotherServiceOneArg: $thirdArg){fieldOne} reusingServiceOne(reusingServiceOneArg: $firstArg){fieldOne}}","variables":{"thirdArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"thirdArg"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`,"firstArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"firstArg"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}}}`), - }, - }, - }, - DataSource: serviceOneDS, - Variables: NewVariables( - &ContextVariable{ - Path: []string{"firstArg"}, - }, - &ContextVariable{ - Path: []string{"thirdArg"}, - }, - ), - }, - &SingleFetch{ - BufferId: 1, - Input: `{"url":"https://service.two","body":{"query":"query($secondArg: Boolean, $fourthArg: Float){serviceTwo(serviceTwoArg: $secondArg){fieldTwo} secondServiceTwo(secondServiceTwoArg: $fourthArg){fieldTwo}}","variables":{"fourthArg":$$1$$,"secondArg":$$0$$}}}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"url":"https://service.two","body":{"query":"query($secondArg: Boolean, $fourthArg: Float){serviceTwo(serviceTwoArg: $secondArg){fieldTwo} secondServiceTwo(secondServiceTwoArg: $fourthArg){fieldTwo}}","variables":{"fourthArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"fourthArg"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`,"secondArg":`), - }, - { - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: []string{"secondArg"}, - }, - { - SegmentType: StaticSegmentType, - Data: []byte(`}}}`), - }, - }, - }, - DataSource: serviceTwoDS, - Variables: NewVariables( - &ContextVariable{ - Path: []string{"secondArg"}, - }, - &ContextVariable{ - Path: []string{"fourthArg"}, - }, - ), - }, - }, - }, - Fields: []*Field{ - { - BufferID: 0, - HasBuffer: true, - Name: []byte("serviceOne"), - Value: &Object{ - Path: []string{"serviceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - { - BufferID: 1, - HasBuffer: true, - Name: []byte("serviceTwo"), - Value: &Object{ - Path: []string{"serviceTwo"}, - Fetch: &SingleFetch{ - BufferId: 2, - Input: `{"url":"https://service.one","body":{"query":"{serviceOne {fieldOne}}"}}`, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: StaticSegmentType, - Data: []byte(`{"url":"https://service.one","body":{"query":"{serviceOne {fieldOne}}"}}`), - }, - }, - }, - DataSource: nestedServiceOneDS, - Variables: Variables{}, - }, - Fields: []*Field{ - { - Name: []byte("fieldTwo"), - Value: &String{ - Path: []string{"fieldTwo"}, - }, - }, - { - BufferID: 2, - HasBuffer: true, - Name: []byte("serviceOneResponse"), - Value: &Object{ - Path: []string{"serviceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("anotherServiceOne"), - Value: &Object{ - Path: []string{"anotherServiceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - { - BufferID: 1, - HasBuffer: true, - Name: []byte("secondServiceTwo"), - Value: &Object{ - Path: []string{"secondServiceTwo"}, - Fields: []*Field{ - { - Name: []byte("fieldTwo"), - Value: &String{ - Path: []string{"fieldTwo"}, - }, - }, - }, - }, - }, - { - BufferID: 0, - HasBuffer: true, - Name: []byte("reusingServiceOne"), - Value: &Object{ - Path: []string{"reusingServiceOne"}, - Fields: []*Field{ - { - Name: []byte("fieldOne"), - Value: &String{ - Path: []string{"fieldOne"}, - }, - }, - }, - }, - }, - }, - }, - } - - var err error - expected := []byte(`{"data":{"serviceOne":{"fieldOne":"fieldOneValue"},"serviceTwo":{"fieldTwo":"fieldTwoValue","serviceOneResponse":{"fieldOne":"fieldOneValue"}},"anotherServiceOne":{"fieldOne":"anotherFieldOneValue"},"secondServiceTwo":{"fieldTwo":"secondFieldTwoValue"},"reusingServiceOne":{"fieldOne":"reUsingFieldOneValue"}}}`) - - pool := sync.Pool{ - New: func() interface{} { - return bytes.NewBuffer(make([]byte, 0, 1024)) - }, - } - - variables := []byte(`{"firstArg":"firstArgValue","thirdArg":123,"secondArg": true, "fourthArg": 12.34}`) - - ctxPool := sync.Pool{ - New: func() interface{} { - return NewContext(context.Background()) - }, - } - - runBench := func(b *testing.B) { - b.ReportAllocs() - b.SetBytes(int64(len(expected))) - b.ResetTimer() - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - // _ = resolver.ResolveGraphQLResponse(ctx, plan, nil, ioutil.Discard) - ctx := ctxPool.Get().(*Context) - ctx.Variables = variables - buf := pool.Get().(*bytes.Buffer) - err = resolver.ResolveGraphQLResponse(ctx, plan, nil, buf) - if err != nil { - b.Fatal(err) - } - if !bytes.Equal(expected, buf.Bytes()) { - b.Fatalf("want:\n%s\ngot:\n%s\n", string(expected), buf.String()) - } - - buf.Reset() - pool.Put(buf) - - ctx.Free() - ctxPool.Put(ctx) - } - }) - } - - b.Run("singleflight enabled (latency 0)", func(b *testing.B) { - serviceOneDS.artificialLatency = 0 - serviceTwoDS.artificialLatency = 0 - nestedServiceOneDS.artificialLatency = 0 - runBench(b) - }) -} - -type hookContextPathMatcher struct { - path string -} - -func (h hookContextPathMatcher) Matches(x interface{}) bool { - path := string(x.(HookContext).CurrentPath) - return path == h.path -} - -func (h hookContextPathMatcher) String() string { - return fmt.Sprintf("is equal to %s", h.path) -} - -type initTestVariableRenderer func(jsonSchema string) VariableRenderer - -func useTestPlainVariableRenderer() initTestVariableRenderer { - return func(jsonSchema string) VariableRenderer { - return NewPlainVariableRendererWithValidation(jsonSchema) - } -} - -func useTestJSONVariableRenderer() initTestVariableRenderer { - return func(jsonSchema string) VariableRenderer { - return NewJSONVariableRendererWithValidation(jsonSchema) - } -} diff --git a/pkg/engine/resolve/stream_test.go b/pkg/engine/resolve/stream_test.go deleted file mode 100644 index 44ee2bc5d..000000000 --- a/pkg/engine/resolve/stream_test.go +++ /dev/null @@ -1,411 +0,0 @@ -//go:build !windows - -package resolve - -import ( - "context" - "os" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestArrayStream(t *testing.T) { - - controller := gomock.NewController(t) - - userService := fakeService(t, controller, "user", "./testdata/users.json", - "") - - res := &GraphQLStreamingResponse{ - InitialResponse: &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Stream: Stream{ - Enabled: true, - InitialBatchSize: 0, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - Patches: []*GraphQLResponsePatch{ - { - Operation: literal.ADD, - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - ctx := NewContext(context.Background()) - - writer := &TestFlushWriter{} - - err := resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - assert.NoError(t, err) - - assert.Equal(t, 3, len(writer.flushed)) - - expected, err := os.ReadFile("./testdata/stream_1.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[0]) - - expected, err = os.ReadFile("./testdata/stream_2.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[1]) - - expected, err = os.ReadFile("./testdata/stream_3.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[2]) -} - -func TestArrayStream_InitialBatch_1(t *testing.T) { - - controller := gomock.NewController(t) - - userService := fakeService(t, controller, "user", "./testdata/users.json", - "") - - res := &GraphQLStreamingResponse{ - InitialResponse: &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Stream: Stream{ - Enabled: true, - InitialBatchSize: 1, - PatchIndex: 0, - }, - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*GraphQLResponsePatch{ - { - Operation: literal.ADD, - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - ctx := NewContext(context.Background()) - - writer := &TestFlushWriter{} - - err := resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - assert.NoError(t, err) - - assert.Equal(t, 2, len(writer.flushed)) - - expected, err := os.ReadFile("./testdata/stream_4.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[0]) - - expected, err = os.ReadFile("./testdata/stream_3.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[1]) -} - -func TestArrayStream_InitialBatch_2(t *testing.T) { - - controller := gomock.NewController(t) - - userService := fakeService(t, controller, "user", "./testdata/users.json", - "") - - res := &GraphQLStreamingResponse{ - InitialResponse: &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Stream: Stream{ - Enabled: true, - InitialBatchSize: 2, - PatchIndex: 0, - }, - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*GraphQLResponsePatch{ - { - Operation: literal.ADD, - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - ctx := NewContext(context.Background()) - - writer := &TestFlushWriter{} - - err := resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - assert.NoError(t, err) - - assert.Equal(t, 1, len(writer.flushed)) - - expected, err := os.ReadFile("./testdata/stream_5.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[0]) -} - -func TestStreamAndDefer(t *testing.T) { - t.Skip("temporary disabled") - - controller := gomock.NewController(t) - - userService := fakeService(t, controller, "user", "./testdata/users.json", - "") - - postsService := fakeService(t, controller, "posts", "./testdata/posts.json", - "1", "2", - ) - - res := &GraphQLStreamingResponse{ - InitialResponse: &GraphQLResponse{ - Data: &Object{ - Fetch: &SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &Array{ - Stream: Stream{ - Enabled: true, - InitialBatchSize: 0, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - Patches: []*GraphQLResponsePatch{ - { - Operation: literal.ADD, - Value: &Object{ - Fields: []*Field{ - { - Name: []byte("id"), - Value: &Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &String{ - Path: []string{"name"}, - }, - }, - { - - Name: []byte("posts"), - Value: &Null{ - Defer: Defer{ - Enabled: true, - PatchIndex: 1, - }, - }, - }, - }, - }, - }, - { - Operation: literal.REPLACE, - Fetch: &SingleFetch{ - DataSource: postsService, - InputTemplate: InputTemplate{ - Segments: []TemplateSegment{ - { - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: []string{"id"}, - Renderer: NewGraphQLVariableRenderer(`{"type":"number"}`), - }, - }, - }, - }, - Value: &Array{ - Item: &Object{ - Fields: []*Field{ - { - Name: []byte("title"), - Value: &String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - } - - rCtx, cancel := context.WithCancel(context.Background()) - defer cancel() - - resolver := New(rCtx, NewFetcher(false), false) - - ctx := NewContext(context.Background()) - - writer := &TestFlushWriter{} - - err := resolver.ResolveGraphQLStreamingResponse(ctx, res, nil, writer) - assert.NoError(t, err) - - assert.Equal(t, 5, len(writer.flushed)) - - expected, err := os.ReadFile("./testdata/stream_1.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[0]) - - expected, err = os.ReadFile("./testdata/stream_6.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[1]) - - expected, err = os.ReadFile("./testdata/stream_7.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[2]) - - expected, err = os.ReadFile("./testdata/stream_8.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[3]) - - expected, err = os.ReadFile("./testdata/stream_9.json") - assert.NoError(t, err) - assert.JSONEq(t, string(expected), writer.flushed[4]) -} diff --git a/pkg/engine/resolve/testdata/defer_1.json b/pkg/engine/resolve/testdata/defer_1.json deleted file mode 100644 index 6f360dbe3..000000000 --- a/pkg/engine/resolve/testdata/defer_1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "data": { - "users": [ - { - "id": 1, - "name": "Leanne Graham", - "posts": null - }, - { - "id": 2, - "name": "Ervin Howell", - "posts": null - } - ] - } -} \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/defer_2.json b/pkg/engine/resolve/testdata/defer_2.json deleted file mode 100644 index 708a55ae3..000000000 --- a/pkg/engine/resolve/testdata/defer_2.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "op": "replace", - "path": "/data/users/0/posts", - "value": [ - { - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } - ] - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/defer_3.json b/pkg/engine/resolve/testdata/defer_3.json deleted file mode 100644 index 338d041c1..000000000 --- a/pkg/engine/resolve/testdata/defer_3.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "op": "replace", - "path": "/data/users/1/posts", - "value": [ - { - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } - ] - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/posts.json b/pkg/engine/resolve/testdata/posts.json deleted file mode 100644 index 4e3758273..000000000 --- a/pkg/engine/resolve/testdata/posts.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "userId": 1, - "id": 1, - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "userId": 1, - "id": 2, - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/response_without_defer.json b/pkg/engine/resolve/testdata/response_without_defer.json deleted file mode 100644 index 6c2b53ecc..000000000 --- a/pkg/engine/resolve/testdata/response_without_defer.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "data": { - "users": [ - { - "id": 1, - "name": "Leanne Graham", - "posts": [ - { - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } - ] - }, - { - "id": 2, - "name": "Ervin Howell", - "posts": [ - { - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } - ] - } - ] - } -} \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_1.json b/pkg/engine/resolve/testdata/stream_1.json deleted file mode 100644 index 39aa03c0c..000000000 --- a/pkg/engine/resolve/testdata/stream_1.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "data": { - "users": [] - } -} \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_2.json b/pkg/engine/resolve/testdata/stream_2.json deleted file mode 100644 index 28eb11312..000000000 --- a/pkg/engine/resolve/testdata/stream_2.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "op": "add", - "path": "/data/users/0", - "value": { - "id": 1, - "name": "Leanne Graham" - } - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_3.json b/pkg/engine/resolve/testdata/stream_3.json deleted file mode 100644 index 2f5a22f16..000000000 --- a/pkg/engine/resolve/testdata/stream_3.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "op": "add", - "path": "/data/users/1", - "value": { - "id": 2, - "name": "Ervin Howell" - } - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_4.json b/pkg/engine/resolve/testdata/stream_4.json deleted file mode 100644 index 82d434b5d..000000000 --- a/pkg/engine/resolve/testdata/stream_4.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "data": { - "users": [ - { - "id": 1, - "name": "Leanne Graham" - } - ] - } -} \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_5.json b/pkg/engine/resolve/testdata/stream_5.json deleted file mode 100644 index 7f9298f02..000000000 --- a/pkg/engine/resolve/testdata/stream_5.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "data": { - "users": [ - { - "id": 1, - "name": "Leanne Graham" - }, - { - "id": 2, - "name": "Ervin Howell" - } - ] - } -} \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_6.json b/pkg/engine/resolve/testdata/stream_6.json deleted file mode 100644 index ec3b54521..000000000 --- a/pkg/engine/resolve/testdata/stream_6.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - { - "op": "add", - "path": "/data/users/0", - "value": { - "id": 1, - "name": "Leanne Graham", - "posts": null - } - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_7.json b/pkg/engine/resolve/testdata/stream_7.json deleted file mode 100644 index 123c50a6a..000000000 --- a/pkg/engine/resolve/testdata/stream_7.json +++ /dev/null @@ -1,11 +0,0 @@ -[ - { - "op": "add", - "path": "/data/users/1", - "value": { - "id": 2, - "name": "Ervin Howell", - "posts": null - } - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_8.json b/pkg/engine/resolve/testdata/stream_8.json deleted file mode 100644 index 708a55ae3..000000000 --- a/pkg/engine/resolve/testdata/stream_8.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "op": "replace", - "path": "/data/users/0/posts", - "value": [ - { - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } - ] - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/stream_9.json b/pkg/engine/resolve/testdata/stream_9.json deleted file mode 100644 index 338d041c1..000000000 --- a/pkg/engine/resolve/testdata/stream_9.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "op": "replace", - "path": "/data/users/1/posts", - "value": [ - { - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" - }, - { - "title": "qui est esse", - "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" - } - ] - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/testdata/users.json b/pkg/engine/resolve/testdata/users.json deleted file mode 100644 index 94e9a34fd..000000000 --- a/pkg/engine/resolve/testdata/users.json +++ /dev/null @@ -1,48 +0,0 @@ -[ - { - "id": 1, - "name": "Leanne Graham", - "username": "Bret", - "email": "Sincere@april.biz", - "address": { - "street": "Kulas Light", - "suite": "Apt. 556", - "city": "Gwenborough", - "zipcode": "92998-3874", - "geo": { - "lat": "-37.3159", - "lng": "81.1496" - } - }, - "phone": "1-770-736-8031 x56442", - "website": "hildegard.org", - "company": { - "name": "Romaguera-Crona", - "catchPhrase": "Multi-layered client-server neural-net", - "bs": "harness real-time e-markets" - } - }, - { - "id": 2, - "name": "Ervin Howell", - "username": "Antonette", - "email": "Shanna@melissa.tv", - "address": { - "street": "Victor Plains", - "suite": "Suite 879", - "city": "Wisokyburgh", - "zipcode": "90566-7771", - "geo": { - "lat": "-43.9509", - "lng": "-34.4618" - } - }, - "phone": "010-692-6593 x09125", - "website": "anastasia.net", - "company": { - "name": "Deckow-Crist", - "catchPhrase": "Proactive didactic contingency", - "bs": "synergize scalable supply-chains" - } - } -] \ No newline at end of file diff --git a/pkg/engine/resolve/variable.go b/pkg/engine/resolve/variable.go deleted file mode 100644 index c505b9eff..000000000 --- a/pkg/engine/resolve/variable.go +++ /dev/null @@ -1,640 +0,0 @@ -package resolve - -import ( - "context" - "encoding/json" - "fmt" - "io" - "strconv" - - "github.com/buger/jsonparser" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphqljsonschema" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type VariableKind int - -const ( - ContextVariableKind VariableKind = iota + 1 - ObjectVariableKind - HeaderVariableKind -) - -const ( - VariableRendererKindPlain = "plain" - VariableRendererKindPlanWithValidation = "plainWithValidation" - VariableRendererKindJson = "json" - VariableRendererKindJsonWithValidation = "jsonWithValidation" - VariableRendererKindGraphqlWithValidation = "graphqlWithValidation" - VariableRendererKindCsv = "csv" -) - -// VariableRenderer is the interface to allow custom implementations of rendering Variables -// Depending on where a Variable is being used, a different method for rendering is required -// E.g. a Variable needs to be rendered conforming to the GraphQL specification, when used within a GraphQL Query -// If a Variable is used within a JSON Object, the contents need to be rendered as a JSON Object -type VariableRenderer interface { - GetKind() string - RenderVariable(ctx context.Context, data []byte, out io.Writer) error -} - -// JSONVariableRenderer is an implementation of VariableRenderer -// It renders the provided data as JSON -// If configured, it also does a JSON Validation Check before rendering -type JSONVariableRenderer struct { - JSONSchema string - Kind string - validator *graphqljsonschema.Validator - rootValueType JsonRootType -} - -func (r *JSONVariableRenderer) GetKind() string { - return r.Kind -} - -func (r *JSONVariableRenderer) RenderVariable(ctx context.Context, data []byte, out io.Writer) error { - if r.validator != nil { - err := r.validator.Validate(ctx, data) - if err != nil { - return fmt.Errorf("could not render JSON variable, %w", err) - } - } - _, err := out.Write(data) - return err -} - -func NewJSONVariableRenderer() *JSONVariableRenderer { - return &JSONVariableRenderer{ - Kind: VariableRendererKindJson, - } -} - -func NewJSONVariableRendererWithValidation(jsonSchema string) *JSONVariableRenderer { - validator := graphqljsonschema.MustNewValidatorFromString(jsonSchema) - return &JSONVariableRenderer{ - Kind: VariableRendererKindJsonWithValidation, - JSONSchema: jsonSchema, - validator: validator, - } -} - -// NewJSONVariableRendererWithValidationFromTypeRef creates a new JSONVariableRenderer -// The argument typeRef must exist on the operation ast.Document, otherwise it will panic! -func NewJSONVariableRendererWithValidationFromTypeRef(operation, definition *ast.Document, variableTypeRef int) (*JSONVariableRenderer, error) { - jsonSchema := graphqljsonschema.FromTypeRef(operation, definition, variableTypeRef) - validator, err := graphqljsonschema.NewValidatorFromSchema(jsonSchema) - if err != nil { - return nil, err - } - schemaBytes, err := json.Marshal(jsonSchema) - if err != nil { - return nil, err - } - return &JSONVariableRenderer{ - Kind: VariableRendererKindJsonWithValidation, - JSONSchema: string(schemaBytes), - validator: validator, - rootValueType: getJSONRootType(operation, definition, variableTypeRef), - }, nil -} - -func NewPlainVariableRenderer() *PlainVariableRenderer { - return &PlainVariableRenderer{ - Kind: VariableRendererKindPlain, - } -} - -func NewPlainVariableRendererWithValidation(jsonSchema string) *PlainVariableRenderer { - validator := graphqljsonschema.MustNewValidatorFromString(jsonSchema) - return &PlainVariableRenderer{ - Kind: VariableRendererKindPlanWithValidation, - JSONSchema: jsonSchema, - validator: validator, - } -} - -// NewPlainVariableRendererWithValidationFromTypeRef creates a new PlainVariableRenderer -// The argument typeRef must exist on the operation ast.Document, otherwise it will panic! -func NewPlainVariableRendererWithValidationFromTypeRef(operation, definition *ast.Document, variableTypeRef int, variablePath ...string) (*PlainVariableRenderer, error) { - var jsonSchema graphqljsonschema.JsonSchema - if len(variablePath) > 1 { - jsonSchema = graphqljsonschema.FromTypeRef(operation, definition, variableTypeRef, graphqljsonschema.WithPath(variablePath[1:])) - } else { - jsonSchema = graphqljsonschema.FromTypeRef(operation, definition, variableTypeRef) - } - - validator, err := graphqljsonschema.NewValidatorFromSchema(jsonSchema) - if err != nil { - return nil, err - } - schemaBytes, err := json.Marshal(jsonSchema) - if err != nil { - return nil, err - } - rootValueType := getJSONRootType(operation, definition, variableTypeRef) - return &PlainVariableRenderer{ - Kind: VariableRendererKindPlanWithValidation, - JSONSchema: string(schemaBytes), - validator: validator, - rootValueType: rootValueType, - }, nil -} - -// PlainVariableRenderer is an implementation of VariableRenderer -// It renders the provided data as plain text -// E.g. a provided JSON string of "foo" will be rendered as foo, without quotes. -// If a nested JSON Object is provided, it will be rendered as is. -// This renderer can be used e.g. to render the provided scalar into a URL. -type PlainVariableRenderer struct { - JSONSchema string - Kind string - validator *graphqljsonschema.Validator - rootValueType JsonRootType -} - -func (p *PlainVariableRenderer) GetKind() string { - return p.Kind -} - -func (p *PlainVariableRenderer) RenderVariable(ctx context.Context, data []byte, out io.Writer) error { - if p.validator != nil { - err := p.validator.Validate(ctx, data) - if err != nil { - return fmt.Errorf("could not render plain text variable, %w", err) - } - } - - data, _ = extractStringWithQuotes(p.rootValueType, data) - - _, err := out.Write(data) - return err -} - -// NewGraphQLVariableRendererFromTypeRef creates a new GraphQLVariableRenderer -// The argument typeRef must exist on the operation ast.Document, otherwise it will panic! -func NewGraphQLVariableRendererFromTypeRef(operation, definition *ast.Document, variableTypeRef int) (*GraphQLVariableRenderer, error) { - jsonSchema := graphqljsonschema.FromTypeRef(operation, definition, variableTypeRef) - validator, err := graphqljsonschema.NewValidatorFromSchema(jsonSchema) - if err != nil { - return nil, err - } - schemaBytes, err := json.Marshal(jsonSchema) - if err != nil { - return nil, err - } - return &GraphQLVariableRenderer{ - Kind: VariableRendererKindGraphqlWithValidation, - JSONSchema: string(schemaBytes), - validator: validator, - rootValueType: getJSONRootType(operation, definition, variableTypeRef), - }, nil -} - -func NewGraphQLVariableRendererFromTypeRefWithOverrides(operation, definition *ast.Document, variableTypeRef int, overrides map[string]graphqljsonschema.JsonSchema) (*GraphQLVariableRenderer, error) { - jsonSchema := graphqljsonschema.FromTypeRef(operation, definition, variableTypeRef, graphqljsonschema.WithOverrides(overrides)) - validator, err := graphqljsonschema.NewValidatorFromSchema(jsonSchema) - if err != nil { - return nil, err - } - schemaBytes, err := json.Marshal(jsonSchema) - if err != nil { - return nil, err - } - return &GraphQLVariableRenderer{ - Kind: VariableRendererKindGraphqlWithValidation, - JSONSchema: string(schemaBytes), - validator: validator, - rootValueType: getJSONRootType(operation, definition, variableTypeRef), - }, nil -} - -func NewGraphQLVariableRendererFromTypeRefWithoutValidation(operation, definition *ast.Document, variableTypeRef int) (*GraphQLVariableRenderer, error) { - return &GraphQLVariableRenderer{ - Kind: VariableRendererKindGraphqlWithValidation, - rootValueType: getJSONRootType(operation, definition, variableTypeRef), - }, nil -} - -// NewGraphQLVariableRendererFromJSONRootTypeWithoutValidation - to be used in tests only -func NewGraphQLVariableRendererFromJSONRootTypeWithoutValidation(rootType JsonRootType) (*GraphQLVariableRenderer, error) { - return &GraphQLVariableRenderer{ - Kind: VariableRendererKindGraphqlWithValidation, - rootValueType: rootType, - }, nil -} - -// NewGraphQLVariableRenderer - to be used in tests only -func NewGraphQLVariableRenderer(jsonSchema string) *GraphQLVariableRenderer { - validator := graphqljsonschema.MustNewValidatorFromString(jsonSchema) - rootValueType, err := graphqljsonschema.TopLevelType(jsonSchema) - if err != nil { - panic(err) - } - return &GraphQLVariableRenderer{ - Kind: VariableRendererKindGraphqlWithValidation, - JSONSchema: jsonSchema, - validator: validator, - rootValueType: JsonRootType{ - Value: rootValueType, - Kind: JsonRootTypeKindSingle, - }, - } -} - -type JsonRootTypeKind int - -const ( - JsonRootTypeKindSingle JsonRootTypeKind = iota - JsonRootTypeKindMultiple -) - -type JsonRootType struct { - Value jsonparser.ValueType - Values []jsonparser.ValueType - Kind JsonRootTypeKind -} - -func (t JsonRootType) Satisfies(dataType jsonparser.ValueType) bool { - switch t.Kind { - case JsonRootTypeKindSingle: - return dataType == t.Value - case JsonRootTypeKindMultiple: - for _, valueType := range t.Values { - if dataType == valueType { - return true - } - } - } - - return false -} - -func getJSONRootType(operation, definition *ast.Document, variableTypeRef int) JsonRootType { - variableTypeRef = operation.ResolveListOrNameType(variableTypeRef) - if operation.TypeIsList(variableTypeRef) { - return JsonRootType{ - Value: jsonparser.Array, - Kind: JsonRootTypeKindSingle, - } - } - - name := operation.TypeNameString(variableTypeRef) - node, exists := definition.Index.FirstNodeByNameStr(name) - if !exists { - return JsonRootType{ - Value: jsonparser.Unknown, - Kind: JsonRootTypeKindSingle, - } - } - - defTypeRef := node.Ref - - if node.Kind == ast.NodeKindEnumTypeDefinition { - return JsonRootType{ - Value: jsonparser.String, - Kind: JsonRootTypeKindSingle, - } - } - if node.Kind == ast.NodeKindScalarTypeDefinition { - typeName := definition.ScalarTypeDefinitionNameString(defTypeRef) - switch typeName { - case "Boolean": - return JsonRootType{ - Value: jsonparser.Boolean, - Kind: JsonRootTypeKindSingle, - } - case "Int", "Float": - return JsonRootType{ - Value: jsonparser.Number, - Kind: JsonRootTypeKindSingle, - } - case "ID": - return JsonRootType{ - Values: []jsonparser.ValueType{jsonparser.String, jsonparser.Number}, - Kind: JsonRootTypeKindMultiple, - } - case "String", "Date": - return JsonRootType{ - Value: jsonparser.String, - Kind: JsonRootTypeKindSingle, - } - case "_Any": - return JsonRootType{ - Value: jsonparser.Object, - Kind: JsonRootTypeKindSingle, - } - default: - return JsonRootType{ - Value: jsonparser.String, - Kind: JsonRootTypeKindSingle, - } - } - } - - return JsonRootType{ - Value: jsonparser.Object, - Kind: JsonRootTypeKindSingle, - } -} - -// GraphQLVariableRenderer is an implementation of VariableRenderer -// It renders variables according to the GraphQL Specification -type GraphQLVariableRenderer struct { - JSONSchema string - Kind string - validator *graphqljsonschema.Validator - rootValueType JsonRootType -} - -func (g *GraphQLVariableRenderer) GetKind() string { - return g.Kind -} - -// add renderer that renders both variable name and variable value -// before rendering, evaluate if the value contains null values -// if an object contains only null values, set the object to null -// do this recursively until reaching the root of the object - -func (g *GraphQLVariableRenderer) RenderVariable(ctx context.Context, data []byte, out io.Writer) error { - if g.validator != nil { - err := g.validator.Validate(ctx, data) - if err != nil { - return fmt.Errorf("could not render GraphQL variable, %w", err) - } - } - - var desiredType jsonparser.ValueType - data, desiredType = extractStringWithQuotes(g.rootValueType, data) - - return g.renderGraphQLValue(data, desiredType, out) -} - -func (g *GraphQLVariableRenderer) renderGraphQLValue(data []byte, valueType jsonparser.ValueType, out io.Writer) (err error) { - switch valueType { - case jsonparser.String: - _, _ = out.Write(literal.BACKSLASH) - _, _ = out.Write(literal.QUOTE) - for i := range data { - switch data[i] { - case '"': - _, _ = out.Write(literal.BACKSLASH) - _, _ = out.Write(literal.BACKSLASH) - _, _ = out.Write(literal.QUOTE) - default: - _, _ = out.Write(data[i : i+1]) - } - } - _, _ = out.Write(literal.BACKSLASH) - _, _ = out.Write(literal.QUOTE) - case jsonparser.Object: - _, _ = out.Write(literal.LBRACE) - first := true - err = jsonparser.ObjectEach(data, func(key []byte, value []byte, objectFieldValueType jsonparser.ValueType, offset int) error { - if !first { - _, _ = out.Write(literal.COMMA) - } else { - first = false - } - _, _ = out.Write(key) - _, _ = out.Write(literal.COLON) - return g.renderGraphQLValue(value, objectFieldValueType, out) - }) - if err != nil { - return err - } - _, _ = out.Write(literal.RBRACE) - case jsonparser.Null: - _, _ = out.Write(literal.NULL) - case jsonparser.Boolean: - _, _ = out.Write(data) - case jsonparser.Array: - _, _ = out.Write(literal.LBRACK) - first := true - var arrayErr error - _, err = jsonparser.ArrayEach(data, func(value []byte, arrayItemValueType jsonparser.ValueType, offset int, err error) { - if !first { - _, _ = out.Write(literal.COMMA) - } else { - first = false - } - arrayErr = g.renderGraphQLValue(value, arrayItemValueType, out) - }) - if arrayErr != nil { - return arrayErr - } - if err != nil { - return err - } - _, _ = out.Write(literal.RBRACK) - case jsonparser.Number: - _, _ = out.Write(data) - } - return -} - -func NewCSVVariableRenderer(arrayValueType JsonRootType) *CSVVariableRenderer { - return &CSVVariableRenderer{ - Kind: VariableRendererKindCsv, - arrayValueType: arrayValueType, - } -} - -func NewCSVVariableRendererFromTypeRef(operation, definition *ast.Document, variableTypeRef int) *CSVVariableRenderer { - return &CSVVariableRenderer{ - Kind: VariableRendererKindCsv, - arrayValueType: getJSONRootType(operation, definition, variableTypeRef), - } -} - -// CSVVariableRenderer is an implementation of VariableRenderer -// It renders the provided list of Values as comma separated Values in plaintext (no JSON encoding of Values) -type CSVVariableRenderer struct { - Kind string - arrayValueType JsonRootType -} - -func (c *CSVVariableRenderer) GetKind() string { - return c.Kind -} - -func (c *CSVVariableRenderer) RenderVariable(_ context.Context, data []byte, out io.Writer) error { - isFirst := true - _, err := jsonparser.ArrayEach(data, func(value []byte, dataType jsonparser.ValueType, offset int, err error) { - if !c.arrayValueType.Satisfies(dataType) { - return - } - - if isFirst { - isFirst = false - } else { - _, _ = out.Write(literal.COMMA) - } - _, _ = out.Write(value) - }) - return err -} - -type ContextVariable struct { - Path []string - Renderer VariableRenderer -} - -func (c *ContextVariable) TemplateSegment() TemplateSegment { - return TemplateSegment{ - SegmentType: VariableSegmentType, - VariableKind: ContextVariableKind, - VariableSourcePath: c.Path, - Renderer: c.Renderer, - } -} - -func (c *ContextVariable) Equals(another Variable) bool { - if another == nil { - return false - } - if another.GetVariableKind() != c.GetVariableKind() { - return false - } - anotherContextVariable := another.(*ContextVariable) - if len(c.Path) != len(anotherContextVariable.Path) { - return false - } - for i := range c.Path { - if c.Path[i] != anotherContextVariable.Path[i] { - return false - } - } - return true -} - -func (_ *ContextVariable) GetVariableKind() VariableKind { - return ContextVariableKind -} - -type ObjectVariable struct { - Path []string - Renderer VariableRenderer -} - -func (o *ObjectVariable) TemplateSegment() TemplateSegment { - return TemplateSegment{ - SegmentType: VariableSegmentType, - VariableKind: ObjectVariableKind, - VariableSourcePath: o.Path, - Renderer: o.Renderer, - } -} - -func (o *ObjectVariable) Equals(another Variable) bool { - if another == nil { - return false - } - if another.GetVariableKind() != o.GetVariableKind() { - return false - } - anotherObjectVariable := another.(*ObjectVariable) - if len(o.Path) != len(anotherObjectVariable.Path) { - return false - } - for i := range o.Path { - if o.Path[i] != anotherObjectVariable.Path[i] { - return false - } - } - return true -} - -func (o *ObjectVariable) GetVariableKind() VariableKind { - return ObjectVariableKind -} - -type HeaderVariable struct { - Path []string -} - -func (h *HeaderVariable) TemplateSegment() TemplateSegment { - return TemplateSegment{ - SegmentType: VariableSegmentType, - VariableKind: HeaderVariableKind, - VariableSourcePath: h.Path, - } -} - -func (h *HeaderVariable) GetVariableKind() VariableKind { - return HeaderVariableKind -} - -func (h *HeaderVariable) Equals(another Variable) bool { - if another == nil { - return false - } - if another.GetVariableKind() != h.GetVariableKind() { - return false - } - anotherHeaderVariable := another.(*HeaderVariable) - if len(h.Path) != len(anotherHeaderVariable.Path) { - return false - } - for i := range h.Path { - if h.Path[i] != anotherHeaderVariable.Path[i] { - return false - } - } - return true -} - -type Variable interface { - GetVariableKind() VariableKind - Equals(another Variable) bool - TemplateSegment() TemplateSegment -} - -type Variables []Variable - -func NewVariables(variables ...Variable) Variables { - return variables -} - -const ( - variablePrefixSuffix = "$$" -) - -func (v *Variables) AddVariable(variable Variable) (name string, exists bool) { - index := -1 - for i := range *v { - if (*v)[i].Equals(variable) { - index = i - exists = true - break - } - } - if index == -1 { - *v = append(*v, variable) - index = len(*v) - 1 - } - i := strconv.Itoa(index) - name = variablePrefixSuffix + i + variablePrefixSuffix - return -} - -type VariableSchema struct { -} - -func extractStringWithQuotes(rootValueType JsonRootType, data []byte) ([]byte, jsonparser.ValueType) { - desiredType := jsonparser.Unknown - switch rootValueType.Kind { - case JsonRootTypeKindSingle: - desiredType = rootValueType.Value - case JsonRootTypeKindMultiple: - _, tt, _, _ := jsonparser.Get(data) - if rootValueType.Satisfies(tt) { - desiredType = tt - } - } - if desiredType == jsonparser.String { - return data[1 : len(data)-1], desiredType - } - return data, desiredType -} diff --git a/pkg/escape/bytes.go b/pkg/escape/bytes.go deleted file mode 100644 index 109e418d9..000000000 --- a/pkg/escape/bytes.go +++ /dev/null @@ -1,33 +0,0 @@ -package escape - -func Bytes(in, out []byte) []byte { - - out = out[:0] - - for i := range in { - switch in[i] { - case 9: - out = append(out, 92, 116) // \t - case 10: - out = append(out, 92, 110) // \n - case 34: - if i > 0 && in[i-1] == 92 { - out = append(out, 92, 92, 34) // \\" - } else { - out = append(out, 92, 34) // \" - } - case 92: - // if we have `\\` inside string - if in[i-1] == 92 { - // make 4 in a row - out = append(out, 92, 92, 92) - continue - } - fallthrough - default: - out = append(out, in[i]) - } - } - - return out -} diff --git a/pkg/escape/bytes_test.go b/pkg/escape/bytes_test.go deleted file mode 100644 index d73d56c05..000000000 --- a/pkg/escape/bytes_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package escape - -import ( - "bytes" - "encoding/json" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBytes(t *testing.T) { - t.Run("", func(t *testing.T) { - input := `foo - bar - baz bal -"str" -` - - marshalled, err := json.Marshal(input) - if err != nil { - t.Fatal(err) - } - - want := marshalled[1 : len(marshalled)-1] - - var out []byte - - got := Bytes([]byte(input), out) - if !bytes.Equal(got, want) { - t.Fatalf("\n%+v (want: %d)\n%+v (got: %d)\n%s (wantString)\n%s (gotString)", want, len(want), got, len(got), string(want), string(got)) - } - - out = make([]byte, len(input)) - - got = Bytes([]byte(input), out) - if !bytes.Equal(got, want) { - t.Fatalf("\n%+v (want: %d)\n%+v (got: %d)\n%s (wantString)\n%s (gotString)", want, len(want), got, len(got), string(want), string(got)) - } - - out = out[:0] - - got = Bytes([]byte(input), out) - if !bytes.Equal(got, want) { - t.Fatalf("\n%+v (want: %d)\n%+v (got: %d)\n%s (wantString)\n%s (gotString)", want, len(want), got, len(got), string(want), string(got)) - } - - got = Bytes([]byte(input), out) - if !bytes.Equal(got, want) { - t.Fatalf("\n%+v (want: %d)\n%+v (got: %d)\n%s (wantString)\n%s (gotString)", want, len(want), got, len(got), string(want), string(got)) - } - }) - - run := func(t *testing.T, input string, expectedOutput string) (string, func(t *testing.T)) { - return fmt.Sprintf("%s should be %s", input, expectedOutput), func(t *testing.T) { - out := make([]byte, len(input)) - result := Bytes([]byte(input), out) - - assert.Equal(t, expectedOutput, string(result)) - } - } - - t.Run(run(t, `"foo"`, `\"foo\"`)) - t.Run(run(t, `foo\n`, `foo\n`)) - t.Run(run(t, `foo\t`, `foo\t`)) - t.Run(run(t, `{"test": "{\"foo\": \"bar\", \"re\":\"\\w+\"}"}`, `{\"test\": \"{\\\"foo\\\": \\\"bar\\\", \\\"re\\\":\\\"\\\\w+\\\"}\"}`)) - t.Run(run(t, `"Hello, 世界"`, `\"Hello, 世界\"`)) - -} - -func BenchmarkBytes(b *testing.B) { - input := `foo - bar - baz bal -` - inputBytes := []byte(input) - out := make([]byte, len(inputBytes)*2) - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - if len(inputBytes) != len(input) { - b.Fatalf("must be same len") - } - out = Bytes(inputBytes, out) - if len(out) == 0 { - b.Fatalf("must not be 0") - } - } -} diff --git a/pkg/escape/escape.go b/pkg/escape/escape.go deleted file mode 100644 index 25830879c..000000000 --- a/pkg/escape/escape.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package escape enables efficient JSON escaping on byte slices. -package escape diff --git a/pkg/execution/datasource/datasource.go b/pkg/execution/datasource/datasource.go deleted file mode 100644 index 97730cfb5..000000000 --- a/pkg/execution/datasource/datasource.go +++ /dev/null @@ -1,272 +0,0 @@ -package datasource - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "net/url" - "strings" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -var RootTypeName = []byte("root_type_name") -var RootFieldName = []byte("root_field_name") - -var defaultHttpClient *http.Client - -func DefaultHttpClient() *http.Client { - if defaultHttpClient == nil { - defaultHttpClient = &http.Client{ - Timeout: time.Second * 10, - Transport: &http.Transport{ - MaxIdleConnsPerHost: 1024, - TLSHandshakeTimeout: 0 * time.Second, - }, - } - } - - return defaultHttpClient -} - -type ResolverArgs interface { - ByKey(key []byte) []byte - Dump() []string - Keys() [][]byte -} - -type DataSource interface { - Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) -} - -type Planner interface { - CorePlanner - PlannerVisitors -} - -type CorePlanner interface { - // Plan plan returns the pre configured DataSource as well as the Arguments - // During runtime the arguments get resolved and passed to the DataSource - Plan(args []Argument) (DataSource, []Argument) - // Configure is the function to initialize all important values for the Planner to function correctly - // You probably need access to the Walker, Operation and ObjectDefinition to use the Planner to its full power - // Walker gives you useful information from within all visitor Callbacks, e.g. the Path & Ancestors - // Operation is the AST of the GraphQL Operation - // ObjectDefinition is the AST of the GraphQL schema ObjectDefinition - // Args are the pre-calculated Arguments from the planner - // resolverParameters are the parameters from the @directive params field - Configure(operation, definition *ast.Document, walker *astvisitor.Walker) -} - -type PlannerVisitors interface { - astvisitor.EnterDocumentVisitor - astvisitor.EnterInlineFragmentVisitor - astvisitor.LeaveInlineFragmentVisitor - astvisitor.EnterSelectionSetVisitor - astvisitor.LeaveSelectionSetVisitor - astvisitor.EnterFieldVisitor - astvisitor.EnterArgumentVisitor - astvisitor.LeaveFieldVisitor -} - -type PlannerFactory interface { - DataSourcePlanner() Planner -} - -type PlannerFactoryFactory interface { - Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) -} - -type BasePlanner struct { - Log abstractlogger.Logger - Walker *astvisitor.Walker // nolint - Definition, Operation *ast.Document // nolint - Args []Argument // nolint - RootField rootField // nolint - Config PlannerConfiguration // nolint -} - -func NewBaseDataSourcePlanner(schema []byte, config PlannerConfiguration, logger abstractlogger.Logger) (*BasePlanner, error) { - definition, report := astparser.ParseGraphqlDocumentBytes(schema) - if report.HasErrors() { - return nil, report - } - - err := asttransform.MergeDefinitionWithBaseSchema(&definition) - if err != nil { - return nil, err - } - - return &BasePlanner{ - Config: config, - Log: logger, - Definition: &definition, - }, nil -} - -func (b *BasePlanner) Configure(operation, definition *ast.Document, walker *astvisitor.Walker) { - b.Operation, b.Definition, b.Walker = operation, definition, walker -} - -func (b *BasePlanner) RegisterDataSourcePlannerFactory(dataSourceName string, factory PlannerFactoryFactory) (err error) { - for i := range b.Config.TypeFieldConfigurations { - if dataSourceName != b.Config.TypeFieldConfigurations[i].DataSource.Name { - continue - } - configReader := bytes.NewReader(b.Config.TypeFieldConfigurations[i].DataSource.Config) - b.Config.TypeFieldConfigurations[i].DataSourcePlannerFactory, err = factory.Initialize(*b, configReader) - if err != nil { - return err - } - } - return nil -} - -type PlannerConfiguration struct { - TypeFieldConfigurations []TypeFieldConfiguration -} - -type TypeFieldConfiguration struct { - TypeName string `bson:"type_name" json:"type_name"` - FieldName string `bson:"field_name" json:"field_name"` - Mapping *MappingConfiguration `bson:"mapping" json:"mapping"` - DataSource SourceConfig `bson:"data_source" json:"data_source"` - DataSourcePlannerFactory PlannerFactory `bson:"-" json:"-"` -} - -type SourceConfig struct { - // Kind defines the unique identifier of the DataSource - // Kind needs to match to the Planner "DataSourceName" name - Name string `bson:"kind" json:"kind"` - // Config is the DataSource specific configuration object - // Each Planner needs to make sure to parse their Config Object correctly - Config json.RawMessage `bson:"data_source_config" json:"data_source_config"` -} - -type MappingConfiguration struct { - Disabled bool `bson:"disabled" json:"disabled"` - Path string `bson:"path" json:"path"` -} - -func (p *PlannerConfiguration) DataSourcePlannerFactoryForTypeField(typeName, fieldName string) PlannerFactory { - for i := range p.TypeFieldConfigurations { - if strings.EqualFold(p.TypeFieldConfigurations[i].TypeName, typeName) && strings.EqualFold(p.TypeFieldConfigurations[i].FieldName, fieldName) { - return p.TypeFieldConfigurations[i].DataSourcePlannerFactory - } - } - return nil -} - -func (p *PlannerConfiguration) MappingForTypeField(typeName, fieldName string) *MappingConfiguration { - for i := range p.TypeFieldConfigurations { - if strings.EqualFold(p.TypeFieldConfigurations[i].TypeName, typeName) && strings.EqualFold(p.TypeFieldConfigurations[i].FieldName, fieldName) { - return p.TypeFieldConfigurations[i].Mapping - } - } - return nil -} - -type rootField struct { - isDefined bool - ref int -} - -func (r *rootField) SetIfNotDefined(ref int) { - if r.isDefined { - return - } - r.isDefined = true - r.ref = ref -} - -func (r *rootField) IsDefinedAndEquals(ref int) bool { - return r.isDefined && r.ref == ref -} - -type visitingDataSourcePlanner struct { - CorePlanner -} - -func (_ visitingDataSourcePlanner) EnterDocument(operation, definition *ast.Document) {} -func (_ visitingDataSourcePlanner) EnterInlineFragment(ref int) {} -func (_ visitingDataSourcePlanner) LeaveInlineFragment(ref int) {} -func (_ visitingDataSourcePlanner) EnterSelectionSet(ref int) {} -func (_ visitingDataSourcePlanner) LeaveSelectionSet(ref int) {} -func (_ visitingDataSourcePlanner) EnterField(ref int) {} -func (_ visitingDataSourcePlanner) EnterArgument(ref int) {} -func (_ visitingDataSourcePlanner) LeaveField(ref int) {} - -func SimpleDataSourcePlanner(core CorePlanner) Planner { - return &visitingDataSourcePlanner{ - CorePlanner: core, - } -} - -type Argument interface { - ArgName() []byte -} - -type ContextVariableArgument struct { - Name []byte - VariableName []byte -} - -func (c *ContextVariableArgument) ArgName() []byte { - return c.Name -} - -type PathSelector struct { - Path string -} - -type ObjectVariableArgument struct { - Name []byte - PathSelector PathSelector -} - -func (o *ObjectVariableArgument) ArgName() []byte { - return o.Name -} - -type StaticVariableArgument struct { - Name []byte - Value []byte -} - -func (s *StaticVariableArgument) ArgName() []byte { - return s.Name -} - -type ListArgument struct { - Name []byte - Arguments []Argument -} - -func (l ListArgument) ArgName() []byte { - return l.Name -} - -func isWhitelistedScheme(scheme string, whitelistedSchemes []string, defaultSchemes []string) bool { - schemes := append(whitelistedSchemes, defaultSchemes...) - for _, whitelistedScheme := range schemes { - if scheme == whitelistedScheme { - return true - } - } - - return false -} - -func parseURLBytes(urlArg []byte) (parsedURL *url.URL, rawURL string, err error) { - rawURL = string(urlArg) - parsedURL, err = url.Parse(rawURL) - return parsedURL, rawURL, err -} diff --git a/pkg/execution/datasource/datasource_graphql.go b/pkg/execution/datasource/datasource_graphql.go deleted file mode 100644 index 6be0133a1..000000000 --- a/pkg/execution/datasource/datasource_graphql.go +++ /dev/null @@ -1,470 +0,0 @@ -package datasource - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - - "github.com/buger/jsonparser" - "github.com/cespare/xxhash/v2" - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astimport" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -var graphqlSchemes = []string{ - "https", - "http", -} - -type GraphqlRequest struct { - OperationName string `json:"operationName"` - Variables json.RawMessage `json:"variables"` - Query string `json:"query"` -} - -// GraphQLDataSourceConfig is the configuration for the GraphQL DataSource -type GraphQLDataSourceConfig struct { - // URL is the url of the upstream - URL string `bson:"url" json:"url"` - // Method is the http.Method of the upstream, defaults to POST (optional) - Method *string `bson:"method" json:"method"` -} - -type GraphQLDataSourcePlanner struct { - BasePlanner - importer *astimport.Importer - nodes []ast.Node - resolveDocument *ast.Document - dataSourceConfiguration GraphQLDataSourceConfig - client *http.Client - whitelistedSchemes []string - whitelistedVariableRefs []int - whitelistedVariableNameHashs map[uint64]bool - hooks Hooks -} - -type GraphQLDataSourcePlannerFactoryFactory struct { - Client *http.Client - WhitelistedSchemes []string - Hooks Hooks -} - -func (g *GraphQLDataSourcePlannerFactoryFactory) httpClient() *http.Client { - if g.Client != nil { - return g.Client - } - return DefaultHttpClient() -} - -func (g GraphQLDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &GraphQLDataSourcePlannerFactory{ - base: base, - client: g.httpClient(), - whitelistedSchemes: g.WhitelistedSchemes, - hooks: g.Hooks, - } - err := json.NewDecoder(configReader).Decode(&factory.config) - return factory, err -} - -type GraphQLDataSourcePlannerFactory struct { - base BasePlanner - config GraphQLDataSourceConfig - client *http.Client - whitelistedSchemes []string - hooks Hooks -} - -func (g *GraphQLDataSourcePlannerFactory) DataSourcePlanner() Planner { - return &GraphQLDataSourcePlanner{ - BasePlanner: g.base, - importer: &astimport.Importer{}, - dataSourceConfiguration: g.config, - resolveDocument: &ast.Document{}, - client: g.client, - whitelistedSchemes: g.whitelistedSchemes, - whitelistedVariableRefs: []int{}, - whitelistedVariableNameHashs: map[uint64]bool{}, - hooks: g.hooks, - } -} - -func (g *GraphQLDataSourcePlanner) EnterDocument(operation, definition *ast.Document) { - g.whitelistedVariableRefs = g.whitelistedVariableRefs[:0] -} - -func (g *GraphQLDataSourcePlanner) EnterInlineFragment(ref int) { - if len(g.nodes) == 0 { - return - } - current := g.nodes[len(g.nodes)-1] - if current.Kind != ast.NodeKindSelectionSet { - return - } - inlineFragmentType := g.importer.ImportType(g.Operation.InlineFragments[ref].TypeCondition.Type, g.Operation, g.resolveDocument) - g.resolveDocument.InlineFragments = append(g.resolveDocument.InlineFragments, ast.InlineFragment{ - TypeCondition: ast.TypeCondition{ - Type: inlineFragmentType, - }, - SelectionSet: -1, - }) - inlineFragmentRef := len(g.resolveDocument.InlineFragments) - 1 - g.resolveDocument.Selections = append(g.resolveDocument.Selections, ast.Selection{ - Kind: ast.SelectionKindInlineFragment, - Ref: inlineFragmentRef, - }) - selectionRef := len(g.resolveDocument.Selections) - 1 - g.resolveDocument.SelectionSets[current.Ref].SelectionRefs = append(g.resolveDocument.SelectionSets[current.Ref].SelectionRefs, selectionRef) - g.nodes = append(g.nodes, ast.Node{ - Kind: ast.NodeKindInlineFragment, - Ref: inlineFragmentRef, - }) -} - -func (g *GraphQLDataSourcePlanner) LeaveInlineFragment(ref int) { - g.nodes = g.nodes[:len(g.nodes)-1] -} - -func (g *GraphQLDataSourcePlanner) EnterSelectionSet(ref int) { - - fieldOrInlineFragment := g.nodes[len(g.nodes)-1] - - set := ast.SelectionSet{} - g.resolveDocument.SelectionSets = append(g.resolveDocument.SelectionSets, set) - setRef := len(g.resolveDocument.SelectionSets) - 1 - - switch fieldOrInlineFragment.Kind { - case ast.NodeKindField: - g.resolveDocument.Fields[fieldOrInlineFragment.Ref].HasSelections = true - g.resolveDocument.Fields[fieldOrInlineFragment.Ref].SelectionSet = setRef - case ast.NodeKindInlineFragment: - g.resolveDocument.InlineFragments[fieldOrInlineFragment.Ref].HasSelections = true - g.resolveDocument.InlineFragments[fieldOrInlineFragment.Ref].SelectionSet = setRef - } - - g.nodes = append(g.nodes, ast.Node{ - Kind: ast.NodeKindSelectionSet, - Ref: setRef, - }) -} - -func (g *GraphQLDataSourcePlanner) LeaveSelectionSet(ref int) { - g.nodes = g.nodes[:len(g.nodes)-1] -} - -func (g *GraphQLDataSourcePlanner) EnterField(ref int) { - if !g.RootField.isDefined { - g.RootField.SetIfNotDefined(ref) - - typeName := g.Definition.NodeNameString(g.Walker.EnclosingTypeDefinition) - fieldNameStr := g.Operation.FieldNameUnsafeString(ref) - fieldName := g.Operation.FieldNameBytes(ref) - - g.Args = append(g.Args, &StaticVariableArgument{ - Name: RootTypeName, - Value: []byte(typeName), - }) - - g.Args = append(g.Args, &StaticVariableArgument{ - Name: RootFieldName, - Value: fieldName, - }) - - mapping := g.Config.MappingForTypeField(typeName, fieldNameStr) - if mapping != nil && !mapping.Disabled { - fieldName = unsafebytes.StringToBytes(mapping.Path) - } - - hasArguments := g.Operation.FieldHasArguments(ref) - var argumentRefs []int - if hasArguments { - argumentRefs = g.importer.ImportArguments(g.Operation.FieldArguments(ref), g.Operation, g.resolveDocument) - } - - field := ast.Field{ - Name: g.resolveDocument.Input.AppendInputBytes(fieldName), - Arguments: ast.ArgumentList{ - Refs: argumentRefs, - }, - HasArguments: hasArguments, - } - g.resolveDocument.Fields = append(g.resolveDocument.Fields, field) - fieldRef := len(g.resolveDocument.Fields) - 1 - selection := ast.Selection{ - Kind: ast.SelectionKindField, - Ref: fieldRef, - } - g.resolveDocument.Selections = append(g.resolveDocument.Selections, selection) - selectionRef := len(g.resolveDocument.Selections) - 1 - set := ast.SelectionSet{ - SelectionRefs: []int{selectionRef}, - } - g.resolveDocument.SelectionSets = append(g.resolveDocument.SelectionSets, set) - setRef := len(g.resolveDocument.SelectionSets) - 1 - operationDefinition := ast.OperationDefinition{ - Name: g.resolveDocument.Input.AppendInputBytes([]byte("o")), - OperationType: g.Operation.OperationDefinitions[g.Walker.Ancestors[0].Ref].OperationType, - SelectionSet: setRef, - HasSelections: true, - } - g.resolveDocument.OperationDefinitions = append(g.resolveDocument.OperationDefinitions, operationDefinition) - operationDefinitionRef := len(g.resolveDocument.OperationDefinitions) - 1 - g.resolveDocument.RootNodes = append(g.resolveDocument.RootNodes, ast.Node{ - Kind: ast.NodeKindOperationDefinition, - Ref: operationDefinitionRef, - }) - g.nodes = append(g.nodes, ast.Node{ - Kind: ast.NodeKindOperationDefinition, - Ref: operationDefinitionRef, - }) - g.nodes = append(g.nodes, ast.Node{ - Kind: ast.NodeKindSelectionSet, - Ref: setRef, - }) - g.nodes = append(g.nodes, ast.Node{ - Kind: ast.NodeKindField, - Ref: fieldRef, - }) - } else { - field := ast.Field{ - Name: g.resolveDocument.Input.AppendInputBytes(g.Operation.FieldNameBytes(ref)), - } - g.resolveDocument.Fields = append(g.resolveDocument.Fields, field) - fieldRef := len(g.resolveDocument.Fields) - 1 - set := g.nodes[len(g.nodes)-1] - selection := ast.Selection{ - Kind: ast.SelectionKindField, - Ref: fieldRef, - } - g.resolveDocument.Selections = append(g.resolveDocument.Selections, selection) - selectionRef := len(g.resolveDocument.Selections) - 1 - g.resolveDocument.SelectionSets[set.Ref].SelectionRefs = append(g.resolveDocument.SelectionSets[set.Ref].SelectionRefs, selectionRef) - g.nodes = append(g.nodes, ast.Node{ - Kind: ast.NodeKindField, - Ref: fieldRef, - }) - } -} - -func (g *GraphQLDataSourcePlanner) EnterArgument(ref int) { - variableValue := g.Operation.ArgumentValue(ref) - if variableValue.Kind != ast.ValueKindVariable { - return - } - - variableName := g.Operation.VariableValueNameBytes(variableValue.Ref) - definitionRef, exists := g.Operation.VariableDefinitionByNameAndOperation(g.nodes[0].Ref, variableName) - if !exists { - return - } - - g.whitelistedVariableRefs = append(g.whitelistedVariableRefs, definitionRef) - g.whitelistedVariableNameHashs[xxhash.Sum64(variableName)] = true -} - -func (g *GraphQLDataSourcePlanner) LeaveField(ref int) { - defer func() { - g.nodes = g.nodes[:len(g.nodes)-1] - }() - if g.RootField.ref != ref { - return - } - - hasVariableDefinitions := len(g.Operation.OperationDefinitions[g.Walker.Ancestors[0].Ref].VariableDefinitions.Refs) != 0 - var variableDefinitionsRefs []int - if hasVariableDefinitions { - operationVariableDefinitions := g.Operation.OperationDefinitions[g.Walker.Ancestors[0].Ref].VariableDefinitions.Refs - definitions := make([]int, len(operationVariableDefinitions)) - copy(definitions, operationVariableDefinitions) - definitions = ast.FilterIntSliceByWhitelist(definitions, g.whitelistedVariableRefs) - - variableDefinitionsRefs = g.importer.ImportVariableDefinitions(definitions, g.Operation, g.resolveDocument) - g.resolveDocument.OperationDefinitions[0].HasVariableDefinitions = len(definitions) != 0 - g.resolveDocument.OperationDefinitions[0].VariableDefinitions.Refs = variableDefinitionsRefs - } - - buff := bytes.Buffer{} - err := astprinter.Print(g.resolveDocument, nil, &buff) - if err != nil { - g.Walker.StopWithInternalErr(err) - return - } - g.Args = append(g.Args, &StaticVariableArgument{ - Name: literal.URL, - Value: []byte(g.dataSourceConfiguration.URL), - }) - g.Args = append(g.Args, &StaticVariableArgument{ - Name: literal.QUERY, - Value: buff.Bytes(), - }) - if g.dataSourceConfiguration.Method == nil { - g.Args = append(g.Args, &StaticVariableArgument{ - Name: literal.METHOD, - Value: literal.HTTP_METHOD_POST, - }) - } else { - g.Args = append(g.Args, &StaticVariableArgument{ - Name: literal.URL, - Value: []byte(*g.dataSourceConfiguration.Method), - }) - } -} - -func (g *GraphQLDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - for i := range args { - if arg, ok := args[i].(*ContextVariableArgument); ok { - if bytes.HasPrefix(arg.Name, literal.DOT_ARGUMENTS_DOT) { - arg.Name = bytes.TrimPrefix(arg.Name, literal.DOT_ARGUMENTS_DOT) - - if g.whitelistedVariableNameHashs[xxhash.Sum64(arg.Name)] { - g.Args = append(g.Args, arg) - } else if g.whitelistedVariableNameHashs[xxhash.Sum64(arg.VariableName)] { - arg.Name = arg.VariableName - g.Args = append(g.Args, arg) - } - } - } - } - return &GraphQLDataSource{ - Log: g.Log, - Client: g.client, - WhitelistedSchemes: g.whitelistedSchemes, - Hooks: g.hooks, - }, g.Args -} - -type GraphQLDataSource struct { - Log log.Logger - Client *http.Client - WhitelistedSchemes []string - Hooks Hooks -} - -func (g *GraphQLDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - urlArg := args.ByKey(literal.URL) - queryArg := args.ByKey(literal.QUERY) - rootTypeName := args.ByKey(RootTypeName) - rootFieldName := args.ByKey(RootFieldName) - hookContext := HookContext{ - TypeName: string(rootTypeName), - FieldName: string(rootFieldName), - } - - g.Log.Debug("GraphQLDataSource.Resolve.Args", - log.Strings("resolvedArgs", args.Dump()), - ) - - if urlArg == nil || queryArg == nil { - g.Log.Error("GraphQLDataSource.Args invalid") - return - } - - parsedURL, rawURL, err := parseURLBytes(urlArg) - if err != nil { - g.Log.Error("GraphQLDataSource.RawURL could not be parsed", log.String("rawURL", rawURL)) - return - } - - if len(parsedURL.Scheme) == 0 || !isWhitelistedScheme(parsedURL.Scheme, g.WhitelistedSchemes, graphqlSchemes) { - parsedURL.Scheme = graphqlSchemes[0] - } - - variables := map[string]interface{}{} - keys := args.Keys() - for i := 0; i < len(keys); i++ { - switch { - case bytes.Equal(keys[i], literal.URL): - case bytes.Equal(keys[i], literal.QUERY): - case bytes.Equal(keys[i], RootTypeName): - case bytes.Equal(keys[i], RootFieldName): - default: - variables[string(keys[i])] = string(args.ByKey(keys[i])) - } - } - - variablesJson, err := json.Marshal(variables) - if err != nil { - g.Log.Error("GraphQLDataSource.json.Marshal(variables)", - log.Error(err), - ) - return n, err - } - - gqlRequest := GraphqlRequest{ - OperationName: "o", - Variables: variablesJson, - Query: string(queryArg), - } - - gqlRequestData, err := json.MarshalIndent(gqlRequest, "", " ") - if err != nil { - g.Log.Error("GraphQLDataSource.json.MarshalIndent", - log.Error(err), - ) - return n, err - } - - g.Log.Debug("GraphQLDataSource.request", - log.String("rawURL", rawURL), - log.String("parsedURL", parsedURL.String()), - log.ByteString("data", gqlRequestData), - ) - - request, err := http.NewRequest(http.MethodPost, parsedURL.String(), bytes.NewBuffer(gqlRequestData)) - if err != nil { - g.Log.Error("GraphQLDataSource.http.NewRequest", - log.Error(err), - ) - return n, err - } - - request.Header.Add("Content-Type", "application/json") - request.Header.Add("Accept", "application/json") - - if g.Hooks.PreSendHttpHook != nil { - g.Hooks.PreSendHttpHook.Execute(hookContext, request) - } - - res, err := g.Client.Do(request) - if err != nil { - g.Log.Error("GraphQLDataSource.client.Do", - log.Error(err), - ) - return n, err - } - data, err := io.ReadAll(res.Body) - if err != nil { - g.Log.Error("GraphQLDataSource.ioutil.ReadAll", - log.Error(err), - ) - return n, err - } - - if g.Hooks.PostReceiveHttpHook != nil { - g.Hooks.PostReceiveHttpHook.Execute(hookContext, res, data) - } - - defer func() { - err := res.Body.Close() - if err != nil { - g.Log.Error("GraphQLDataSource.Resolve.Response.Body.Close", log.Error(err)) - } - }() - - data = bytes.ReplaceAll(data, literal.BACKSLASH, nil) - data, _, _, err = jsonparser.Get(data, "data") - if err != nil { - g.Log.Error("GraphQLDataSource.jsonparser.Get", - log.Error(err), - ) - return n, err - } - return out.Write(data) -} diff --git a/pkg/execution/datasource/datasource_http_json.go b/pkg/execution/datasource/datasource_http_json.go deleted file mode 100644 index 522e7b7c9..000000000 --- a/pkg/execution/datasource/datasource_http_json.go +++ /dev/null @@ -1,400 +0,0 @@ -package datasource - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "strconv" - - "github.com/buger/jsonparser" - log "github.com/jensneuse/abstractlogger" - "github.com/tidwall/gjson" - "github.com/tidwall/sjson" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -var httpJsonSchemes = []string{ - "https", - "http", -} - -// HttpJsonDataSourceConfig is the configuration object for the HttpJsonDataSource -type HttpJsonDataSourceConfig struct { - // URL is the url of the upstream - URL string `bson:"url" json:"url"` - // Method is the http.Method, e.g. GET, POST, UPDATE, DELETE - // default is GET - Method *string `bson:"method" json:"method"` - // Body is the http body to send - // default is null/nil (no body) - Body *string `bson:"body" json:"body"` - // Headers defines the header mappings - Headers []HttpJsonDataSourceConfigHeader `bson:"headers" json:"headers"` - // DefaultTypeName is the optional variable to define a default type name for the response object - // This is useful in case the response might be a Union or Interface type which uses StatusCodeTypeNameMappings - DefaultTypeName *string `bson:"default_type_name" json:"default_type_name"` - // StatusCodeTypeNameMappings is a slice of mappings from http.StatusCode to GraphQL TypeName - // This can be used when the TypeName depends on the http.StatusCode - StatusCodeTypeNameMappings []StatusCodeTypeNameMapping `bson:"status_code_type_name_mappings" json:"status_code_type_name_mappings"` -} - -type StatusCodeTypeNameMapping struct { - StatusCode int `bson:"status_code" json:"status_code"` - TypeName string `bson:"type_name" json:"type_name"` -} - -type HttpJsonDataSourceConfigHeader struct { - Key string `bson:"key" json:"key"` - Value string `bson:"value" json:"value"` -} - -type HttpJsonDataSourcePlannerFactoryFactory struct { - Client *http.Client - WhitelistedSchemes []string - Hooks Hooks -} - -func (h *HttpJsonDataSourcePlannerFactoryFactory) httpClient() *http.Client { - if h.Client != nil { - return h.Client - } - return DefaultHttpClient() -} - -func (h *HttpJsonDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &HttpJsonDataSourcePlannerFactory{ - base: base, - client: h.httpClient(), - whitelistedSchemes: h.WhitelistedSchemes, - hooks: h.Hooks, - } - err := json.NewDecoder(configReader).Decode(&factory.config) - return factory, err -} - -type HttpJsonDataSourcePlannerFactory struct { - base BasePlanner - config HttpJsonDataSourceConfig - client *http.Client - whitelistedSchemes []string - hooks Hooks -} - -func (h *HttpJsonDataSourcePlannerFactory) DataSourcePlanner() Planner { - return &HttpJsonDataSourcePlanner{ - BasePlanner: h.base, - dataSourceConfig: h.config, - client: h.client, - whitelistedSchemes: h.whitelistedSchemes, - hooks: h.hooks, - } -} - -type HttpJsonDataSourcePlanner struct { - BasePlanner - dataSourceConfig HttpJsonDataSourceConfig - client *http.Client - whitelistedSchemes []string - hooks Hooks -} - -func (h *HttpJsonDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - return &HttpJsonDataSource{ - Log: h.Log, - Client: h.client, - WhitelistedSchemes: h.whitelistedSchemes, - Hooks: h.hooks, - }, append(h.Args, args...) -} - -func (h *HttpJsonDataSourcePlanner) EnterDocument(operation, definition *ast.Document) { - -} - -func (h *HttpJsonDataSourcePlanner) EnterInlineFragment(ref int) { - -} - -func (h *HttpJsonDataSourcePlanner) LeaveInlineFragment(ref int) { - -} - -func (h *HttpJsonDataSourcePlanner) EnterSelectionSet(ref int) { - -} - -func (h *HttpJsonDataSourcePlanner) LeaveSelectionSet(ref int) { - -} - -func (h *HttpJsonDataSourcePlanner) EnterField(ref int) { - if !h.RootField.isDefined { - h.RootField.SetIfNotDefined(ref) - - typeName := h.Definition.NodeNameBytes(h.Walker.EnclosingTypeDefinition) - fieldName := h.Operation.FieldNameBytes(ref) - - h.Args = append(h.Args, &StaticVariableArgument{ - Name: RootTypeName, - Value: typeName, - }) - - h.Args = append(h.Args, &StaticVariableArgument{ - Name: RootFieldName, - Value: fieldName, - }) - } -} - -func (h *HttpJsonDataSourcePlanner) EnterArgument(ref int) {} - -func (h *HttpJsonDataSourcePlanner) LeaveField(ref int) { - if !h.RootField.IsDefinedAndEquals(ref) { - return - } - definition, exists := h.Walker.FieldDefinition(ref) - if !exists { - return - } - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.URL, - Value: []byte(h.dataSourceConfig.URL), - }) - if h.dataSourceConfig.Method == nil { - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.METHOD, - Value: literal.HTTP_METHOD_GET, - }) - } else { - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte(*h.dataSourceConfig.Method), - }) - } - if h.dataSourceConfig.Body != nil { - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.BODY, - Value: []byte(*h.dataSourceConfig.Body), - }) - } - - if len(h.dataSourceConfig.Headers) != 0 { - listArg := &ListArgument{ - Name: literal.HEADERS, - } - for i := range h.dataSourceConfig.Headers { - listArg.Arguments = append(listArg.Arguments, &StaticVariableArgument{ - Name: []byte(h.dataSourceConfig.Headers[i].Key), - Value: []byte(h.dataSourceConfig.Headers[i].Value), - }) - } - h.Args = append(h.Args, listArg) - } - - // __typename - var typeNameValue []byte - var err error - fieldDefinitionTypeNode := h.Definition.FieldDefinitionTypeNode(definition) - fieldDefinitionType := h.Definition.FieldDefinitionType(definition) - fieldDefinitionTypeName := h.Definition.ResolveTypeNameBytes(fieldDefinitionType) - quotedFieldDefinitionTypeName := append(literal.QUOTE, append(fieldDefinitionTypeName, literal.QUOTE...)...) - switch fieldDefinitionTypeNode.Kind { - case ast.NodeKindScalarTypeDefinition: - return - case ast.NodeKindUnionTypeDefinition, ast.NodeKindInterfaceTypeDefinition: - if h.dataSourceConfig.DefaultTypeName != nil { - typeNameValue, err = sjson.SetRawBytes(typeNameValue, "defaultTypeName", []byte("\""+*h.dataSourceConfig.DefaultTypeName+"\"")) - if err != nil { - h.Log.Error("HttpJsonDataSourcePlanner set defaultTypeName (switch case union/interface)", log.Error(err)) - return - } - } - for i := range h.dataSourceConfig.StatusCodeTypeNameMappings { - typeNameValue, err = sjson.SetRawBytes(typeNameValue, strconv.Itoa(h.dataSourceConfig.StatusCodeTypeNameMappings[i].StatusCode), []byte("\""+h.dataSourceConfig.StatusCodeTypeNameMappings[i].TypeName+"\"")) - if err != nil { - h.Log.Error("HttpJsonDataSourcePlanner set statusCodeTypeMapping", log.Error(err)) - return - } - } - default: - typeNameValue, err = sjson.SetRawBytes(typeNameValue, "defaultTypeName", quotedFieldDefinitionTypeName) - if err != nil { - h.Log.Error("HttpJsonDataSourcePlanner set defaultTypeName (switch case default)", log.Error(err)) - return - } - } - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.TYPENAME, - Value: typeNameValue, - }) -} - -type HttpJsonDataSource struct { - Log log.Logger - Client *http.Client - WhitelistedSchemes []string - Hooks Hooks -} - -func (r *HttpJsonDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - urlArg := args.ByKey(literal.URL) - methodArg := args.ByKey(literal.METHOD) - bodyArg := args.ByKey(literal.BODY) - headersArg := args.ByKey(literal.HEADERS) - typeNameArg := args.ByKey(literal.TYPENAME) - rootTypeName := args.ByKey(RootTypeName) - rootFieldName := args.ByKey(RootFieldName) - hookContext := HookContext{ - TypeName: string(rootTypeName), - FieldName: string(rootFieldName), - } - - r.Log.Debug("HttpJsonDataSource.Resolve.Args", - log.Strings("resolvedArgs", args.Dump()), - ) - - switch { - case urlArg == nil: - r.Log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.URL))) - return - case methodArg == nil: - r.Log.Error(fmt.Sprintf("arg '%s' must not be nil", string(literal.METHOD))) - return - } - - httpMethod := http.MethodGet - switch { - case bytes.Equal(methodArg, literal.HTTP_METHOD_GET): - httpMethod = http.MethodGet - case bytes.Equal(methodArg, literal.HTTP_METHOD_POST): - httpMethod = http.MethodPost - case bytes.Equal(methodArg, literal.HTTP_METHOD_PUT): - httpMethod = http.MethodPut - case bytes.Equal(methodArg, literal.HTTP_METHOD_DELETE): - httpMethod = http.MethodDelete - case bytes.Equal(methodArg, literal.HTTP_METHOD_PATCH): - httpMethod = http.MethodPatch - } - - parsedURL, rawURL, err := parseURLBytes(urlArg) - if err != nil { - r.Log.Error("HttpJsonDataSource.RawURL could not be parsed", log.String("rawURL", rawURL)) - return - } - - if len(parsedURL.Scheme) == 0 || !isWhitelistedScheme(parsedURL.Scheme, r.WhitelistedSchemes, httpJsonSchemes) { - parsedURL.Scheme = httpJsonSchemes[0] - } - - header := make(http.Header) - if len(headersArg) != 0 { - err := jsonparser.ObjectEach(headersArg, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { - header.Set(string(key), string(value)) - return nil - }) - if err != nil { - r.Log.Error("accessing headers", log.Error(err)) - } - } - - r.Log.Debug("HttpJsonDataSource.Resolve", - log.String("rawURL", rawURL), - log.String("parsedURL", parsedURL.String()), - ) - - var bodyReader io.Reader - if len(bodyArg) != 0 { - bodyReader = bytes.NewReader(bodyArg) - } - - request, err := http.NewRequest(httpMethod, parsedURL.String(), bodyReader) - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.NewRequest", - log.Error(err), - ) - return - } - - request.Header = header - - if r.Hooks.PreSendHttpHook != nil { - r.Hooks.PreSendHttpHook.Execute(hookContext, request) - } - - res, err := r.Client.Do(request) - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.HTTPClient.Do", - log.Error(err), - ) - return - } - - data, err := io.ReadAll(res.Body) - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.ioutil.ReadAll", - log.Error(err), - ) - return - } - - if r.Hooks.PostReceiveHttpHook != nil { - r.Hooks.PostReceiveHttpHook.Execute(hookContext, res, data) - } - - defer func() { - err := res.Body.Close() - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.Response.Body.Close", log.Error(err)) - } - }() - - statusCode := strconv.Itoa(res.StatusCode) - statusCodeTypeName := gjson.GetBytes(typeNameArg, statusCode) - defaultTypeName := gjson.GetBytes(typeNameArg, "defaultTypeName") - var result *gjson.Result - if statusCodeTypeName.Exists() { - result = &statusCodeTypeName - } - if result == nil && defaultTypeName.Exists() { - result = &defaultTypeName - } - - if result != nil { - parsed := gjson.ParseBytes(data) - if parsed.IsArray() { - arrayData := []byte(`[]`) - items := parsed.Array() - for i := range items { - item, err := sjson.SetRaw(items[i].Raw, "__typename", result.Raw) - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.array.setDefaultTypeName", - log.Error(err), - ) - } - arrayData, err = sjson.SetRawBytes(arrayData, "-1", unsafebytes.StringToBytes(item)) - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.array.setArrayItem", - log.Error(err), - ) - } - } - data = arrayData - } else { - data, err = sjson.SetRawBytes(data, "__typename", []byte(result.Raw)) - if err != nil { - r.Log.Error("HttpJsonDataSource.Resolve.setDefaultTypeName", - log.Error(err), - ) - return - } - } - } - - return out.Write(data) -} diff --git a/pkg/execution/datasource/datasource_http_polling_stream.go b/pkg/execution/datasource/datasource_http_polling_stream.go deleted file mode 100644 index 20f024fe9..000000000 --- a/pkg/execution/datasource/datasource_http_polling_stream.go +++ /dev/null @@ -1,267 +0,0 @@ -package datasource - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "strings" - "sync" - "text/template" - "time" - - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type HttpPollingStreamDataSourceConfiguration struct { - Host string - URL string - DelaySeconds *int -} - -type HttpPollingStreamDataSourcePlannerFactoryFactory struct { -} - -func (h HttpPollingStreamDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &HttpPollingStreamDataSourcePlannerFactory{ - base: base, - } - return factory, json.NewDecoder(configReader).Decode(&factory.config) -} - -type HttpPollingStreamDataSourcePlannerFactory struct { - base BasePlanner - config HttpPollingStreamDataSourceConfiguration -} - -func (h HttpPollingStreamDataSourcePlannerFactory) DataSourcePlanner() Planner { - return &HttpPollingStreamDataSourcePlanner{ - BasePlanner: h.base, - dataSourceConfig: h.config, - } -} - -type HttpPollingStreamDataSourcePlanner struct { - BasePlanner - dataSourceConfig HttpPollingStreamDataSourceConfiguration - delay time.Duration -} - -func (h *HttpPollingStreamDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - return &HttpPollingStreamDataSource{ - Log: h.Log, - Delay: h.delay, - }, append(h.Args, args...) -} - -func (h *HttpPollingStreamDataSourcePlanner) EnterDocument(operation, definition *ast.Document) { - -} - -func (h *HttpPollingStreamDataSourcePlanner) EnterInlineFragment(ref int) { - -} - -func (h *HttpPollingStreamDataSourcePlanner) LeaveInlineFragment(ref int) { - -} - -func (h *HttpPollingStreamDataSourcePlanner) EnterSelectionSet(ref int) { - -} - -func (h *HttpPollingStreamDataSourcePlanner) LeaveSelectionSet(ref int) { - -} - -func (h *HttpPollingStreamDataSourcePlanner) EnterField(ref int) { - h.RootField.SetIfNotDefined(ref) -} - -func (h *HttpPollingStreamDataSourcePlanner) EnterArgument(ref int) { - -} - -func (h *HttpPollingStreamDataSourcePlanner) LeaveField(ref int) { - if !h.RootField.IsDefinedAndEquals(ref) { - return - } - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.HOST, - Value: []byte(h.dataSourceConfig.Host), - }) - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.URL, - Value: []byte(h.dataSourceConfig.URL), - }) - if h.dataSourceConfig.DelaySeconds == nil { - h.delay = time.Second * time.Duration(1) - } else { - h.delay = time.Second * time.Duration(*h.dataSourceConfig.DelaySeconds) - } -} - -type HttpPollingStreamDataSource struct { - Log log.Logger - once sync.Once - ch chan []byte - Delay time.Duration - client *http.Client - request *http.Request - lastData []byte - - // The mutex guards the fields following it. Use the - // accessor methods to read/write them. - mu sync.RWMutex - closed bool -} - -func (s *HttpPollingStreamDataSource) close() { - s.mu.Lock() - defer s.mu.Unlock() - s.closed = true -} - -func (s *HttpPollingStreamDataSource) isClosed() bool { - s.mu.RLock() - defer s.mu.RUnlock() - return s.closed -} - -func (h *HttpPollingStreamDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - h.once.Do(func() { - h.ch = make(chan []byte) - h.request = h.generateRequest(args) - h.client = &http.Client{ - Timeout: time.Second * 5, - Transport: &http.Transport{ - MaxIdleConnsPerHost: 1024, - TLSHandshakeTimeout: 0 * time.Second, - }, - } - go h.startPolling(ctx) - }) - if h.isClosed() { - return - } - select { - case data := <-h.ch: - h.Log.Debug("HttpPollingStreamDataSource.Resolve.out.Write", - log.ByteString("data", data), - ) - _, err := out.Write(data) - if err != nil { - h.Log.Error("HttpPollingStreamDataSource.Resolve", - log.Error(err), - ) - } - case <-ctx.Done(): - h.close() - return - } - return -} - -func (h *HttpPollingStreamDataSource) startPolling(ctx context.Context) { - first := true - for { - if first { - first = !first - } else { - time.Sleep(h.Delay) - } - var data []byte - select { - case <-ctx.Done(): - h.close() - return - default: - response, err := h.client.Do(h.request) - if err != nil { - h.Log.Error("HttpPollingStreamDataSource.startPolling.client.Do", - log.Error(err), - ) - return - } - data, err = io.ReadAll(response.Body) - if err != nil { - h.Log.Error("HttpPollingStreamDataSource.startPolling.ioutil.ReadAll", - log.Error(err), - ) - return - } - } - if bytes.Equal(data, h.lastData) { - continue - } - h.lastData = data - select { - case <-ctx.Done(): - h.close() - return - case h.ch <- data: - continue - } - } -} - -func (h *HttpPollingStreamDataSource) generateRequest(args ResolverArgs) *http.Request { - hostArg := args.ByKey(literal.HOST) - urlArg := args.ByKey(literal.URL) - - h.Log.Debug("HttpPollingStreamDataSource.generateRequest.Resolve.Args", - log.Strings("resolvedArgs", args.Dump()), - ) - - if hostArg == nil || urlArg == nil { - h.Log.Error("HttpPollingStreamDataSource.generateRequest.Args invalid") - return nil - } - - url := string(hostArg) + string(urlArg) - if !strings.HasPrefix(url, "https://") && !strings.HasPrefix(url, "http://") { - url = "https://" + url - } - - if strings.Contains(url, "{{") { - tmpl, err := template.New("url").Parse(url) - if err != nil { - h.Log.Error("HttpPollingStreamDataSource.generateRequest.template.New", - log.Error(err), - ) - return nil - } - out := bytes.Buffer{} - keys := args.Keys() - data := make(map[string]string, len(keys)) - for i := 0; i < len(keys); i++ { - data[string(keys[i])] = string(args.ByKey(keys[i])) - } - err = tmpl.Execute(&out, data) - if err != nil { - h.Log.Error("HttpPollingStreamDataSource.generateRequest.tmpl.Execute", - log.Error(err), - ) - return nil - } - url = out.String() - } - - h.Log.Debug("HttpPollingStreamDataSource.generateRequest.Resolve", - log.String("url", url), - ) - - request, err := http.NewRequest(http.MethodGet, url, nil) - if err != nil { - h.Log.Error("HttpPollingStreamDataSource.generateRequest.Resolve.NewRequest", - log.Error(err), - ) - return nil - } - request.Header.Add("Accept", "application/json") - return request -} diff --git a/pkg/execution/datasource/datasource_mqtt.go b/pkg/execution/datasource/datasource_mqtt.go deleted file mode 100644 index 911d3986b..000000000 --- a/pkg/execution/datasource/datasource_mqtt.go +++ /dev/null @@ -1,178 +0,0 @@ -package datasource - -import ( - "context" - "encoding/json" - "io" - "sync" - "time" - - mqtt "github.com/eclipse/paho.mqtt.golang" - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type MQTTDataSourceConfig struct { - BrokerAddr string - ClientID string - Topic string -} - -type MQTTDataSourcePlannerFactoryFactory struct { -} - -func (M MQTTDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &MQTTDataSourcePlannerFactory{ - base: base, - } - return factory, json.NewDecoder(configReader).Decode(&factory.config) -} - -type MQTTDataSourcePlannerFactory struct { - base BasePlanner - config MQTTDataSourceConfig -} - -func (m MQTTDataSourcePlannerFactory) DataSourcePlanner() Planner { - return &MQTTDataSourcePlanner{ - BasePlanner: m.base, - dataSourceConfig: m.config, - } -} - -type MQTTDataSourcePlanner struct { - BasePlanner - dataSourceConfig MQTTDataSourceConfig -} - -func (n *MQTTDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - return &MQTTDataSource{ - log: n.Log, - }, append(n.Args, args...) -} - -func (n *MQTTDataSourcePlanner) EnterDocument(operation, definition *ast.Document) { - -} - -func (n *MQTTDataSourcePlanner) EnterInlineFragment(ref int) { - -} - -func (n *MQTTDataSourcePlanner) LeaveInlineFragment(ref int) { - -} - -func (n *MQTTDataSourcePlanner) EnterSelectionSet(ref int) { - -} - -func (n *MQTTDataSourcePlanner) LeaveSelectionSet(ref int) { - -} - -func (n *MQTTDataSourcePlanner) EnterField(ref int) { - n.RootField.SetIfNotDefined(ref) -} - -func (n *MQTTDataSourcePlanner) EnterArgument(ref int) { - -} - -func (n *MQTTDataSourcePlanner) LeaveField(ref int) { - if !n.RootField.IsDefinedAndEquals(ref) { - return - } - n.Args = append(n.Args, &StaticVariableArgument{ - Name: literal.BROKERADDR, - Value: []byte(n.dataSourceConfig.BrokerAddr), - }) - n.Args = append(n.Args, &StaticVariableArgument{ - Name: literal.CLIENTID, - Value: []byte(n.dataSourceConfig.ClientID), - }) - n.Args = append(n.Args, &StaticVariableArgument{ - Name: literal.TOPIC, - Value: []byte(n.dataSourceConfig.Topic), - }) -} - -type MQTTDataSource struct { - log log.Logger - once sync.Once - ch chan mqtt.Message - client mqtt.Client -} - -func (m *MQTTDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - - defer func() { - select { - case <-ctx.Done(): - m.log.Debug("MQTTDataSource.Resolve.client.Disconnect") - m.client.Disconnect(250) - m.log.Debug("MQTTDataSource.Resolve.client.Disconnect.disconnected") - default: - return - } - }() - - m.once.Do(func() { - - brokerArg := args.ByKey(literal.BROKERADDR) - clientIDArg := args.ByKey(literal.CLIENTID) - topicArg := args.ByKey(literal.TOPIC) - - m.log.Debug("MQTTDataSource.Resolve.init", - log.String("broker", string(brokerArg)), - log.String("clientID", string(clientIDArg)), - log.String("topic", string(topicArg)), - ) - - m.ch = make(chan mqtt.Message) - m.start(string(brokerArg), string(clientIDArg), string(topicArg)) - }) - - select { - case <-ctx.Done(): - return - case msg, ok := <-m.ch: - if !ok { - return - } - return out.Write(msg.Payload()) - } -} - -func (m *MQTTDataSource) start(brokerAddr, clientID, topic string) { - mqtt.ERROR = m.log.LevelLogger(log.ErrorLevel) - mqtt.DEBUG = m.log.LevelLogger(log.DebugLevel) - opts := mqtt.NewClientOptions().AddBroker(brokerAddr).SetClientID(clientID) - opts.SetKeepAlive(5 * time.Second) - opts.SetResumeSubs(true) - opts.SetAutoReconnect(true) - opts.SetDefaultPublishHandler(func(client mqtt.Client, msg mqtt.Message) { - m.ch <- msg - msg.Ack() - }) - opts.SetPingTimeout(5 * time.Second) - - m.client = mqtt.NewClient(opts) - if token := m.client.Connect(); token.Wait() && token.Error() != nil { - m.log.Error("MQTTDataSource.start.Connect", - log.Error(token.Error()), - ) - close(m.ch) - return - } - - if token := m.client.Subscribe(topic, 0, nil); token.Wait() && token.Error() != nil { - m.log.Error("MQTTDataSource.start.Subscribe", - log.Error(token.Error()), - ) - close(m.ch) - return - } -} diff --git a/pkg/execution/datasource/datasource_nats.go b/pkg/execution/datasource/datasource_nats.go deleted file mode 100644 index 61a74cb87..000000000 --- a/pkg/execution/datasource/datasource_nats.go +++ /dev/null @@ -1,134 +0,0 @@ -package datasource - -import ( - "context" - "encoding/json" - "io" - "sync" - "time" - - log "github.com/jensneuse/abstractlogger" - "github.com/nats-io/nats.go" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type NatsDataSourceConfig struct { - Addr string - Topic string -} - -type NatsDataSourcePlannerFactoryFactory struct { -} - -func (n NatsDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &NatsDataSourcePlannerFactory{ - base: base, - } - return factory, json.NewDecoder(configReader).Decode(&factory.config) -} - -type NatsDataSourcePlannerFactory struct { - base BasePlanner - config NatsDataSourceConfig -} - -func (n NatsDataSourcePlannerFactory) DataSourcePlanner() Planner { - return SimpleDataSourcePlanner(&NatsDataSourcePlanner{ - BasePlanner: n.base, - dataSourceConfig: n.config, - }) -} - -type NatsDataSourcePlanner struct { - BasePlanner - dataSourceConfig NatsDataSourceConfig -} - -func (n *NatsDataSourcePlanner) Plan([]Argument) (DataSource, []Argument) { - n.Args = append(n.Args, &StaticVariableArgument{ - Name: literal.ADDR, - Value: []byte(n.dataSourceConfig.Addr), - }) - n.Args = append(n.Args, &StaticVariableArgument{ - Name: literal.TOPIC, - Value: []byte(n.dataSourceConfig.Topic), - }) - return &NatsDataSource{ - log: n.Log, - }, n.Args -} - -type NatsDataSource struct { - log log.Logger - conn *nats.Conn - sub *nats.Subscription - once sync.Once -} - -func (d *NatsDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - d.once.Do(func() { - - addrArg := args.ByKey(literal.ADDR) - topicArg := args.ByKey(literal.TOPIC) - - addr := nats.DefaultURL - topic := string(topicArg) - - if len(addrArg) != 0 { - addr = string(addrArg) - } - - go func() { - <-ctx.Done() - if d.sub != nil { - d.log.Debug("NatsDataSource.unsubscribing", - log.String("addr", addr), - log.String("topic", topic), - ) - err := d.sub.Unsubscribe() - if err != nil { - d.log.Error("Unsubscribe", log.Error(err)) - } - } - if d.conn != nil { - d.log.Debug("NatsDataSource.closing", - log.String("addr", addr), - log.String("topic", topic), - ) - d.conn.Close() - } - }() - - d.log.Debug("NatsDataSource.connecting", - log.String("addr", addr), - log.String("topic", topic), - ) - - d.conn, err = nats.Connect(addr) - if err != nil { - panic(err) - } - - d.log.Debug("NatsDataSource.subscribing", - log.String("addr", addr), - log.String("topic", topic), - ) - - d.sub, err = d.conn.SubscribeSync(topic) - if err != nil { - panic(err) - } - }) - - if err != nil { - return n, err - } - - message, err := d.sub.NextMsg(time.Minute) - if err != nil { - return n, err - } - - return out.Write(message.Data) -} diff --git a/pkg/execution/datasource/datasource_pipeline.go b/pkg/execution/datasource/datasource_pipeline.go deleted file mode 100644 index 497fc6a90..000000000 --- a/pkg/execution/datasource/datasource_pipeline.go +++ /dev/null @@ -1,142 +0,0 @@ -package datasource - -import ( - "bytes" - "context" - "encoding/json" - "io" - "os" - - log "github.com/jensneuse/abstractlogger" - "github.com/jensneuse/pipeline/pkg/pipe" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type PipelineDataSourceConfig struct { - /* - ConfigFilePath is the path where the Pipeline configuration file can be found - it needs to be in the json format according to the Pipeline json schema - see this url for more info: https://github.com/jensneuse/pipeline - */ - ConfigFilePath *string - /* - ConfigString is a string to configure the Pipeline - it needs to be in the json format according to the Pipeline json schema - see this url for more info: https://github.com/jensneuse/pipeline - The PipelinDataSourcePlanner will always choose the configString over the configFilePath in case both are defined. - */ - ConfigString *string - // InputJSON is the template to define a JSON object based on the request, parameters etc. which gets passed to the first Pipeline step - InputJSON string -} - -type PipelineDataSourcePlannerFactoryFactory struct { -} - -func (p PipelineDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &PipelineDataSourcePlannerFactory{ - base: base, - } - return factory, json.NewDecoder(configReader).Decode(&factory.config) -} - -type PipelineDataSourcePlannerFactory struct { - base BasePlanner - config PipelineDataSourceConfig -} - -func (p PipelineDataSourcePlannerFactory) DataSourcePlanner() Planner { - return &PipelineDataSourcePlanner{ - BasePlanner: p.base, - dataSourceConfig: p.config, - } -} - -type PipelineDataSourcePlanner struct { - BasePlanner - dataSourceConfig PipelineDataSourceConfig - rawPipelineConfig []byte -} - -func (h *PipelineDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - - source := PipelineDataSource{ - Log: h.Log, - } - - err := source.Pipeline.FromConfig(bytes.NewReader(h.rawPipelineConfig)) - if err != nil { - h.Log.Error("PipelineDataSourcePlanner.pipe.FromConfig", log.Error(err)) - } - - return &source, append(h.Args, args...) -} - -func (h *PipelineDataSourcePlanner) EnterDocument(operation, definition *ast.Document) { - -} - -func (h *PipelineDataSourcePlanner) EnterInlineFragment(ref int) { - -} - -func (h *PipelineDataSourcePlanner) LeaveInlineFragment(ref int) { - -} - -func (h *PipelineDataSourcePlanner) EnterSelectionSet(ref int) { - -} - -func (h *PipelineDataSourcePlanner) LeaveSelectionSet(ref int) { - -} - -func (h *PipelineDataSourcePlanner) EnterField(ref int) { - h.RootField.SetIfNotDefined(ref) -} - -func (h *PipelineDataSourcePlanner) EnterArgument(ref int) { - -} - -func (h *PipelineDataSourcePlanner) LeaveField(ref int) { - if !h.RootField.IsDefinedAndEquals(ref) { - return - } - - if h.dataSourceConfig.ConfigString != nil { - h.rawPipelineConfig = []byte(*h.dataSourceConfig.ConfigString) - } - if h.dataSourceConfig.ConfigFilePath != nil { - var err error - h.rawPipelineConfig, err = os.ReadFile(*h.dataSourceConfig.ConfigFilePath) - if err != nil { - h.Log.Error("PipelineDataSourcePlanner.readConfigFile", log.Error(err)) - } - } - - h.Args = append(h.Args, &StaticVariableArgument{ - Name: literal.INPUT_JSON, - Value: []byte(h.dataSourceConfig.InputJSON), - }) -} - -type PipelineDataSource struct { - Log log.Logger - Pipeline pipe.Pipeline -} - -func (r *PipelineDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - - inputJSON := args.ByKey(literal.INPUT_JSON) - - err = r.Pipeline.Run(bytes.NewReader(inputJSON), out) - if err != nil { - r.Log.Error("PipelineDataSource.pipe.Run", log.Error(err)) - } - - return -} diff --git a/pkg/execution/datasource/datasource_schema.go b/pkg/execution/datasource/datasource_schema.go deleted file mode 100644 index 22bb2c88d..000000000 --- a/pkg/execution/datasource/datasource_schema.go +++ /dev/null @@ -1,66 +0,0 @@ -package datasource - -import ( - "context" - "encoding/json" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/introspection" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type SchemaDataSourcePlannerConfig struct { -} - -type SchemaDataSourcePlannerFactoryFactory struct { -} - -func (s SchemaDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &SchemaDataSourcePlannerFactory{ - base: base, - } - err := json.NewDecoder(configReader).Decode(&factory.config) - if err != nil { - return factory, err - } - gen := introspection.NewGenerator() - var data introspection.Data - var report operationreport.Report - gen.Generate(base.Definition, &report, &data) - factory.schemaBytes, err = json.Marshal(data) - return factory, err -} - -type SchemaDataSourcePlannerFactory struct { - base BasePlanner - config SchemaDataSourcePlannerConfig - schemaBytes []byte -} - -func (s SchemaDataSourcePlannerFactory) DataSourcePlanner() Planner { - return SimpleDataSourcePlanner(&SchemaDataSourcePlanner{ - BasePlanner: s.base, - dataSourceConfig: s.config, - schemaBytes: s.schemaBytes, - }) -} - -type SchemaDataSourcePlanner struct { - BasePlanner - dataSourceConfig SchemaDataSourcePlannerConfig - schemaBytes []byte -} - -func (s *SchemaDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - return &SchemaDataSource{ - SchemaBytes: s.schemaBytes, - }, append(s.Args, args...) -} - -type SchemaDataSource struct { - SchemaBytes []byte -} - -func (s *SchemaDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - return out.Write(s.SchemaBytes) -} diff --git a/pkg/execution/datasource/datasource_static.go b/pkg/execution/datasource/datasource_static.go deleted file mode 100644 index ef8f83420..000000000 --- a/pkg/execution/datasource/datasource_static.go +++ /dev/null @@ -1,52 +0,0 @@ -package datasource - -import ( - "context" - "encoding/json" - "io" -) - -type StaticDataSourceConfig struct { - Data string -} - -type StaticDataSourcePlannerFactoryFactory struct { -} - -func (s StaticDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := &StaticDataSourcePlannerFactory{ - base: base, - } - return factory, json.NewDecoder(configReader).Decode(&factory.config) -} - -type StaticDataSourcePlannerFactory struct { - base BasePlanner - config StaticDataSourceConfig -} - -func (s StaticDataSourcePlannerFactory) DataSourcePlanner() Planner { - return SimpleDataSourcePlanner(&StaticDataSourcePlanner{ - BasePlanner: s.base, - dataSourceConfig: s.config, - }) -} - -type StaticDataSourcePlanner struct { - BasePlanner - dataSourceConfig StaticDataSourceConfig -} - -func (s *StaticDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - return &StaticDataSource{ - Data: []byte(s.dataSourceConfig.Data), - }, append(s.Args, args...) -} - -type StaticDataSource struct { - Data []byte -} - -func (s StaticDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - return out.Write(s.Data) -} diff --git a/pkg/execution/datasource/datasource_type.go b/pkg/execution/datasource/datasource_type.go deleted file mode 100644 index 5e42207b2..000000000 --- a/pkg/execution/datasource/datasource_type.go +++ /dev/null @@ -1,48 +0,0 @@ -package datasource - -import ( - "context" - "encoding/json" - "io" -) - -type TypeDataSourcePlannerConfig struct { -} - -type TypeDataSourcePlannerFactoryFactory struct { -} - -func (t TypeDataSourcePlannerFactoryFactory) Initialize(base BasePlanner, configReader io.Reader) (PlannerFactory, error) { - factory := TypeDataSourcePlannerFactory{ - base: base, - } - return factory, json.NewDecoder(configReader).Decode(&factory.config) -} - -type TypeDataSourcePlannerFactory struct { - base BasePlanner - config TypeDataSourcePlannerConfig -} - -func (t TypeDataSourcePlannerFactory) DataSourcePlanner() Planner { - return SimpleDataSourcePlanner(&TypeDataSourcePlanner{ - BasePlanner: t.base, - dataSourceConfig: t.config, - }) -} - -type TypeDataSourcePlanner struct { - BasePlanner - dataSourceConfig TypeDataSourcePlannerConfig -} - -func (t *TypeDataSourcePlanner) Plan(args []Argument) (DataSource, []Argument) { - return &TypeDataSource{}, append(t.Args, args...) -} - -type TypeDataSource struct { -} - -func (t *TypeDataSource) Resolve(ctx context.Context, args ResolverArgs, out io.Writer) (n int, err error) { - return -} diff --git a/pkg/execution/datasource/hooks.go b/pkg/execution/datasource/hooks.go deleted file mode 100644 index ccd397e3d..000000000 --- a/pkg/execution/datasource/hooks.go +++ /dev/null @@ -1,23 +0,0 @@ -package datasource - -import ( - "net/http" -) - -type HookContext struct { - TypeName string - FieldName string -} - -type Hooks struct { - PreSendHttpHook PreSendHttpHook - PostReceiveHttpHook PostReceiveHttpHook -} - -type PreSendHttpHook interface { - Execute(ctx HookContext, req *http.Request) -} - -type PostReceiveHttpHook interface { - Execute(ctx HookContext, resp *http.Response, body []byte) -} diff --git a/pkg/execution/datasource_config.go b/pkg/execution/datasource_config.go deleted file mode 100644 index c6d40334d..000000000 --- a/pkg/execution/datasource_config.go +++ /dev/null @@ -1,417 +0,0 @@ -// Code generated by graphql-go-tools gen, DO NOT EDIT. -package execution - -import ast "github.com/wundergraph/graphql-go-tools/pkg/ast" - -type GraphQLDataSourceConfig struct { - Host string - Url string - Method HTTP_METHOD - Params *[]*Parameter -} - -func (g *GraphQLDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "host": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - g.Host = val - case "url": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - g.Url = val - case "method": - var val HTTP_METHOD - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - g.Method = val - case "params": - list := make([]*Parameter, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Parameter - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - g.Params = &list - } - } -} - -type HttpJsonDataSourceConfig struct { - Host string - Url string - Method HTTP_METHOD - Params *[]*Parameter - Body *string - Headers *[]*Header - DefaultTypeName *string - StatusCodeTypeNameMappings *[]*StatusCodeTypeNameMapping -} - -func (h *HttpJsonDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "host": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - h.Host = val - case "url": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - h.Url = val - case "method": - var val HTTP_METHOD - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - h.Method = val - case "params": - list := make([]*Parameter, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Parameter - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - h.Params = &list - case "body": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - h.Body = &val - case "headers": - list := make([]*Header, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Header - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - h.Headers = &list - case "defaultTypeName": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - h.DefaultTypeName = &val - case "statusCodeTypeNameMappings": - list := make([]*StatusCodeTypeNameMapping, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val StatusCodeTypeNameMapping - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - h.StatusCodeTypeNameMappings = &list - } - } -} - -type HttpPollingStreamDataSourceConfig struct { - Host string - Url string - Method HTTP_METHOD - DelaySeconds int64 - Params *[]*Parameter -} - -func (h *HttpPollingStreamDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - h.DelaySeconds = doc.DirectiveDefinitionArgumentDefaultValueInt64("HttpPollingStreamDataSource", "delaySeconds") - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "host": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - h.Host = val - case "url": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - h.Url = val - case "method": - var val HTTP_METHOD - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - h.Method = val - case "delaySeconds": - val := doc.IntValueAsInt(doc.ArgumentValue(ii).Ref) - h.DelaySeconds = val - case "params": - list := make([]*Parameter, 0, len(doc.ListValues[doc.ArgumentValue(ii).Ref].Refs)) - for _, ii := range doc.ListValues[doc.ArgumentValue(ii).Ref].Refs { - var val Parameter - val.Unmarshal(doc, doc.Value(ii).Ref) - list = append(list, &val) - } - h.Params = &list - } - } -} - -type MappingConfig struct { - Mode MAPPING_MODE - PathSelector *string -} - -func (m *MappingConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "mode": - var val MAPPING_MODE - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - m.Mode = val - case "pathSelector": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - m.PathSelector = &val - } - } -} - -type MQTTDataSourceConfig struct { - BrokerAddr string - ClientID string - Topic string -} - -func (m *MQTTDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "brokerAddr": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - m.BrokerAddr = val - case "clientID": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - m.ClientID = val - case "topic": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - m.Topic = val - } - } -} - -type NatsDataSourceConfig struct { - Addr string - Topic string -} - -func (n *NatsDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "addr": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - n.Addr = val - case "topic": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - n.Topic = val - } - } -} - -type PipelineDataSourceConfig struct { - ConfigFilePath *string - ConfigString *string - InputJSON string -} - -func (p *PipelineDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "configFilePath": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - p.ConfigFilePath = &val - case "configString": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - p.ConfigString = &val - case "inputJSON": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - p.InputJSON = val - } - } -} - -type StaticDataSourceConfig struct { - Data *string -} - -func (s *StaticDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "data": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - s.Data = &val - } - } -} - -type TransformationConfig struct { - Mode TRANSFORMATION_MODE - PipelineConfigFile *string - PipelineConfigString *string -} - -func (t *TransformationConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "mode": - var val TRANSFORMATION_MODE - val.Unmarshal(doc, doc.ArgumentValue(ii).Ref) - t.Mode = val - case "pipelineConfigFile": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - t.PipelineConfigFile = &val - case "pipelineConfigString": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - t.PipelineConfigString = &val - } - } -} - -type WasmDataSourceConfig struct { - Input string - WasmFile string -} - -func (w *WasmDataSourceConfig) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.Directives[ref].Arguments.Refs { - name := doc.ArgumentNameString(ii) - switch name { - case "input": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - w.Input = val - case "wasmFile": - val := doc.StringValueContentString(doc.ArgumentValue(ii).Ref) - w.WasmFile = val - } - } -} - -type HTTP_METHOD int - -func (h *HTTP_METHOD) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "GET": - *h = HTTP_METHOD_GET - case "POST": - *h = HTTP_METHOD_POST - case "UPDATE": - *h = HTTP_METHOD_UPDATE - case "DELETE": - *h = HTTP_METHOD_DELETE - } -} - -const ( - UNDEFINED_HTTP_METHOD HTTP_METHOD = iota - HTTP_METHOD_GET - HTTP_METHOD_POST - HTTP_METHOD_UPDATE - HTTP_METHOD_DELETE -) - -type MAPPING_MODE int - -func (m *MAPPING_MODE) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "NONE": - *m = MAPPING_MODE_NONE - case "PATH_SELECTOR": - *m = MAPPING_MODE_PATH_SELECTOR - } -} - -const ( - UNDEFINED_MAPPING_MODE MAPPING_MODE = iota - MAPPING_MODE_NONE - MAPPING_MODE_PATH_SELECTOR -) - -type PARAMETER_SOURCE int - -func (p *PARAMETER_SOURCE) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "CONTEXT_VARIABLE": - *p = PARAMETER_SOURCE_CONTEXT_VARIABLE - case "OBJECT_VARIABLE_ARGUMENT": - *p = PARAMETER_SOURCE_OBJECT_VARIABLE_ARGUMENT - case "FIELD_ARGUMENTS": - *p = PARAMETER_SOURCE_FIELD_ARGUMENTS - } -} - -const ( - UNDEFINED_PARAMETER_SOURCE PARAMETER_SOURCE = iota - PARAMETER_SOURCE_CONTEXT_VARIABLE - PARAMETER_SOURCE_OBJECT_VARIABLE_ARGUMENT - PARAMETER_SOURCE_FIELD_ARGUMENTS -) - -type TRANSFORMATION_MODE int - -func (t *TRANSFORMATION_MODE) Unmarshal(doc *ast.Document, ref int) { - switch doc.EnumValueNameString(ref) { - case "PIPELINE": - *t = TRANSFORMATION_MODE_PIPELINE - } -} - -const ( - UNDEFINED_TRANSFORMATION_MODE TRANSFORMATION_MODE = iota - TRANSFORMATION_MODE_PIPELINE -) - -type Header struct { - Key string - Value string -} - -func (h *Header) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "key": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - h.Key = val - case "value": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - h.Value = val - } - } -} - -type Parameter struct { - Name string - SourceKind PARAMETER_SOURCE - SourceName string - VariableType string -} - -func (p *Parameter) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "name": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.Name = val - case "sourceKind": - var val PARAMETER_SOURCE - val.Unmarshal(doc, doc.ObjectFieldValue(ii).Ref) - p.SourceKind = val - case "sourceName": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.SourceName = val - case "variableType": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - p.VariableType = val - } - } -} - -type StatusCodeTypeNameMapping struct { - StatusCode int64 - TypeName string -} - -func (s *StatusCodeTypeNameMapping) Unmarshal(doc *ast.Document, ref int) { - for _, ii := range doc.ObjectValues[ref].Refs { - name := string(doc.ObjectFieldNameBytes(ii)) - switch name { - case "statusCode": - val := doc.IntValueAsInt(doc.ObjectFieldValue(ii).Ref) - s.StatusCode = val - case "typeName": - val := doc.StringValueContentString(doc.ObjectFieldValue(ii).Ref) - s.TypeName = val - } - } -} diff --git a/pkg/execution/datasource_graphql_test.go b/pkg/execution/datasource_graphql_test.go deleted file mode 100644 index f8e5657d6..000000000 --- a/pkg/execution/datasource_graphql_test.go +++ /dev/null @@ -1,312 +0,0 @@ -package execution - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "net/http/httptest" - "testing" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type preSendHttpHookFunc func(ctx datasource.HookContext, req *http.Request) - -func (p preSendHttpHookFunc) Execute(ctx datasource.HookContext, req *http.Request) { - p(ctx, req) -} - -type postReceiveHttpHookFunc func(ctx datasource.HookContext, resp *http.Response, body []byte) - -func (p postReceiveHttpHookFunc) Execute(ctx datasource.HookContext, resp *http.Response, body []byte) { - p(ctx, resp, body) -} - -var graphqlDataSourceName = "graphql" - -func TestGraphqlDataSource_WithPlanning(t *testing.T) { - type testCase struct { - definition string - operation datasource.GraphqlRequest - typeFieldConfigs []datasource.TypeFieldConfiguration - hooksFactory func(t *testing.T) datasource.Hooks - assertRequestBody bool - expectedRequestBodies []string - upstreamResponses []string - expectedResponseBody string - } - - run := func(tc testCase) func(t *testing.T) { - return func(t *testing.T) { - upstreams := make([]*httptest.Server, len(tc.upstreamResponses)) - for i := 0; i < len(tc.upstreamResponses); i++ { - if tc.assertRequestBody { - require.Len(t, tc.expectedRequestBodies, len(tc.upstreamResponses)) - } - - var expectedRequestBody string - if tc.assertRequestBody { - expectedRequestBody = tc.expectedRequestBodies[i] - } - - upstream := upstreamGraphqlServer(t, tc.assertRequestBody, expectedRequestBody, tc.upstreamResponses[i]) - defer upstream.Close() - - upstreams[i] = upstream - } - - var upstreamURLs []string - for _, upstream := range upstreams { - upstreamURLs = append(upstreamURLs, upstream.URL) - } - - plannerConfig := createPlannerConfigToUpstream(t, upstreamURLs, http.MethodPost, tc.typeFieldConfigs) - basePlanner, err := datasource.NewBaseDataSourcePlanner([]byte(tc.definition), plannerConfig, abstractlogger.NoopLogger) - require.NoError(t, err) - - var hooks datasource.Hooks - if tc.hooksFactory != nil { - hooks = tc.hooksFactory(t) - } - - err = basePlanner.RegisterDataSourcePlannerFactory(graphqlDataSourceName, &datasource.GraphQLDataSourcePlannerFactoryFactory{Hooks: hooks}) - require.NoError(t, err) - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(tc.definition) - operationDocument := unsafeparser.ParseGraphqlDocumentString(tc.operation.Query) - - var report operationreport.Report - operationDocument.Input.Variables = tc.operation.Variables - normalizer := astnormalization.NewNormalizer(true, true) - normalizer.NormalizeOperation(&operationDocument, &definitionDocument, &report) - require.False(t, report.HasErrors()) - - tc.operation.Variables = operationDocument.Input.Variables - - planner := NewPlanner(basePlanner) - plan := planner.Plan(&operationDocument, &definitionDocument, tc.operation.OperationName, &report) - require.False(t, report.HasErrors()) - - variables, extraArguments := VariablesFromJson(tc.operation.Variables, nil) - executionContext := Context{ - Context: context.Background(), - Variables: variables, - ExtraArguments: extraArguments, - } - - var buf bytes.Buffer - executor := NewExecutor(nil) - err = executor.Execute(executionContext, plan, &buf) - require.NoError(t, err) - - assert.JSONEq(t, tc.expectedResponseBody, buf.String()) - } - } - - t.Run("should execute a single query without arguments", run( - testCase{ - definition: countriesSchema, - operation: datasource.GraphqlRequest{ - OperationName: "", - Variables: nil, - Query: "{ continents { code name } }", - }, - typeFieldConfigs: []datasource.TypeFieldConfiguration{ - graphqlTypeFieldConfigContinents, - }, - assertRequestBody: false, - upstreamResponses: []string{ - `{ "data": { "continents": [ { "code": "DE", "name": "Germany" } ] } }`, - }, - expectedResponseBody: `{ "data": { "continents": [ { "code": "DE", "name": "Germany" } ] } }`, - }), - ) - - t.Run("should execute a single query with arguments", run( - testCase{ - definition: countriesSchema, - operation: datasource.GraphqlRequest{ - OperationName: "", - Variables: nil, - Query: `{ country(code: "DE") { code name } }`, - }, - typeFieldConfigs: []datasource.TypeFieldConfiguration{ - graphqlTypeFieldConfigCountry, - }, - assertRequestBody: false, - upstreamResponses: []string{ - `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - }, - expectedResponseBody: `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - }), - ) - - t.Run("should execute hooks", run( - testCase{ - definition: countriesSchema, - operation: datasource.GraphqlRequest{ - OperationName: "", - Variables: nil, - Query: `{ country(code: "DE") { code name } }`, - }, - typeFieldConfigs: []datasource.TypeFieldConfiguration{ - graphqlTypeFieldConfigCountry, - }, - hooksFactory: func(t *testing.T) datasource.Hooks { - return datasource.Hooks{ - PreSendHttpHook: preSendHttpHookFunc(func(ctx datasource.HookContext, req *http.Request) { - assert.Equal(t, ctx.TypeName, "Query") - assert.Equal(t, ctx.FieldName, "country") - assert.Regexp(t, `http://127.0.0.1:[0-9]+`, req.URL.String()) - }), - PostReceiveHttpHook: postReceiveHttpHookFunc(func(ctx datasource.HookContext, resp *http.Response, body []byte) { - assert.Equal(t, ctx.TypeName, "Query") - assert.Equal(t, ctx.FieldName, "country") - assert.Equal(t, 200, resp.StatusCode) - assert.Equal(t, body, []byte(`{ "data": { "country": { "code": "DE", "name": "Germany" } } }`)) - }), - } - }, - assertRequestBody: false, - upstreamResponses: []string{ - `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - }, - expectedResponseBody: `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - }), - ) - - t.Run("should execute a multiple queries in a single query", run( - testCase{ - definition: countriesSchema, - operation: datasource.GraphqlRequest{ - OperationName: "", - Variables: nil, - Query: `{ continents { code name } country(code: "DE") { code name } }`, - }, - typeFieldConfigs: []datasource.TypeFieldConfiguration{ - graphqlTypeFieldConfigCountry, - graphqlTypeFieldConfigContinents, - }, - assertRequestBody: true, - expectedRequestBodies: []string{ - `{ "operationName": "o", "variables": {"a": "DE"}, "query": "query o($a: ID!){country(code: $a){code name}}" }`, - `{ "operationName": "o", "variables": {}, "query": "query o {continents {code name}}" }`, - }, - upstreamResponses: []string{ - `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - `{ "data": { "continents": [ { "code": "DE", "name": "Germany" } ] } }`, - }, - expectedResponseBody: `{ "data": { "country": { "code": "DE", "name": "Germany" }, "continents": [ { "code": "DE", "name": "Germany" } ] } }`, - }), - ) - - t.Run("should execute a multiple queries in a single query with same arguments", run( - testCase{ - definition: countriesSchema, - operation: datasource.GraphqlRequest{ - OperationName: "", - Variables: nil, - Query: `{ country(code: "DE") { code name } continent(code: "EU") { code name } }`, - }, - typeFieldConfigs: []datasource.TypeFieldConfiguration{ - graphqlTypeFieldConfigCountry, - graphqlTypeFieldConfigContinent, - }, - assertRequestBody: true, - expectedRequestBodies: []string{ - `{ "operationName": "o", "variables": {"a": "DE"}, "query": "query o($a: ID!){country(code: $a){code name}}" }`, - `{ "operationName": "o", "variables": {"b": "EU"}, "query": "query o($b: ID!){continent(code: $b){code name}}" }`, - }, - upstreamResponses: []string{ - `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - `{ "data": { "continent": { "code": "EU", "name": "Europe" } } }`, - }, - expectedResponseBody: `{ "data": { "country": { "code": "DE", "name": "Germany" }, "continent": { "code": "EU", "name": "Europe" } } }`, - }), - ) -} - -func upstreamGraphqlServer(t *testing.T, assertRequestBody bool, expectedRequestBody string, response string) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.NotNil(t, r.Body) - - bodyBytes, err := io.ReadAll(r.Body) - require.NoError(t, err) - - if assertRequestBody { - isEqual := assert.JSONEq(t, expectedRequestBody, string(bodyBytes)) - if !isEqual { - w.WriteHeader(http.StatusBadRequest) - return - } - } - - _, err = w.Write([]byte(response)) - require.NoError(t, err) - })) -} - -func createPlannerConfigToUpstream(t *testing.T, upstreamURL []string, method string, typeFieldConfigs []datasource.TypeFieldConfiguration) datasource.PlannerConfiguration { - require.Len(t, upstreamURL, len(typeFieldConfigs)) - - for i := 0; i < len(typeFieldConfigs); i++ { - typeFieldConfigs[i].DataSource.Config = jsonRawMessagify(map[string]interface{}{ - "url": upstreamURL[i], - "method": method, - }) - } - - return datasource.PlannerConfiguration{ - TypeFieldConfigurations: typeFieldConfigs, - } -} - -var graphqlTypeFieldConfigContinents = datasource.TypeFieldConfiguration{ - TypeName: "Query", - FieldName: "continents", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "continents", - }, - DataSource: datasource.SourceConfig{ - Name: graphqlDataSourceName, - }, -} - -var graphqlTypeFieldConfigContinent = datasource.TypeFieldConfiguration{ - TypeName: "Query", - FieldName: "continent", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "continent", - }, - DataSource: datasource.SourceConfig{ - Name: graphqlDataSourceName, - }, -} - -var graphqlTypeFieldConfigCountry = datasource.TypeFieldConfiguration{ - TypeName: "Query", - FieldName: "country", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "country", - }, - DataSource: datasource.SourceConfig{ - Name: graphqlDataSourceName, - }, -} - -func jsonRawMessagify(any interface{}) []byte { - out, _ := json.Marshal(any) - return out -} diff --git a/pkg/execution/datasource_http_json_test.go b/pkg/execution/datasource_http_json_test.go deleted file mode 100644 index 264a233ea..000000000 --- a/pkg/execution/datasource_http_json_test.go +++ /dev/null @@ -1,873 +0,0 @@ -package execution - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "testing" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/tidwall/gjson" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const httpJsonDataSourceSchema = ` -schema { - query: Query -} -type Query { - simpleType: SimpleType - unionType: UnionType - interfaceType: InterfaceType - listOfStrings: [String!] - listOfObjects: [SimpleType] -} -type SimpleType { - scalarField: String -} -union UnionType = SuccessType | ErrorType -type SuccessType { - result: String -} -type ErrorType { - message: String -} -interface InterfaceType { - name: String! -} -type SuccessInterface implements InterfaceType { - name: String! - successField: String! -} -type ErrorInterface implements InterfaceType { - name: String! - errorField: String! -} -` - -func TestHttpJsonDataSourcePlanner_Plan(t *testing.T) { - t.Run("simpleType", run(httpJsonDataSourceSchema, ` - query SimpleTypeQuery { - simpleType { - __typename - scalarField - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "simpleType", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - DefaultTypeName: func() *string { - typeName := "SimpleType" - return &typeName - }(), - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: literal.DATA, - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "simpleType", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: abstractlogger.Noop{}, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("simpleType"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("example.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"SimpleType"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("simpleType"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("scalarField"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "scalarField", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("list of strings", run(httpJsonDataSourceSchema, ` - query ListOfStrings { - listOfStrings - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "listOfStrings", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: literal.DATA, - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "listOfStrings", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: abstractlogger.Noop{}, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("listOfStrings"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("example.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("listOfStrings"), - HasResolvedData: true, - Value: &List{ - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("list of objects", run(httpJsonDataSourceSchema, ` - query ListOfObjects { - listOfObjects { - scalarField - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "listOfObjects", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - DefaultTypeName: func() *string { - typeName := "SimpleType" - return &typeName - }(), - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: literal.DATA, - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "listOfObjects", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: abstractlogger.Noop{}, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("listOfObjects"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("example.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"SimpleType"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("listOfObjects"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("scalarField"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "scalarField", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("unionType", run(httpJsonDataSourceSchema, ` - query UnionTypeQuery { - unionType { - __typename - ... on SuccessType { - result - } - ... on ErrorType { - message - } - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "unionType", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - defaultTypeName := "SuccessType" - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - DefaultTypeName: &defaultTypeName, - StatusCodeTypeNameMappings: []datasource.StatusCodeTypeNameMapping{ - { - StatusCode: 500, - TypeName: "ErrorType", - }, - }, - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: literal.DATA, - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "unionType", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: abstractlogger.Noop{}, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("unionType"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("example.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"500":"ErrorType","defaultTypeName":"SuccessType"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("unionType"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("result"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("SuccessType"), - }, - }, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "result", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("message"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("ErrorType"), - }, - }, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "message", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("interfaceType", run(httpJsonDataSourceSchema, ` - query InterfaceTypeQuery { - interfaceType { - __typename - name - ... on SuccessInterface { - successField - } - ... on ErrorInterface { - errorField - } - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "interfaceType", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - defaultTypeName := "SuccessInterface" - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - DefaultTypeName: &defaultTypeName, - StatusCodeTypeNameMappings: []datasource.StatusCodeTypeNameMapping{ - { - StatusCode: 500, - TypeName: "ErrorInterface", - }, - }, - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: literal.DATA, - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "interfaceType", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: abstractlogger.Noop{}, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("interfaceType"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("example.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"500":"ErrorInterface","defaultTypeName":"SuccessInterface"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("interfaceType"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("successField"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("SuccessInterface"), - }, - }, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "successField", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("errorField"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("ErrorInterface"), - }, - }, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "errorField", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) -} - -func TestHttpJsonDataSource_Resolve(t *testing.T) { - - test := func(serverStatusCode int, typeNameDefinition, wantTypeName string) func(t *testing.T) { - return func(t *testing.T) { - fakeServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(serverStatusCode) - _, _ = w.Write([]byte(`{"foo":"bar"}`)) - })) - defer fakeServer.Close() - ctx := Context{ - Context: context.Background(), - } - buf := bytes.Buffer{} - source := &datasource.HttpJsonDataSource{ - Log: abstractlogger.Noop{}, - Client: datasource.DefaultHttpClient(), - } - args := ResolvedArgs{ - { - Key: []byte("url"), - Value: []byte(fakeServer.URL + "/"), - }, - { - Key: []byte("method"), - Value: []byte("GET"), - }, - { - Key: []byte("__typename"), - Value: []byte(typeNameDefinition), - }, - } - _, err := source.Resolve(ctx, args, &buf) - if err != nil { - t.Fatal(err) - } - result := gjson.GetBytes(buf.Bytes(), "__typename") - gotTypeName := result.Str - if gotTypeName != wantTypeName { - panic(fmt.Errorf("want: %s, got: %s\n", wantTypeName, gotTypeName)) - } - } - } - - t.Run("typename selection on err", test( - 500, - `{"500":"ErrorInterface","defaultTypeName":"SuccessInterface"}`, - "ErrorInterface")) - t.Run("typename selection on success using default", test( - 200, - `{"500":"ErrorInterface","defaultTypeName":"SuccessInterface"}`, - "SuccessInterface")) - t.Run("typename selection on success using select", test( - 200, - `{"500":"ErrorInterface","200":"AnotherSuccess","defaultTypeName":"SuccessInterface"}`, - "AnotherSuccess")) -} - -var httpJsonDataSourceName = "http_json" - -func TestHttpJsonDataSource_WithPlanning(t *testing.T) { - type testCase struct { - definition string - operation datasource.GraphqlRequest - typeFieldConfigs []datasource.TypeFieldConfiguration - hooksFactory func(t *testing.T) datasource.Hooks - assertRequestBody bool - expectedRequestBodies []string - upstreamResponses []string - expectedResponseBody string - } - - run := func(tc testCase) func(t *testing.T) { - return func(t *testing.T) { - upstreams := make([]*httptest.Server, len(tc.upstreamResponses)) - for i := 0; i < len(tc.upstreamResponses); i++ { - if tc.assertRequestBody { - require.Len(t, tc.expectedRequestBodies, len(tc.upstreamResponses)) - } - - var expectedRequestBody string - if tc.assertRequestBody { - expectedRequestBody = tc.expectedRequestBodies[i] - } - - upstream := upstreamHttpJsonServer(t, tc.assertRequestBody, expectedRequestBody, tc.upstreamResponses[i]) - defer upstream.Close() - - upstreams[i] = upstream - } - - var upstreamURLs []string - for _, upstream := range upstreams { - upstreamURLs = append(upstreamURLs, upstream.URL) - } - - plannerConfig := createPlannerConfigToUpstream(t, upstreamURLs, http.MethodPost, tc.typeFieldConfigs) - basePlanner, err := datasource.NewBaseDataSourcePlanner([]byte(tc.definition), plannerConfig, abstractlogger.NoopLogger) - require.NoError(t, err) - - var hooks datasource.Hooks - if tc.hooksFactory != nil { - hooks = tc.hooksFactory(t) - } - - err = basePlanner.RegisterDataSourcePlannerFactory(httpJsonDataSourceName, &datasource.HttpJsonDataSourcePlannerFactoryFactory{Hooks: hooks}) - require.NoError(t, err) - - definitionDocument := unsafeparser.ParseGraphqlDocumentString(tc.definition) - operationDocument := unsafeparser.ParseGraphqlDocumentString(tc.operation.Query) - - var report operationreport.Report - operationDocument.Input.Variables = tc.operation.Variables - normalizer := astnormalization.NewNormalizer(true, true) - normalizer.NormalizeOperation(&operationDocument, &definitionDocument, &report) - require.False(t, report.HasErrors()) - - tc.operation.Variables = operationDocument.Input.Variables - - planner := NewPlanner(basePlanner) - plan := planner.Plan(&operationDocument, &definitionDocument, tc.operation.OperationName, &report) - require.False(t, report.HasErrors()) - - variables, extraArguments := VariablesFromJson(tc.operation.Variables, nil) - executionContext := Context{ - Context: context.Background(), - Variables: variables, - ExtraArguments: extraArguments, - } - - var buf bytes.Buffer - executor := NewExecutor(nil) - err = executor.Execute(executionContext, plan, &buf) - require.NoError(t, err) - - assert.JSONEq(t, tc.expectedResponseBody, buf.String()) - } - } - - t.Run("should execute hooks", run( - testCase{ - definition: countriesSchema, - operation: datasource.GraphqlRequest{ - OperationName: "", - Variables: nil, - Query: `{ country(code: "DE") { code name } }`, - }, - typeFieldConfigs: []datasource.TypeFieldConfiguration{ - httpJsonTypeFieldConfigCountry, - }, - hooksFactory: func(t *testing.T) datasource.Hooks { - return datasource.Hooks{ - PreSendHttpHook: preSendHttpHookFunc(func(ctx datasource.HookContext, req *http.Request) { - assert.Equal(t, ctx.TypeName, "Query") - assert.Equal(t, ctx.FieldName, "country") - assert.Regexp(t, `http://127.0.0.1:[0-9]+`, req.URL.String()) - }), - PostReceiveHttpHook: postReceiveHttpHookFunc(func(ctx datasource.HookContext, resp *http.Response, body []byte) { - assert.Equal(t, ctx.TypeName, "Query") - assert.Equal(t, ctx.FieldName, "country") - assert.Equal(t, 200, resp.StatusCode) - assert.Equal(t, body, []byte(`{ "code": "DE", "name": "Germany" }`)) - }), - } - }, - assertRequestBody: false, - upstreamResponses: []string{ - `{ "code": "DE", "name": "Germany" }`, - }, - expectedResponseBody: `{ "data": { "country": { "code": "DE", "name": "Germany" } } }`, - }), - ) -} - -func upstreamHttpJsonServer(t *testing.T, assertRequestBody bool, expectedRequestBody string, response string) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - require.NotNil(t, r.Body) - - bodyBytes, err := io.ReadAll(r.Body) - require.NoError(t, err) - - if assertRequestBody { - isEqual := assert.JSONEq(t, expectedRequestBody, string(bodyBytes)) - if !isEqual { - w.WriteHeader(http.StatusBadRequest) - return - } - } - - _, err = w.Write([]byte(response)) - require.NoError(t, err) - })) -} - -var httpJsonTypeFieldConfigCountry = datasource.TypeFieldConfiguration{ - TypeName: "Query", - FieldName: "country", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - Path: "country", - }, - DataSource: datasource.SourceConfig{ - Name: httpJsonDataSourceName, - }, -} diff --git a/pkg/execution/datasource_pipeline_test.go b/pkg/execution/datasource_pipeline_test.go deleted file mode 100644 index 1f21aebf7..000000000 --- a/pkg/execution/datasource_pipeline_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package execution - -import ( - "bytes" - "os" - "testing" - - log "github.com/jensneuse/abstractlogger" - "github.com/jensneuse/pipeline/pkg/pipe" - - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestPipelineDataSource_Resolve(t *testing.T) { - - configFile, err := os.Open("./testdata/simple_pipeline.json") - if err != nil { - t.Fatal(err) - } - - defer configFile.Close() - - var pipeline pipe.Pipeline - err = pipeline.FromConfig(configFile) - if err != nil { - t.Fatal(err) - } - - source := datasource.PipelineDataSource{ - Log: log.NoopLogger, - Pipeline: pipeline, - } - - args := ResolvedArgs{ - { - Key: literal.INPUT_JSON, - Value: []byte(`{"foo":"bar"}`), - }, - } - - var out bytes.Buffer - _, err = source.Resolve(Context{}, args, &out) - if err != nil { - t.Fatal(err) - } - - got := out.String() - want := `{"foo":"bar"}` - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} diff --git a/pkg/execution/execution.go b/pkg/execution/execution.go deleted file mode 100644 index 1d259a0a0..000000000 --- a/pkg/execution/execution.go +++ /dev/null @@ -1,613 +0,0 @@ -// Package execution is a complete GraphQL runtime. -// It contains a Handler to orchestrate the execution, a Query Planner to generate a Query Plan from an AST as well as the Executor to execute a Query Plan. -package execution - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "strconv" - "strings" - "sync" - "unicode/utf8" - - "github.com/buger/jsonparser" - "github.com/cespare/xxhash/v2" - byte_template "github.com/jensneuse/byte-template" - "github.com/tidwall/gjson" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/runes" -) - -type Executor struct { - context Context - out io.Writer - err error - buffers LockableBufferMap - escapeBuf [48]byte - templateDirectives []byte_template.DirectiveDefinition -} - -type LockableBufferMap struct { - sync.Mutex - Buffers map[uint64]*bytes.Buffer -} - -func NewExecutor(templateDirectives []byte_template.DirectiveDefinition) *Executor { - return &Executor{ - buffers: LockableBufferMap{ - Buffers: map[uint64]*bytes.Buffer{}, - }, - templateDirectives: templateDirectives, - } -} - -func (e *Executor) Execute(ctx Context, node RootNode, w io.Writer) error { - e.context = ctx - e.out = w - e.err = nil - - var path string - switch node.OperationType() { - case ast.OperationTypeQuery: - path = "query" - case ast.OperationTypeMutation: - path = "mutation" - case ast.OperationTypeSubscription: - path = "subscription" - } - e.resolveNode(node, nil, path, nil, true) - return e.err -} - -// write writes the data to the out io.Writer if there is no error previously captured -func (e *Executor) write(data []byte) { - if e.err != nil { - return - } - _, e.err = e.out.Write(data) -} - -// writeQuoted quotes and writes the data to the out io.Writer if there is no error previously captured -func (e *Executor) writeQuoted(data []byte) { - e.write(literal.QUOTE) - e.write(data) - e.write(literal.QUOTE) -} - -func (e *Executor) resolveNode(node Node, data []byte, path string, prefetch *sync.WaitGroup, shouldFetch bool) { - - switch node := node.(type) { - case *Object: - if data != nil { // in case data is not nil apply any path selection/transformation and return early if there is no data - data = e.resolveData(node.DataResolvingConfig, data) - if data == nil || bytes.Equal(data, literal.NULL) { - e.write(literal.NULL) - return - } - } - if shouldFetch && node.Fetch != nil { // execute the fetch on the object - _, err := node.Fetch.Fetch(e.context, data, e, path, &e.buffers) - if err != nil { - e.err = err - } - if prefetch != nil { // in case this was a prefetch we can immediately return - prefetch.Done() - return - } - } - e.write(literal.LBRACE) // start writing the object - hasPreviousValue := false - for i := 0; i < len(node.Fields); i++ { - if node.Fields[i].Skip != nil { - if node.Fields[i].Skip.Evaluate(e.context, data) { - continue - } - } - if hasPreviousValue { // separate all values with a comma in case we have at least one previous (unskipped field) - e.write(literal.COMMA) - } - hasPreviousValue = true - e.resolveNode(&node.Fields[i], data, path, nil, true) // recursively evaluate all fields - } - e.write(literal.RBRACE) // end writing the object - case *Field: - path = path + "." + unsafebytes.BytesToString(node.Name) // add the node name to the path using a "." as separator - if node.HasResolvedData { // in case this field has associated resolved data we have to fetch it from the buffer - if buf := e.buffers.Buffers[xxhash.Sum64String(path)]; buf != nil { - data = buf.Bytes() - } - } - e.writeQuoted(node.Name) - e.write(literal.COLON) - if data == nil && !node.Value.HasResolversRecursively() { - e.write(literal.NULL) - return - } - e.resolveNode(node.Value, data, path, nil, true) - case *Value: - data = e.resolveData(node.DataResolvingConfig, data) - _, e.err = node.ValueType.writeValue(data, e.escapeBuf[:], e.out) - return - case *List: - data = e.resolveData(node.DataResolvingConfig, data) - if len(data) == 0 { - e.write(literal.NULL) - return - } - shouldPrefetch := false - switch object := node.Value.(type) { - case *Object: - if object.Fetch != nil { - shouldPrefetch = true - } - } - result := gjson.ParseBytes(data).Array() - listItems := make([][]byte, len(result)) - for i := range result { - if result[i].Type == gjson.String { - listItems[i] = unsafebytes.StringToBytes(result[i].Str) - } else { - listItems[i] = unsafebytes.StringToBytes(result[i].Raw) - } - } - path = path + "." - maxItems := len(listItems) - if node.Filter != nil { - switch filter := node.Filter.(type) { - case *ListFilterFirstN: - if maxItems > filter.FirstN { - maxItems = filter.FirstN - } - } - } - if shouldPrefetch { - wg := &sync.WaitGroup{} - for i := 0; i < maxItems; i++ { - wg.Add(1) - go e.resolveNode(node.Value, listItems[i], path+strconv.Itoa(i), wg, true) - } - wg.Wait() - } - i := 0 - for i = 0; i < maxItems; i++ { - if i == 0 { - e.write(literal.LBRACK) - } else { - e.write(literal.COMMA) - } - e.resolveNode(node.Value, listItems[i], path+strconv.Itoa(i), nil, false) - } - if i == 0 || e.err == jsonparser.KeyPathNotFoundError { - e.err = nil - e.write(literal.LBRACK) - } - e.write(literal.RBRACK) - } -} - -func (e *Executor) resolveData(config DataResolvingConfig, data []byte) []byte { - if len(data) == 0 { - return nil - } - if config.PathSelector.Path == "" { - return data - } - result := gjson.GetBytes(data, config.PathSelector.Path) - if config.Transformation == nil && result.Type == gjson.String { - data = unsafebytes.StringToBytes(result.Str) - } else { - data = unsafebytes.StringToBytes(result.Raw) - } - if config.Transformation == nil { - return data - } - data, e.err = config.Transformation.Transform(data) - return data -} - -func (e *Executor) ResolveArgs(args []datasource.Argument, data []byte) ResolvedArgs { - - args = append(args, e.context.ExtraArguments...) - - resolved := make(ResolvedArgs, len(args)) - for i := 0; i < len(args); i++ { - switch arg := args[i].(type) { - case *datasource.StaticVariableArgument: - resolved[i].Key = arg.Name - resolved[i].Value = arg.Value - case *datasource.ObjectVariableArgument: - resolved[i].Key = arg.Name - result := gjson.GetBytes(data, arg.PathSelector.Path) - resolved[i].Value = unsafebytes.StringToBytes(result.Raw) - case *datasource.ContextVariableArgument: - resolved[i].Key = arg.Name - resolved[i].Value = e.context.Variables[xxhash.Sum64(arg.VariableName)] - case *datasource.ListArgument: - resolved[i].Key = arg.Name - listArgs := e.ResolveArgs(arg.Arguments, data) - listValues := make(map[string]string, len(listArgs)) - for j := range listArgs { - listValues[string(listArgs[j].Key)] = string(listArgs[j].Value) - } - resolved[i].Value, _ = json.Marshal(listValues) - } - } - - buf := bytes.Buffer{} - tmpl := byte_template.New(e.templateDirectives...) - - for i := range resolved { - if !bytes.Contains(resolved[i].Value, literal.DOUBLE_LBRACE) { - continue - } - _, err := tmpl.Execute(&buf, resolved[i].Value, func(w io.Writer, path []byte) (n int, err error) { - path = bytes.TrimFunc(path, func(r rune) bool { - return r == runes.SPACE || r == runes.TAB || r == runes.LINETERMINATOR - }) - if bytes.Count(path, literal.DOT) == 1 { - path = bytes.TrimPrefix(path, literal.DOT) - for j := range resolved { - if bytes.Equal(resolved[j].Key, path) { - return w.Write(resolved[j].Value) - } - } - } - if bytes.HasPrefix(path, literal.DOT_OBJECT_DOT) { - path = bytes.TrimPrefix(path, literal.DOT_OBJECT_DOT) - result := gjson.GetBytes(data, unsafebytes.BytesToString(path)) - if result.Type == gjson.String { - return w.Write(unsafebytes.StringToBytes(result.Str)) - } - return w.Write(unsafebytes.StringToBytes(result.Raw)) - } - for j := range resolved { - key := resolved[j].Key - if bytes.HasPrefix(path, literal.DOT) && !bytes.HasPrefix(key, literal.DOT) { - key = append(literal.DOT, key...) - } - if !bytes.HasPrefix(path, key) { - continue - } - key = bytes.TrimPrefix(path, key) - if len(key) == 0 { - return w.Write(resolved[j].Value) - } - key = bytes.TrimPrefix(key, literal.DOT) - - result := gjson.GetBytes(resolved[j].Value, unsafebytes.BytesToString(key)) - - if result.Type == gjson.String { - resultBytes := unsafebytes.StringToBytes(strings.Trim(strconv.Quote(result.Str), `"`)) - return w.Write(resultBytes) - } - - rawResultBytes := unsafebytes.StringToBytes(result.Raw) - return w.Write(rawResultBytes) - } - _, _ = w.Write(literal.LBRACE) - _, _ = w.Write(literal.LBRACE) - _, _ = w.Write(literal.SPACE) - _, _ = w.Write(path) - _, _ = w.Write(literal.SPACE) - _, _ = w.Write(literal.RBRACE) - return w.Write(literal.RBRACE) - }) - if err == nil { - value := buf.Bytes() - resolved[i].Value = make([]byte, len(value)) - copy(resolved[i].Value, value) - buf.Reset() - } - } - - resolved.Filter(func(i int) (keep bool) { - return !bytes.HasPrefix(resolved[i].Key, literal.DOT) - }) - - return resolved -} - -const ( - ObjectKind NodeKind = iota + 1 - FieldKind - ListKind - ValueKind -) - -type NodeKind int - -type Node interface { - // Kind returns the NodeKind of each Node - Kind() NodeKind - // HasResolversRecursively returns true if this Node or any child Node has a resolver - HasResolversRecursively() bool -} - -type RootNode interface { - Node - OperationType() ast.OperationType -} - -type Context struct { - context.Context - Variables Variables - ExtraArguments []datasource.Argument -} - -type Variables map[uint64][]byte - -type ResolvedArgument struct { - Key []byte - Value []byte -} - -type ResolvedArgs []ResolvedArgument - -func (r ResolvedArgs) Keys() [][]byte { - keys := make([][]byte, len(r)) - for i := range r { - keys[i] = (r)[i].Key - } - return keys -} - -func (r *ResolvedArgs) Filter(condition func(i int) (keep bool)) { - n := 0 - for i := range *r { - if condition(i) { - (*r)[n] = (*r)[i] - n++ - } - } - *r = (*r)[:n] -} - -func (r ResolvedArgs) ByKey(key []byte) []byte { - for i := 0; i < len(r); i++ { - if bytes.Equal(r[i].Key, key) { - return r[i].Value - } - } - return nil -} - -func (r ResolvedArgs) Dump() []string { - out := make([]string, len(r)) - for i := range r { - out[i] = string(r[i].Key) + "=" + string(r[i].Value) - } - return out -} - -type DataResolvingConfig struct { - PathSelector datasource.PathSelector - Transformation Transformation -} - -type Object struct { - DataResolvingConfig DataResolvingConfig - Fields []Field - Fetch Fetch - operationType ast.OperationType -} - -func (o *Object) OperationType() ast.OperationType { - return o.operationType -} - -type ArgsResolver interface { - ResolveArgs(args []datasource.Argument, data []byte) ResolvedArgs -} - -type Fetch interface { - Fetch(ctx Context, data []byte, argsResolver ArgsResolver, suffix string, buffers *LockableBufferMap) (n int, err error) -} - -type SingleFetch struct { - Source *DataSourceInvocation - BufferName string -} - -func (s *SingleFetch) Fetch(ctx Context, data []byte, argsResolver ArgsResolver, path string, buffers *LockableBufferMap) (int, error) { - bufferName := path + "." + s.BufferName - hash := xxhash.Sum64String(bufferName) - buffers.Lock() - buffer, exists := buffers.Buffers[hash] - buffers.Unlock() - if !exists { - buffer = bytes.NewBuffer(make([]byte, 0, 1024)) - buffers.Lock() - buffers.Buffers[hash] = buffer - buffers.Unlock() - } else { - buffer.Reset() - } - return s.Source.DataSource.Resolve(ctx, argsResolver.ResolveArgs(s.Source.Args, data), buffer) -} - -type SerialFetch struct { - Fetches []Fetch -} - -func (s *SerialFetch) Fetch(ctx Context, data []byte, argsResolver ArgsResolver, suffix string, buffers *LockableBufferMap) (n int, err error) { - for i := 0; i < len(s.Fetches); i++ { - nextN, nextErr := s.Fetches[i].Fetch(ctx, data, argsResolver, suffix, buffers) - if nextErr != nil { - return n, nextErr - } - n = n + nextN - } - return -} - -type ParallelFetch struct { - wg sync.WaitGroup - Fetches []Fetch -} - -func (p *ParallelFetch) Fetch(ctx Context, data []byte, argsResolver ArgsResolver, suffix string, buffers *LockableBufferMap) (n int, err error) { - for i := 0; i < len(p.Fetches); i++ { - p.wg.Add(1) - go func(fetch Fetch, ctx Context, data []byte, argsResolver ArgsResolver) { - _, _ = fetch.Fetch(ctx, data, argsResolver, suffix, buffers) // TODO: handle results - p.wg.Done() - }(p.Fetches[i], ctx, data, argsResolver) - } - p.wg.Wait() - return -} - -func (o *Object) HasResolversRecursively() bool { - for i := 0; i < len(o.Fields); i++ { - if o.Fields[i].HasResolversRecursively() { - return true - } - } - return false -} - -func (*Object) Kind() NodeKind { - return ObjectKind -} - -type BooleanCondition interface { - Evaluate(ctx Context, data []byte) bool -} - -type Field struct { - Name []byte - Value Node - Skip BooleanCondition - HasResolvedData bool -} - -func (f *Field) HasResolversRecursively() bool { - return f.HasResolvedData || f.Value.HasResolversRecursively() -} - -type IfEqual struct { - Left, Right datasource.Argument -} - -func (i *IfEqual) Evaluate(ctx Context, data []byte) bool { - var left []byte - var right []byte - - switch value := i.Left.(type) { - case *datasource.ContextVariableArgument: - left = ctx.Variables[xxhash.Sum64(value.VariableName)] - case *datasource.ObjectVariableArgument: - result := gjson.GetBytes(data, value.PathSelector.Path) - if result.Type == gjson.String { - left = unsafebytes.StringToBytes(result.Str) - } else { - left = unsafebytes.StringToBytes(result.Raw) - } - case *datasource.StaticVariableArgument: - left = value.Value - } - - switch value := i.Right.(type) { - case *datasource.ContextVariableArgument: - right = ctx.Variables[xxhash.Sum64(value.VariableName)] - case *datasource.ObjectVariableArgument: - result := gjson.GetBytes(data, value.PathSelector.Path) - if result.Type == gjson.String { - right = unsafebytes.StringToBytes(result.Str) - } else { - right = unsafebytes.StringToBytes(result.Raw) - } - case *datasource.StaticVariableArgument: - right = value.Value - } - - return bytes.Equal(left, right) -} - -type IfNotEqual struct { - Left, Right datasource.Argument -} - -func (i *IfNotEqual) Evaluate(ctx Context, data []byte) bool { - equal := IfEqual{ - Left: i.Left, - Right: i.Right, - } - return !equal.Evaluate(ctx, data) -} - -func (*Field) Kind() NodeKind { - return FieldKind -} - -type Value struct { - DataResolvingConfig DataResolvingConfig - ValueType JSONValueType -} - -func (value *Value) HasResolversRecursively() bool { - return false -} - -func (*Value) Kind() NodeKind { - return ValueKind -} - -type List struct { - DataResolvingConfig DataResolvingConfig - Value Node - Filter ListFilter -} - -func (l *List) HasResolversRecursively() bool { - return l.Value.HasResolversRecursively() -} - -func (*List) Kind() NodeKind { - return ListKind -} - -type ListFilter interface { - Kind() ListFilterKind -} - -type ListFilterKind int - -const ( - ListFilterKindFirstN ListFilterKind = iota + 1 -) - -type ListFilterFirstN struct { - FirstN int -} - -func (_ ListFilterFirstN) Kind() ListFilterKind { - return ListFilterKindFirstN -} - -type DataSourceInvocation struct { - Args []datasource.Argument - DataSource datasource.DataSource -} - -func isJSONObjectAsBytes(input []byte) bool { - trimmedInput := bytes.Trim(input, " ") - firstRune, _ := utf8.DecodeRune(trimmedInput) - lastRune, _ := utf8.DecodeLastRune(trimmedInput) - return fmt.Sprintf("%c", firstRune) == "{" && fmt.Sprintf("%c", lastRune) == "}" -} - -func byteSliceContainsEscapedQuotes(input []byte) bool { - return bytes.Contains(input, []byte(`\"`)) -} - -func byteSliceContainsQuotes(input []byte) bool { - return bytes.Contains(input, []byte(`"`)) -} diff --git a/pkg/execution/execution_test.go b/pkg/execution/execution_test.go deleted file mode 100644 index 38fd03554..000000000 --- a/pkg/execution/execution_test.go +++ /dev/null @@ -1,3072 +0,0 @@ -package execution - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "net/http/httputil" - "os" - "testing" - "time" - - "github.com/cespare/xxhash/v2" - log "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -// nolint -func dumpRequest(t *testing.T, r *http.Request, name string) { - dump, err := httputil.DumpRequest(r, true) - if err != nil { - t.Fatal(err) - } - fmt.Printf("%s dump: \n%s\n", name, string(dump)) -} - -func TestExecution(t *testing.T) { - exampleContext := Context{ - Variables: map[uint64][]byte{ - xxhash.Sum64String("name"): []byte("User"), - xxhash.Sum64String("id"): []byte("1"), - }, - } - - graphQL1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // dumpRequest(t, r, "graphQL1") - - _, err := w.Write(userData) - if err != nil { - t.Fatal(err) - } - })) - - graphQL2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // dumpRequest(t, r, "graphQL2") - - _, err := w.Write(petsData) - if err != nil { - t.Fatal(err) - } - })) - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // dumpRequest(t, r, "rest1") - - _, err := w.Write(friendsData) - if err != nil { - t.Fatal(err) - } - })) - - REST2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - // dumpRequest(t, r, "rest1") - - var data []byte - - switch r.RequestURI { - case "/friends/3/pets": - data = ahmetsPets - case "/friends/2/pets": - data = yaarasPets - default: - panic(fmt.Errorf("unexpected URI: %s", r.RequestURI)) - } - - _, err := w.Write(data) - if err != nil { - t.Fatal(err) - } - })) - - defer graphQL1.Close() - defer graphQL2.Close() - defer REST1.Close() - defer REST2.Close() - - object := &Object{ - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.ContextVariableArgument{ - Name: []byte("name"), - VariableName: []byte("name"), - }, - }, - DataSource: &datasource.TypeDataSource{}, - }, - BufferName: "__type", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(graphQL1.URL + "/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte("query q1($id: String!){user{id name birthday}}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("id"), - VariableName: []byte("id"), - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "user", - }, - }, - }, - Fields: []Field{ - { - Name: []byte("__type"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__type", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("fields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "fields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("user"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "user", - }, - }, - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(REST1.URL + "/user/{{ .id }}/friends"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("GET"), - }, - &datasource.ObjectVariableArgument{ - Name: []byte("id"), - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "friends", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(graphQL2.URL + "/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte(`query q1($id: String!){userPets(id: $id){ __typename name nickname... on Dog {woof} ... on Cat {meow}}}`), - }, - &datasource.ObjectVariableArgument{ - Name: []byte("id"), - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "pets", - }, - }, - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("friends"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(REST2.URL + "/friends/{{ .id }}/pets"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("GET"), - }, - &datasource.ObjectVariableArgument{ - Name: []byte("id"), - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "pets", - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("pets"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("nickname"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "nickname", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("woof"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "woof", - }, - }, - ValueType: StringValueType, - }, - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Dog"), - }, - }, - }, - { - Name: []byte("meow"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "meow", - }, - }, - ValueType: StringValueType, - }, - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Cat"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("pets"), - HasResolvedData: true, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "userPets", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("nickname"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "nickname", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("woof"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "woof", - }, - }, - ValueType: StringValueType, - }, - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Dog"), - }, - }, - }, - { - Name: []byte("meow"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "meow", - }, - }, - ValueType: StringValueType, - }, - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Cat"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := bytes.Buffer{} - ex := NewExecutor(nil) - err := ex.Execute(exampleContext, object, &out) - if err != nil { - t.Fatal(err) - } - - data := map[string]interface{}{} - err = json.Unmarshal(out.Bytes(), &data) - if err != nil { - fmt.Println(out.String()) - t.Fatal(err) - } - - pretty, err := json.MarshalIndent(data, "", " ") - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "execution", pretty) - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/execution.golden") - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, fixture, pretty) - } -} - -func BenchmarkExecution(b *testing.B) { - - exampleContext := Context{ - Variables: map[uint64][]byte{ - xxhash.Sum64String("name"): []byte("User"), - xxhash.Sum64String("id"): []byte("1"), - }, - } - - out := bytes.Buffer{} - ex := NewExecutor(nil) - - sizes := []int{1, 5, 10, 20, 50, 100} - - for _, size := range sizes { - b.Run(fmt.Sprintf("size:%d", size), func(b *testing.B) { - fields := make([]Field, 0, size) - for i := 0; i < size; i++ { - fields = append(fields, genField()) - } - object := &Object{ - Fields: fields, - } - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - out.Reset() - err := ex.Execute(exampleContext, object, &out) - if err != nil { - b.Fatal(err) - } - } - }) - } -} - -type FakeDataSource struct { - data []byte -} - -func (f FakeDataSource) Resolve(ctx context.Context, args datasource.ResolverArgs, out io.Writer) (n int, err error) { - return out.Write(f.data) -} - -func genField() Field { - - return Field{ - Name: []byte("data"), - Value: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.ContextVariableArgument{ - Name: []byte("name"), - VariableName: []byte("name"), - }, - }, - DataSource: &datasource.TypeDataSource{}, - }, - BufferName: "__type", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("localhost:8001/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte("query q1($id: String!){user{id name birthday}}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("id"), - VariableName: []byte("id"), - }, - }, - DataSource: &FakeDataSource{ - data: userData, - }, - }, - BufferName: "user", - }, - }, - }, - Fields: []Field{ - { - Name: []byte("__type"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__type", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - { - Name: []byte("fields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "fields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("user"), - HasResolvedData: true, - Value: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("/user/:id/friends"), - }, - &datasource.ObjectVariableArgument{ - Name: []byte("id"), - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - DataSource: &FakeDataSource{ - friendsData, - }, - }, - BufferName: "friends", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("localhost:8002/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte(`query q1($id: String!){userPets(id: $id){ __typename name nickname... on Dog {woof} ... on Cat {meow}}}`), - }, - &datasource.ObjectVariableArgument{ - Name: []byte("id"), - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - DataSource: &FakeDataSource{ - data: petsData, - }, - }, - BufferName: "pets", - }, - }, - }, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "data.user", - }, - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - }, - }, - { - Name: []byte("friends"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("pets"), - HasResolvedData: true, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "data.userPets", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - { - Name: []byte("nickname"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "nickname", - }, - }, - }, - }, - { - Name: []byte("woof"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "woof", - }, - }, - ValueType: StringValueType, - }, - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Dog"), - }, - }, - }, - { - Name: []byte("meow"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "meow", - }, - }, - ValueType: StringValueType, - }, - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Cat"), - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -var userData = []byte(` - { - "data": { - "user": { - "id":1, - "name":"Jens", - "birthday":"08.02.1988" - } - } - }`) - -var friendsData = []byte(`[ - { - "id":2, - "name":"Yaara", - "birthday":"1990 I guess? ;-)" - }, - { - "id":3, - "name":"Ahmet", - "birthday":"1980" - }]`) - -var yaarasPets = []byte(`[ -{ - "__typename":"Dog", - "name":"Woof", - "nickname":"Woofie", - "woof":"Woof! Woof!" - } -]`) - -var ahmetsPets = []byte(`[ -{ - "__typename":"Cat", - "name":"KitCat", - "nickname":"Kitty", - "meow":"Meow meow!" - } -]`) - -var petsData = []byte(`{ - "data":{ - "userPets":[{ - "__typename":"Dog", - "name":"Paw", - "nickname":"Pawie", - "woof":"Woof! Woof!" - }, - { - "__typename":"Cat", - "name":"Mietz", - "nickname":"Mietzie", - "meow":"Meow meow!" - }]} -}`) - -func TestStreamExecution(t *testing.T) { - out := bytes.Buffer{} - ex := NewExecutor(nil) - c, cancel := context.WithCancel(context.Background()) - ctx := Context{ - Context: c, - } - - want1 := `{"data":{"stream":{"bar":"bal","baz":1}}}` - want2 := `{"data":{"stream":{"bar":"bal","baz":2}}}` - want3 := `{"data":{"stream":{"bar":"bal","baz":3}}}` - - response1 := []byte(`{"bar":"bal","baz":1}`) - response2 := []byte(`{"bar":"bal","baz":2}`) - response3 := []byte(`{"bar":"bal","baz":3}`) - - resCount := 0 - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - resCount++ - - if r.RequestURI != "/bal" { - t.Fatalf("want: /bal, got: %s\n", r.RequestURI) - } - - var data []byte - switch resCount { - case 1: - data = response1 - case 2: - data = response2 - case 3: - data = response2 - case 4: - data = response3 - } - - _, err := w.Write(data) - if err != nil { - t.Fatal(err) - } - })) - defer REST1.Close() - - streamPlan := &Object{ - operationType: ast.OperationTypeSubscription, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.HOST, - Value: []byte(REST1.URL), - }, - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("/bal"), - }, - }, - DataSource: &datasource.HttpPollingStreamDataSource{ - Delay: time.Millisecond, - Log: log.NoopLogger, - }, - }, - BufferName: "stream", - }, - Fields: []Field{ - { - Name: []byte("stream"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("bar"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "bar", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("baz"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "baz", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - var err error - for i := 1; i < 4; i++ { - out.Reset() - err = ex.Execute(ctx, streamPlan, &out) // nolint - if err != nil { - t.Fatal(err) - } - var want string - switch i { - case 1: - want = want1 - case 2: - want = want2 - case 3: - want = want3 - } - - got := out.String() - if want != got { - t.Fatalf("want(%d): %s\ngot: %s\n", i, want, got) - } - } - - cancel() - err = ex.Execute(ctx, streamPlan, &out) - if err != nil { - t.Fatal(err) - } - - select { - case <-ctx.Done(): - return - default: - t.Fatalf("expected context.Context to be cancelled") - } -} - -func TestExecutor_ListFilterFirstN(t *testing.T) { - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("[{\"bar\":\"1\"},{\"bar\":\"2\"},{\"bar\":\"3\"}]"), - }, - }, - BufferName: "foos", - }, - Fields: []Field{ - { - Name: []byte("foos"), - HasResolvedData: true, - Value: &List{ - Filter: &ListFilterFirstN{ - FirstN: 2, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("bar"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "bar", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - want := `{"data":{"foos":[{"bar":"1"},{"bar":"2"}]}}` - got := out.String() - - if got != want { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} - -func TestExecutor_ObjectVariables(t *testing.T) { - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - if r.Method != http.MethodPost { - t.Fatalf("want method POST, got: %s", r.Method) - return - } - - got, err := io.ReadAll(r.Body) - if err != nil { - t.Fatal(err) - } - - want := []byte(`{"id":1}`) - - if !bytes.Equal(want, got) { - t.Fatalf("want: '%s', got: '%s'", string(want), string(got)) - } - - response := []byte(`{"name":"Woof","age":3}`) - - _, err = w.Write(response) - if err != nil { - t.Fatal(err) - } - })) - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte(`{"name": "Jens","id":1}`), - }, - }, - BufferName: "user", - }, - Fields: []Field{ - { - Name: []byte("user"), - HasResolvedData: true, - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "pet", - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(REST1.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("POST"), - }, - &datasource.StaticVariableArgument{ - Name: literal.BODY, - Value: []byte(`{"id":{{ .object.id }}}`), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - { - Name: []byte("pet"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("age"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "age", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - want := `{"data":{"user":{"name":"Jens","id":1,"pet":{"name":"Woof","age":3}}}}` - got := out.String() - - if got != want { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} - -func TestExecutor_NestedObjectVariables(t *testing.T) { - - previewService := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, _ = w.Write([]byte(`{"data":{"id":1}}`)) - })) - - defer previewService.Close() - - additionalDataService := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - want := "/api/additional_data?data_ids=1" - if r.RequestURI != want { - t.Fatalf("want uri: %s, got: %s", want, r.RequestURI) - } - _, _ = w.Write([]byte(`{"name":"foo"}`)) - })) - - defer additionalDataService.Close() - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "preview", - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(previewService.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("GET"), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - }, - Fields: []Field{ - { - Name: []byte("preview"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "data", - }, - }, - Fetch: &SingleFetch{ - BufferName: "additional_data_for_id", - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(additionalDataService.URL + "/api/additional_data?data_ids={{ .object.id }}"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("GET"), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - { - Name: []byte("additional_data_for_id"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - want := `{"data":{"preview":{"data":{"id":1,"additional_data_for_id":{"name":"foo"}}}}}` - got := out.String() - - if got != want { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} - -func TestExecutor_ListWithPath(t *testing.T) { - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte(`{"apis": [{"id": 1},{"id":2}]}`), - }, - }, - BufferName: "apis", - }, - Fields: []Field{ - { - Name: []byte("apis"), - HasResolvedData: true, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "apis", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - want := `{"data":{"apis":[{"id":1},{"id":2}]}}` - got := out.String() - - if got != want { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} - -func TestExecutor_GraphqlDataSourceWithParams(t *testing.T) { - - graphQL1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - _, err := w.Write([]byte(`{ - "data": { - "countries": [ - {"id":1},{"id":2} - ] - } - }`)) - if err != nil { - t.Fatal(err) - } - })) - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte(graphQL1.URL + "/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte("query q1($code: String!){countries(code: $code){id}}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("code"), - VariableName: []byte("code"), - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "countries", - }, - Fields: []Field{ - { - Name: []byte("countries"), - HasResolvedData: true, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "countries", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("code"): []byte("DE"), - }, - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - want := `{"data":{"countries":[{"id":1},{"id":2}]}}` - got := out.String() - - if got != want { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} - -func TestExecutor_ObjectWithPath(t *testing.T) { - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte(`{"api": {"id": 1}`), - }, - }, - BufferName: "id", - }, - Fields: []Field{ - { - Name: []byte("id"), - HasResolvedData: true, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "api.id", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - want := `{"data":{"id":1}}` - got := out.String() - - if got != want { - t.Fatalf("want: %s\ngot: %s\n", want, got) - } -} - -func TestExecutor_ResolveArgs(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("input"): []byte(`{"foo": "fooValue"}`), - }, - } - - args := []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("body"), - Value: []byte("{\\\"key\\\":\\\"{{ .arguments.input.foo }}\\\"}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.input"), - VariableName: []byte("input"), - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 1 { - t.Fatalf("want 1, got: %d\n", len(resolved)) - return - } - want := []byte("{\\\"key\\\":\\\"fooValue\\\"}") - if !bytes.Equal(resolved.ByKey([]byte("body")), want) { - t.Fatalf("want key 'body' with value: '%s'\ndump: %s", string(want), resolved.Dump()) - } -} - -func TestExecutor_ResolveArgsString(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("id"): []byte("foo123"), - }, - } - - args := []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("/apis/{{ .arguments.id }}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.id"), - VariableName: []byte("id"), - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 1 { - t.Fatalf("want 1, got: %d\n", len(resolved)) - return - } - want := []byte("/apis/foo123") - if !bytes.Equal(resolved.ByKey([]byte("url")), want) { - t.Fatalf("want key 'body' with value: '%s'\ndump: %s", string(want), resolved.Dump()) - } -} - -func TestExecutor_ResolveArgs_MultipleNested(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("from"): []byte(`{"year":2019,"month":11,"day":1}`), - xxhash.Sum64String("until"): []byte(`{"year":2019,"month":12,"day":31}`), - xxhash.Sum64String("page"): []byte(`0`), - }, - } - - args := []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("/api/usage/apis/{{ .id }}/{{ .arguments.from.day }}/{{ .arguments.from.month }}/{{ .arguments.from.year }}/{{ .arguments.until.day }}/{{ .arguments.until.month }}/{{ .arguments.until.year }}?by=Hits&sort=1&p={{ .arguments.page }}"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("id"), - Value: []byte("1"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.from"), - VariableName: []byte("from"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.until"), - VariableName: []byte("until"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.page"), - VariableName: []byte("page"), - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 2 { - t.Fatalf("want 1, got: %d\n", len(resolved)) - return - } - want := []byte("/api/usage/apis/1/1/11/2019/31/12/2019?by=Hits&sort=1&p=0") - got := resolved.ByKey([]byte("url")) - if !bytes.Equal(got, want) { - t.Fatalf("want key 'body' with value: '%s'\ngot: '%s'\ndump: %s", string(want), string(got), resolved.Dump()) - } -} - -func TestExecutor_ResolveArgsComplexPayload(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("input"): []byte(`{"foo": "fooValue", "bar": {"bal": "baz"}}`), - }, - } - - args := []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("body"), - Value: []byte("{{ .arguments.input }}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.input"), - VariableName: []byte("input"), - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 1 { - t.Fatalf("want 1, got: %d\n", len(resolved)) - return - } - want := `{"foo": "fooValue", "bar": {"bal": "baz"}}` - got := resolved.ByKey([]byte("body")) - if !bytes.Equal(got, []byte(want)) { - t.Fatalf("want key 'body' with value:\n%s\ngot:\n%s\n", want, string(got)) - } -} - -func TestExecutor_ResolveArgsComplexPayloadWithSelector(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("input"): []byte(`{"foo": "fooValue", "bar": {"bal": "baz"}}`), - }, - } - - args := []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("body"), - Value: []byte("{{ .arguments.input.bar }}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.input"), - VariableName: []byte("input"), - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 1 { - t.Fatalf("want 1, got: %d\n", len(resolved)) - return - } - want := `{"bal": "baz"}` - if !bytes.Equal(resolved.ByKey([]byte("body")), []byte(want)) { - t.Fatalf("want key 'body' with value: '%s'\ngot: '%s'", want, resolved.ByKey([]byte("body"))) - } -} - -func TestExecutor_ResolveArgsFlatObjectContainingJSON(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("request"): []byte(`{"header":{"Authorization":"foo"}}`), - }, - } - - args := []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("header"), - Value: []byte("{{ .request.header.Authorization }}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("request"), - VariableName: []byte("request"), - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 2 { - t.Fatalf("want 2, got: %d\n", len(resolved)) - return - } - want := "foo" - got := resolved.ByKey([]byte("header")) - if !bytes.Equal(got, []byte(want)) { - t.Fatalf("want key 'request' with value: '%s', got: '%s'", want, string(got)) - } -} - -func TestExecutor_ResolveArgsWithListArguments(t *testing.T) { - e := NewExecutor(nil) - e.context = Context{ - Context: context.Background(), - } - - args := []datasource.Argument{ - &datasource.ListArgument{ - Name: []byte("headers"), - Arguments: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("foo"), - Value: []byte("fooVal"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("bar"), - Value: []byte("barVal"), - }, - }, - }, - } - - resolved := e.ResolveArgs(args, nil) - if len(resolved) != 1 { - t.Fatalf("want 1, got: %d\n", len(resolved)) - return - } - want := "{\"bar\":\"barVal\",\"foo\":\"fooVal\"}" - got := string(resolved.ByKey([]byte("headers"))) - if want != got { - t.Fatalf("want key 'headers' with value:\n%s, got:\n%s\ndump:\n%s\n", want, got, resolved.Dump()) - } -} - -func TestExecutor_HTTPJSONDataSourceWithBody(t *testing.T) { - createRESTServer := func(wantString string) *httptest.Server { - return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - if r.Method != http.MethodPost { - t.Fatalf("wantUpstream: %s, got: %s\n", http.MethodPost, r.Method) - return - } - - data, err := io.ReadAll(r.Body) - if err != nil { - t.Fatal(err) - return - } - defer r.Body.Close() - - strData := string(data) - _ = strData - - gotString := prettyJSON(bytes.NewReader(data)) - - if wantString != gotString { - t.Fatalf("wantUpstream: %s\ngot: %s\n", wantString, gotString) - return - } - - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("bar")) - })) - } - - createPlanForRestServer := func(restServer *httptest.Server, bodyValue string) *Object { - return &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "withBody", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte(restServer.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("POST"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("body"), - Value: []byte(bodyValue), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.input"), - VariableName: []byte("input"), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("withBody"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - } - } - - run := func(t *testing.T, testServer *httptest.Server, bodyValue string, argumentsInputString string, expectedResult map[string]interface{}) { - plan := createPlanForRestServer(testServer, bodyValue) - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("input"): []byte(argumentsInputString), - }, - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - wantResult, err := json.MarshalIndent(expectedResult, "", " ") - if err != nil { - t.Fatal(err) - } - - want := string(wantResult) - got := prettyJSON(out) - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - return - } - } - - t.Run("should successfully use data source with body", func(t *testing.T) { - wantUpstream := map[string]interface{}{ - "key": "fooValue", - } - wantBytes, err := json.MarshalIndent(wantUpstream, "", " ") - if err != nil { - t.Fatal(err) - return - } - - expectedResult := map[string]interface{}{ - "data": map[string]interface{}{ - "withBody": "bar", - }, - } - - wantString := string(wantBytes) - restServer := createRESTServer(wantString) - defer restServer.Close() - - run(t, restServer, `{"key":"{{ .arguments.input.foo }}"}`, `{"foo": "fooValue"}`, expectedResult) - }) - - t.Run("should successfully use data source with body including json object as value in json object argument", func(t *testing.T) { - wantUpstream := map[string]interface{}{ - "key": "{ \"obj_key\": \"obj_value\" }", - } - wantBytes, err := json.MarshalIndent(wantUpstream, "", " ") - if err != nil { - t.Fatal(err) - return - } - - expectedResult := map[string]interface{}{ - "data": map[string]interface{}{ - "withBody": "bar", - }, - } - - wantString := string(wantBytes) - restServer := createRESTServer(wantString) - defer restServer.Client() - - run(t, restServer, `{ "key": "{{ .arguments.input.foo }}" }`, `{"foo": "{ \"obj_key\": \"obj_value\" }"}`, expectedResult) - }) - - t.Run("should successfully use data source with body including complex json object with escaped strings", func(t *testing.T) { - wantUpstream := map[string]interface{}{ - "meta_data": map[string]interface{}{ - "test": "{\"foo\": \"bar\", \"re\":\"\\w+\"}", - }, - } - wantBytes, err := json.MarshalIndent(wantUpstream, "", " ") - if err != nil { - t.Fatal(err) - return - } - - expectedResult := map[string]interface{}{ - "data": map[string]interface{}{ - "withBody": "bar", - }, - } - - wantString := string(wantBytes) - restServer := createRESTServer(wantString) - defer restServer.Client() - - run(t, restServer, `{{ .arguments.input.query }}`, `{"query": { "meta_data": { "test": "{\"foo\": \"bar\", \"re\":\"\\w+\"}" } }`, expectedResult) - }) - -} - -func TestExecutor_Execute_WithUnions(t *testing.T) { - - planApi := func(apiResponse string, succesFirst bool) *Object { - - successFields := []Field{ - { - Name: []byte("id"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Api"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - }, - }, - { - Name: []byte("name"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("Api"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - } - - errorFields := []Field{ - { - Name: []byte("status"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("RequestResult"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Status", - }, - }, - }, - }, - { - Name: []byte("message"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("RequestResult"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Message", - }, - }, - }, - }, - } - - var fields []Field - if succesFirst { - fields = append(successFields, errorFields...) - } else { - fields = append(errorFields, successFields...) - } - - return &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: FakeDataSource{ - data: []byte(apiResponse), - }, - }, - BufferName: "api", - }, - Fields: []Field{ - { - Name: []byte("api"), - HasResolvedData: true, - Value: &Object{ - Fields: fields, - }, - }, - }, - }, - }, - }, - } - } - - planApis := func(apiResponse string, succesFirst bool) *Object { - successField := Field{ - Name: []byte("apis"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("ApisResultSuccess"), - }, - }, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "apis", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - } - - errorFields := []Field{ - { - Name: []byte("status"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("RequestResult"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Status", - }, - }, - }, - }, - { - Name: []byte("message"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("RequestResult"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Message", - }, - }, - }, - }, - } - - var fields []Field - if succesFirst { - fields = append(fields, successField, errorFields[0], errorFields[1]) - } else { - fields = append(fields, errorFields[0], errorFields[1], successField) - } - - return &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: FakeDataSource{ - data: []byte(apiResponse), - }, - }, - BufferName: "apis", - }, - Fields: []Field{ - { - Name: []byte("apis"), - HasResolvedData: true, - Value: &Object{ - Fields: fields, - }, - }, - }, - }, - }, - }, - } - } - - makeTest := func(apiResponse, wantResult string, planner func(apiResponse string, successFirst bool) *Object) func(t *testing.T) { - return func(t *testing.T) { - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - err := ex.Execute(ctx, planner(apiResponse, true), out) - if err != nil { - panic(err) - } - - successFirst := out.String() - out.Reset() - err = ex.Execute(ctx, planner(apiResponse, false), out) - if err != nil { - panic(err) - } - errorFirst := out.String() - if successFirst != errorFirst { - panic(fmt.Errorf("successFirst: %s\nerrorFirst: %s\n", successFirst, errorFirst)) - } - if wantResult != successFirst { - panic(fmt.Errorf("want: %s\n got: %s\n", wantResult, successFirst)) - } - } - } - - t.Run("list response error case", makeTest( - `{"__typename":"RequestResult","Status":"Error","Message":"Could not retrieve Apis details"}`, - `{"data":{"apis":{"status":"Error","message":"Could not retrieve Apis details"}}}`, planApis), - ) - t.Run("list response valid response", makeTest( - `{"__typename":"ApisResultSuccess","apis":[{"id":"1","name":"a", "__typename":"Api"},{"id":"2","name":"b", "__typename":"Api"}]}`, - `{"data":{"apis":{"apis":[{"name":"a"},{"name":"b"}]}}}`, planApis), - ) - t.Run("object response valid response", makeTest( - `{"id":"1","name":"a", "__typename":"Api"}}`, - `{"data":{"api":{"id":"1","name":"a"}}}`, planApi), - ) - t.Run("object response error response", makeTest( - `{"__typename":"RequestResult","Status":"Error","Message":"Could not retrieve Api detail","Meta":null}`, - `{"data":{"api":{"status":"Error","message":"Could not retrieve Api detail"}}}`, planApi)) -} - -func TestExecutor_HTTPJSONDataSourceWithBodyComplexPlayload(t *testing.T) { - - wantUpstream := map[string]interface{}{ - "foo": "fooValue", - "bar": map[string]interface{}{ - "bal": "baz", - }, - } - - wantBytes, err := json.MarshalIndent(wantUpstream, "", " ") - if err != nil { - t.Fatal(err) - return - } - - wantString := string(wantBytes) - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - if r.Method != http.MethodPost { - t.Fatalf("wantUpstream: %s, got: %s\n", http.MethodPost, r.Method) - return - } - - data, err := io.ReadAll(r.Body) - if err != nil { - t.Fatal(err) - return - } - defer r.Body.Close() - - gotString := prettyJSON(bytes.NewReader(data)) - - if wantString != gotString { - t.Fatalf("wantUpstream: %s\ngot: %s\n", wantString, gotString) - return - } - - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("bar")) - })) - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "withBody", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte(REST1.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("POST"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("body"), - Value: []byte("{{ .arguments.input }}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.input"), - VariableName: []byte("input"), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("withBody"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - Variables: map[uint64][]byte{ - xxhash.Sum64String("input"): []byte(`{"foo": "fooValue", "bar": {"bal": "baz"}}`), - }, - } - - err = ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - expected := map[string]interface{}{ - "data": map[string]interface{}{ - "withBody": "bar", - }, - } - - wantResult, err := json.MarshalIndent(expected, "", " ") - if err != nil { - t.Fatal(err) - } - - want := string(wantResult) - got := prettyJSON(out) - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - return - } -} - -func TestExecutor_HTTPJSONDataSource_ArrayResponse(t *testing.T) { - - response := []interface{}{ - map[string]interface{}{ - "fieldValue": "foo", - }, - map[string]interface{}{ - "fieldValue": "bar", - }, - map[string]interface{}{ - "fieldValue": "baz", - }, - } - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - responseData, err := json.Marshal(response) - assert.NoError(t, err) - - w.WriteHeader(http.StatusOK) - _, _ = w.Write(responseData) - })) - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "objects", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte(REST1.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"SimpleType"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("objects"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("__typename"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - }, - }, - { - Name: []byte("fieldValue"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "fieldValue", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - expected := map[string]interface{}{ - "data": map[string]interface{}{ - "objects": []interface{}{ - map[string]interface{}{ - "__typename": "SimpleType", - "fieldValue": "foo", - }, - map[string]interface{}{ - "__typename": "SimpleType", - "fieldValue": "bar", - }, - map[string]interface{}{ - "__typename": "SimpleType", - "fieldValue": "baz", - }, - }, - }, - } - - wantResult, err := json.MarshalIndent(expected, "", " ") - if err != nil { - t.Fatal(err) - } - - want := string(wantResult) - got := prettyJSON(out) - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - return - } -} - -func TestExecutor_HTTPJSONDataSourceWithHeaders(t *testing.T) { - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - - for k, v := range map[string]string{ - "foo": "fooVal", - "bar": "barVal", - } { - got := r.Header.Get(k) - if got != v { - t.Fatalf("want header with key '%s' and value '%s', got: '%s'", k, v, got) - } - } - - w.WriteHeader(http.StatusOK) - _, _ = w.Write([]byte("bar")) - })) - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "withHeaders", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte(REST1.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.ListArgument{ - Name: []byte("headers"), - Arguments: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("foo"), - Value: []byte("fooVal"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("bar"), - Value: []byte("barVal"), - }, - }, - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("withHeaders"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - expected := map[string]interface{}{ - "data": map[string]interface{}{ - "withHeaders": "bar", - }, - } - - wantResult, err := json.MarshalIndent(expected, "", " ") - if err != nil { - t.Fatal(err) - } - - want := string(wantResult) - got := prettyJSON(out) - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - return - } -} - -func TestExecutor_HTTPJSONDataSourceWithPathSelector(t *testing.T) { - - response := []byte(` -{ - "name": {"first": "Tom", "last": "Anderson"}, - "age":37, - "children": ["Sara","Alex","Jack"], - "fav.movie": "Deer Hunter", - "friends": [ - {"first": "Dale", "last": "Murphy", "age": 44, "nets": ["ig", "fb", "tw"]}, - {"first": "Roger", "last": "Craig", "age": 68, "nets": ["fb", "tw"]}, - {"first": "Jane", "last": "Murphy", "age": 47, "nets": ["ig", "tw"]} - ] -}`) - - REST1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, _ = w.Write(response) - })) - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "friends", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte(REST1.URL + "/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("friends"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("firstNames"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "friends.#.first", - }, - }, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - expected := map[string]interface{}{ - "data": map[string]interface{}{ - "friends": map[string]interface{}{ - "firstNames": []string{"Dale", "Roger", "Jane"}, - }, - }, - } - - wantResult, err := json.MarshalIndent(expected, "", " ") - if err != nil { - t.Fatal(err) - } - - want := string(wantResult) - got := prettyJSON(out) - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - return - } -} - -func prettyJSON(r io.Reader) string { - var data interface{} - err := json.NewDecoder(r).Decode(&data) - if err != nil { - panic(err) - } - out, err := json.MarshalIndent(data, "", " ") - if err != nil { - panic(err) - } - return string(out) -} - -func TestExecutor_Introspection(t *testing.T) { - executor := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - schema := []byte(` - schema { - query: Query - } - type Query { - """ - multiline - description - """ - foo: String - __schema: __Schema! - } - `) - - config := datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "__schema", - DataSource: datasource.SourceConfig{ - Name: "SchemaDataSource", - Config: toJSON(datasource.SchemaDataSourcePlannerConfig{}), - }, - }, - }, - } - - base, err := datasource.NewBaseDataSourcePlanner(schema, config, log.NoopLogger) - if err != nil { - t.Fatal(err) - } - - err = base.RegisterDataSourcePlannerFactory("SchemaDataSource", datasource.SchemaDataSourcePlannerFactoryFactory{}) - if err != nil { - t.Fatal(err) - } - - handler := NewHandler(base, nil) - - gen := introspection.NewGenerator() - report := operationreport.Report{} - data := introspection.Data{} - gen.Generate(handler.base.Definition, &report, &data) - - introspectionData, err := json.Marshal(data) - if err != nil { - t.Fatal(err) - } - - out := bytes.Buffer{} - err = executor.Execute(ctx, introspectionQuery(introspectionData), &out) - if err != nil { - t.Fatal(err) - } - - response := out.Bytes() - - goldie.Assert(t, "introspection_execution", response) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/introspection_execution.golden") - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, fixture, response) - } -} - -func TestIsJSONObjectAsBytes(t *testing.T) { - run := func(inputString string, expectedResult bool) (string, func(t *testing.T)) { - return fmt.Sprintf("%s is %v", inputString, expectedResult), func(t *testing.T) { - inputBytes := []byte(inputString) - result := isJSONObjectAsBytes(inputBytes) - assert.Equal(t, expectedResult, result) - } - } - - t.Run(run("hello", false)) - t.Run(run("1", false)) - t.Run(run("query { meow }", false)) - t.Run(run(": - }", false)) - t.Run(run("{ - )", false)) - t.Run(run("{}", true)) - t.Run(run(" {}", true)) - t.Run(run("{} ", true)) - t.Run(run("{\"hello\": \"world\"}", true)) - t.Run(run(`{"hello": "world"}`, true)) -} - -func Test_byteSliceContainsEscapedQuotes(t *testing.T) { - run := func(inputString string, expectedResult bool) (string, func(t *testing.T)) { - return fmt.Sprintf("%s is %v", inputString, expectedResult), func(t *testing.T) { - inputBytes := []byte(inputString) - result := byteSliceContainsEscapedQuotes(inputBytes) - assert.Equal(t, expectedResult, result) - } - } - - t.Run(run(`"my dog is a string"`, false)) - t.Run(run(`[1, 2, 3, 4]`, false)) - t.Run(run(`{"key": "value"}`, false)) - - t.Run(run(`"the name of my dog is \"Hans\""`, true)) - t.Run(run(`{"test": "{foo: \"bar\"}"}`, true)) -} - -func Test_byteSliceContainsQuotes(t *testing.T) { - run := func(inputString string, expectedResult bool) (string, func(t *testing.T)) { - return fmt.Sprintf("%s is %v", inputString, expectedResult), func(t *testing.T) { - inputBytes := []byte(inputString) - result := byteSliceContainsQuotes(inputBytes) - assert.Equal(t, expectedResult, result) - } - } - - t.Run(run(`my dog is a string`, false)) - t.Run(run(`[1, 2, 3, 4]`, false)) - - t.Run(run(`the name of my dog is "Hans"`, true)) -} diff --git a/pkg/execution/fixtures/execution.golden b/pkg/execution/fixtures/execution.golden deleted file mode 100644 index d4e3b78a1..000000000 --- a/pkg/execution/fixtures/execution.golden +++ /dev/null @@ -1,52 +0,0 @@ -{ - "data": { - "__type": null, - "user": { - "birthday": "08.02.1988", - "friends": [ - { - "birthday": "1990 I guess? ;-)", - "id": 2, - "name": "Yaara", - "pets": [ - { - "__typename": "Dog", - "name": "Woof", - "nickname": "Woofie", - "woof": "Woof! Woof!" - } - ] - }, - { - "birthday": "1980", - "id": 3, - "name": "Ahmet", - "pets": [ - { - "__typename": "Cat", - "meow": "Meow meow!", - "name": "KitCat", - "nickname": "Kitty" - } - ] - } - ], - "id": 1, - "name": "Jens", - "pets": [ - { - "__typename": "Dog", - "name": "Paw", - "nickname": "Pawie", - "woof": "Woof! Woof!" - }, - { - "__typename": "Cat", - "meow": "Meow meow!", - "name": "Mietz", - "nickname": "Mietzie" - } - ] - } - } -} \ No newline at end of file diff --git a/pkg/execution/fixtures/handler_render_graphql_definitions.golden b/pkg/execution/fixtures/handler_render_graphql_definitions.golden deleted file mode 100644 index 2c7f5b6e5..000000000 --- a/pkg/execution/fixtures/handler_render_graphql_definitions.golden +++ /dev/null @@ -1,134 +0,0 @@ -directive @GraphQLDataSource - """ - the host of the origin - """ - host: String! - """ - the url of the origin - """ - url: String! - """ - the HTTP method the client should use for the request, defaults to GET - """ - method: HTTP_METHOD = POST - """ - the field/entry point on the remote schema - """ - field: String - """ - parameters - """ - params: [Parameter] - on FIELD_DEFINITION - -directive @HttpJsonDataSource - """ - the host of the origin - """ - host: String! - """ - the url of the origin - """ - url: String! - """ - the HTTP method the client should use for the request, defaults to GET - """ - method: HTTP_METHOD = GET - """ - parameters - """ - params: [Parameter] - on FIELD_DEFINITION - -""" -HttpPollingStreamDataSource -""" -directive @HttpPollingStreamDataSource - """ - host is the host name of the data source, e.g. example.com - """ - host: String! - """ - url is the URL from which the data source should poll data from - you could use golang templating syntax, e.g.: - '/users/{{ .id }}' + parameter named id with value 1 (see below) will render to URL '/users/1' - """ - url: String! - "method is the HTTP method the data source should use to fetch data from the upstream" - method: HTTP_METHOD = GET - "the delay in seconds between each polling" - delaySeconds: Int = 5 - """ - params are the parameters that should get passed to the data source - you could use this function to pass variables from field variables, the context or parent object to the data source - thse could be used to 'render' the url dynamically - """ - params: [Parameter] - on FIELD_DEFINITION - -directive @StaticDataSource - data: String - on FIELD_DEFINITION - -enum HTTP_METHOD { - GET - POST - UPDATE - DELETE -} - -"PARAMETER_SOURCE defines the source of a dyanmic parameter" -enum PARAMETER_SOURCE { - "parameter from the context object which could be populated by the http wrapper" - CONTEXT_VARIABLE - """ - parameter from the parent object - example: - consider the following query: - { - user(id: 1) { - userID - friends - } - } - Using the PARAMETER_SOURCE 'OBJECT_VARIABLE_ARGUMENT' with sourceName 'userID' returns the userID for user with id 1 at runtime. - This way you can dynamically build a query to the friends resource using the userID at runtime and inject it into the second query. - """ - OBJECT_VARIABLE_ARGUMENT - """ - parameter from the field arguments - example: - consider the following query: - { - user(id: 1) { - friends - } - } - Using the PARAMETER_SOURCE 'FIELD_ARGUMENTS' with sourceName 'id' returns 1 at runtime. - This way you can render the resource url for /user/:id to /user/1 at runtime dynamically. - """ - FIELD_ARGUMENTS -} - -""" -Parameter is useful to map variables from various sources into the data source executor. -""" -input Parameter { - """ - this is the name by which the execution engine will access the variable - """ - name: String! - """ - the kind of the parameter source - currently sources: the context, the enclosing object (at execution time), field variables - """ - sourceKind: PARAMETER_SOURCE! - """ - name of the parameter on the source - """ - sourceName: String! - """ - type name of the variable, used to generate a valid GraphQL query for the upstream - """ - variableType: String! -} \ No newline at end of file diff --git a/pkg/execution/fixtures/introspection_execution.golden b/pkg/execution/fixtures/introspection_execution.golden deleted file mode 100644 index e7bc1950f..000000000 --- a/pkg/execution/fixtures/introspection_execution.golden +++ /dev/null @@ -1 +0,0 @@ -{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":null,"subscriptionType":null,"types":[{"kind":"OBJECT","name":"Query","description":null,"fields":[{"name":"foo","description":"multiline\n\t\t\tdescription","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Int","description":"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Float","description":"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"String","description":"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Boolean","description":"The 'Boolean' scalar type represents 'true' or 'false' .","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"ID","description":"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"skip","description":"Directs the executor to skip this field or fragment when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"deprecated","description":"Marks an element of a GraphQL schema as no longer supported.","locations":["FIELD_DEFINITION","ENUM_VALUE"],"args":[{"name":"reason","description":"Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"\"No longer supported\""}]}]}}} \ No newline at end of file diff --git a/pkg/execution/fixtures/render_graphql_definitions.golden b/pkg/execution/fixtures/render_graphql_definitions.golden deleted file mode 100644 index c54514526..000000000 --- a/pkg/execution/fixtures/render_graphql_definitions.golden +++ /dev/null @@ -1,246 +0,0 @@ -directive @GraphQLDataSource - """ - the host of the origin - """ - host: String! - """ - the url of the origin - """ - url: String! - """ - the HTTP method the client should use for the request, defaults to GET - """ - method: HTTP_METHOD = POST - """ - parameters - """ - params: [Parameter] - on FIELD_DEFINITION - -directive @HttpJsonDataSource - """ - the host of the origin - """ - host: String! - """ - the url of the origin - """ - url: String! - """ - the HTTP method the client should use for the request, defaults to GET - """ - method: HTTP_METHOD = GET - """ - parameters - """ - params: [Parameter] - """ - body is the optional definition of the http body to be sent to the upstream - golang templating syntax might be used to create the body - """ - body: String - """ - headers are the key value pairs to be set on the upstream request - """ - headers: [Header] - """ - defaultTypeName is an optional argument to set the default __typename - in case there is only one possible __typename this arg can be omitted - if there are multiple options in the statusCodeTypeNameMappings but none matches the defaultTypeName will be chosen - """ - defaultTypeName: String - """ - statusCodeTypeNameMappings is a mapping table to map from exact status codes to a __typename - example: - 200 -> OperationSuccessType - 500 -> OperationFailedType - This gives the user the opportunity to map the JSON response from the upstream to different union/interface definitions - """ - statusCodeTypeNameMappings: [StatusCodeTypeNameMapping] - on FIELD_DEFINITION - -""" -HttpPollingStreamDataSource -""" -directive @HttpPollingStreamDataSource - """ - host is the host name of the data source, e.g. example.com - """ - host: String! - """ - url is the URL from which the data source should poll data from - you could use golang templating syntax, e.g.: - '/users/{{ .Id }}' + parameter named id with value 1 (see below) will render to URL '/users/1' - """ - url: String! - "method is the HTTP method the data source should use to fetch data from the upstream" - method: HTTP_METHOD = GET - "the delay in seconds between each polling" - delaySeconds: Int = 5 - """ - params are the parameters that should get passed to the data source - you could use this function to pass variables from field variables, the context or parent object to the data source - thse could be used to 'render' the url dynamically - """ - params: [Parameter] - on FIELD_DEFINITION - -""" -mapping is the directive to define mappings from response objects to GraphQL fields -""" -directive @mapping - """ - mode defines the operating mode of the mapping - """ - mode: MAPPING_MODE! = PATH_SELECTOR - """ - pathSelector is the optional selector String to customize the mappings - see https://github.com/tidwall/gjson for more information on what syntax is possible - """ - pathSelector: String - on FIELD_DEFINITION - -""" -MQTTDataSource -""" -directive @MQTTDataSource - brokerAddr: String! - clientID: String! - topic: String! - on FIELD_DEFINITION - -""" -NatsDataSource -""" -directive @NatsDataSource - addr: String! - topic: String! - on FIELD_DEFINITION - -directive @PipelineDataSource - """ - configFilePath is the path where the pipeline configuration file can be found - it needs to be in the json format according to the pipeline json schema - see this url for more info: https://github.com/jensneuse/pipeline - """ - configFilePath: String - """ - configString is a string to configure the pipeline - it needs to be in the json format according to the pipeline json schema - see this url for more info: https://github.com/jensneuse/pipeline - - The PipelinDataSourcePlanner will always choose the configString over the configFilePath in case both are defined. - """ - configString: String - """ - inputJSON is the template to define a JSON object based on the request, parameters etc. which gets passed to the first pipeline step - """ - inputJSON: String! - on FIELD_DEFINITION - -directive @StaticDataSource - data: String - on FIELD_DEFINITION - -directive @transformation - mode: TRANSFORMATION_MODE = PIPELINE - pipelineConfigFile: String - pipelineConfigString: String - on FIELD_DEFINITION - -directive @WasmDataSource - input: String! - wasmFile: String! - on FIELD_DEFINITION - -enum HTTP_METHOD { - GET - POST - UPDATE - DELETE -} - -""" -MAPPING_MODE is the enum to define the different mapper modes -""" -enum MAPPING_MODE { - """ - NONE is the mode to skip mappings at all, therefore the parent object will directly get passed to the child - """ - NONE - """ - PATH_SELECTOR is the mode which applies a path selector string on the parent object before passing it to the child - see https://github.com/tidwall/gjson for more information on what syntax is possible - """ - PATH_SELECTOR -} - -"PARAMETER_SOURCE defines the source of a dyanmic parameter" -enum PARAMETER_SOURCE { - "parameter from the context object which could be populated by the http wrapper" - CONTEXT_VARIABLE - """ - parameter from the parent object - example: - consider the following query: - { - user(id: 1) { - userID - friends - } - } - Using the PARAMETER_SOURCE 'OBJECT_VARIABLE_ARGUMENT' with sourceName 'userID' returns the userID for user with id 1 at runtime. - This way you can dynamically build a query to the friends resource using the userID at runtime and inject it into the second query. - """ - OBJECT_VARIABLE_ARGUMENT - """ - parameter from the field arguments - example: - consider the following query: - { - user(id: 1) { - friends - } - } - Using the PARAMETER_SOURCE 'FIELD_ARGUMENTS' with sourceName 'id' returns 1 at runtime. - This way you can render the resource url for /user/:id to /user/1 at runtime dynamically. - """ - FIELD_ARGUMENTS -} - -enum TRANSFORMATION_MODE { - PIPELINE -} - -input Header { - key: String! - value: String! -} - -""" -Parameter is useful to map variables from various sources into the data source executor. -""" -input Parameter { - """ - this is the name by which the execution engine will access the variable - """ - name: String! - """ - the kind of the parameter source - currently sources: the context, the enclosing object (at execution time), field variables - """ - sourceKind: PARAMETER_SOURCE! - """ - name of the parameter on the source - """ - sourceName: String! - """ - type name of the variable, used to generate a valid GraphQL query for the upstream - """ - variableType: String! -} - -input StatusCodeTypeNameMapping { - statusCode: Int! - typeName: String! -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/graphql_datasource.graphql b/pkg/execution/graphql_definitions/directives/graphql_datasource.graphql deleted file mode 100644 index 3f4cdff4b..000000000 --- a/pkg/execution/graphql_definitions/directives/graphql_datasource.graphql +++ /dev/null @@ -1,18 +0,0 @@ -directive @GraphQLDataSource ( - """ - the host of the origin - """ - host: String! - """ - the url of the origin - """ - url: String! - """ - the HTTP method the client should use for the request, defaults to GET - """ - method: HTTP_METHOD = POST - """ - parameters - """ - params: [Parameter] -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/http_json_datasource.graphql b/pkg/execution/graphql_definitions/directives/http_json_datasource.graphql deleted file mode 100644 index 3caa2dd18..000000000 --- a/pkg/execution/graphql_definitions/directives/http_json_datasource.graphql +++ /dev/null @@ -1,41 +0,0 @@ -directive @HttpJsonDataSource ( - """ - the host of the origin - """ - host: String! - """ - the url of the origin - """ - url: String! - """ - the HTTP method the client should use for the request, defaults to GET - """ - method: HTTP_METHOD = GET - """ - parameters - """ - params: [Parameter] - """ - body is the optional definition of the http body to be sent to the upstream - golang templating syntax might be used to create the body - """ - body: String - """ - headers are the key value pairs to be set on the upstream request - """ - headers: [Header] - """ - defaultTypeName is an optional argument to set the default __typename - in case there is only one possible __typename this arg can be omitted - if there are multiple options in the statusCodeTypeNameMappings but none matches the defaultTypeName will be chosen - """ - defaultTypeName: String - """ - statusCodeTypeNameMappings is a mapping table to map from exact status codes to a __typename - example: - 200 -> OperationSuccessType - 500 -> OperationFailedType - This gives the user the opportunity to map the JSON response from the upstream to different union/interface definitions - """ - statusCodeTypeNameMappings: [StatusCodeTypeNameMapping] -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/http_polling_stream_datasource.graphql b/pkg/execution/graphql_definitions/directives/http_polling_stream_datasource.graphql deleted file mode 100644 index 72f75489c..000000000 --- a/pkg/execution/graphql_definitions/directives/http_polling_stream_datasource.graphql +++ /dev/null @@ -1,25 +0,0 @@ -""" -HttpPollingStreamDataSource -""" -directive @HttpPollingStreamDataSource ( - """ - host is the host name of the data source, e.g. example.com - """ - host: String! - """ - url is the URL from which the data source should poll data from - you could use golang templating syntax, e.g.: - '/users/{{ .Id }}' + parameter named id with value 1 (see below) will render to URL '/users/1' - """ - url: String! - "method is the HTTP method the data source should use to fetch data from the upstream" - method: HTTP_METHOD = GET - "the delay in seconds between each polling" - delaySeconds: Int = 5 - """ - params are the parameters that should get passed to the data source - you could use this function to pass variables from field variables, the context or parent object to the data source - thse could be used to 'render' the url dynamically - """ - params: [Parameter] -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/mapping.graphql b/pkg/execution/graphql_definitions/directives/mapping.graphql deleted file mode 100644 index bdfa6635c..000000000 --- a/pkg/execution/graphql_definitions/directives/mapping.graphql +++ /dev/null @@ -1,14 +0,0 @@ -""" -mapping is the directive to define mappings from response objects to GraphQL fields -""" -directive @mapping( - """ - mode defines the operating mode of the mapping - """ - mode: MAPPING_MODE! = PATH_SELECTOR - """ - pathSelector is the optional selector String to customize the mappings - see https://github.com/tidwall/gjson for more information on what syntax is possible - """ - pathSelector: String -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/mqtt_datasource.graphql b/pkg/execution/graphql_definitions/directives/mqtt_datasource.graphql deleted file mode 100644 index 722c79968..000000000 --- a/pkg/execution/graphql_definitions/directives/mqtt_datasource.graphql +++ /dev/null @@ -1,8 +0,0 @@ -""" -MQTTDataSource -""" -directive @MQTTDataSource ( - brokerAddr: String! - clientID: String! - topic: String! -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/nats_datasource.graphql b/pkg/execution/graphql_definitions/directives/nats_datasource.graphql deleted file mode 100644 index 1fb815ec5..000000000 --- a/pkg/execution/graphql_definitions/directives/nats_datasource.graphql +++ /dev/null @@ -1,7 +0,0 @@ -""" -NatsDataSource -""" -directive @NatsDataSource ( - addr: String! - topic: String! -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/pipeline_datasource.graphql b/pkg/execution/graphql_definitions/directives/pipeline_datasource.graphql deleted file mode 100644 index 963bb291b..000000000 --- a/pkg/execution/graphql_definitions/directives/pipeline_datasource.graphql +++ /dev/null @@ -1,20 +0,0 @@ -directive @PipelineDataSource ( - """ - configFilePath is the path where the pipeline configuration file can be found - it needs to be in the json format according to the pipeline json schema - see this url for more info: https://github.com/jensneuse/pipeline - """ - configFilePath: String - """ - configString is a string to configure the pipeline - it needs to be in the json format according to the pipeline json schema - see this url for more info: https://github.com/jensneuse/pipeline - - The PipelinDataSourcePlanner will always choose the configString over the configFilePath in case both are defined. - """ - configString: String - """ - inputJSON is the template to define a JSON object based on the request, parameters etc. which gets passed to the first pipeline step - """ - inputJSON: String! -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/static_datasource.graphql b/pkg/execution/graphql_definitions/directives/static_datasource.graphql deleted file mode 100644 index 329cf9684..000000000 --- a/pkg/execution/graphql_definitions/directives/static_datasource.graphql +++ /dev/null @@ -1,3 +0,0 @@ -directive @StaticDataSource ( - data: String -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/transformation.graphql b/pkg/execution/graphql_definitions/directives/transformation.graphql deleted file mode 100644 index ac8f27f0c..000000000 --- a/pkg/execution/graphql_definitions/directives/transformation.graphql +++ /dev/null @@ -1,5 +0,0 @@ -directive @transformation( - mode: TRANSFORMATION_MODE = PIPELINE - pipelineConfigFile: String - pipelineConfigString: String -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/directives/wasm_datasource.graphql b/pkg/execution/graphql_definitions/directives/wasm_datasource.graphql deleted file mode 100644 index 2f371df38..000000000 --- a/pkg/execution/graphql_definitions/directives/wasm_datasource.graphql +++ /dev/null @@ -1,4 +0,0 @@ -directive @WasmDataSource ( - input: String! - wasmFile: String! -) on FIELD_DEFINITION \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/enums/http_method.graphql b/pkg/execution/graphql_definitions/enums/http_method.graphql deleted file mode 100644 index b31299cba..000000000 --- a/pkg/execution/graphql_definitions/enums/http_method.graphql +++ /dev/null @@ -1,6 +0,0 @@ -enum HTTP_METHOD { - GET - POST - UPDATE - DELETE -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/enums/mapping_mode.graphql b/pkg/execution/graphql_definitions/enums/mapping_mode.graphql deleted file mode 100644 index c927da9b3..000000000 --- a/pkg/execution/graphql_definitions/enums/mapping_mode.graphql +++ /dev/null @@ -1,14 +0,0 @@ -""" -MAPPING_MODE is the enum to define the different mapper modes -""" -enum MAPPING_MODE { - """ - NONE is the mode to skip mappings at all, therefore the parent object will directly get passed to the child - """ - NONE - """ - PATH_SELECTOR is the mode which applies a path selector string on the parent object before passing it to the child - see https://github.com/tidwall/gjson for more information on what syntax is possible - """ - PATH_SELECTOR -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/enums/parameter_source.graphql b/pkg/execution/graphql_definitions/enums/parameter_source.graphql deleted file mode 100644 index 54b46cb62..000000000 --- a/pkg/execution/graphql_definitions/enums/parameter_source.graphql +++ /dev/null @@ -1,32 +0,0 @@ -"PARAMETER_SOURCE defines the source of a dyanmic parameter" -enum PARAMETER_SOURCE { - "parameter from the context object which could be populated by the http wrapper" - CONTEXT_VARIABLE - """ - parameter from the parent object - example: - consider the following query: - { - user(id: 1) { - userID - friends - } - } - Using the PARAMETER_SOURCE 'OBJECT_VARIABLE_ARGUMENT' with sourceName 'userID' returns the userID for user with id 1 at runtime. - This way you can dynamically build a query to the friends resource using the userID at runtime and inject it into the second query. - """ - OBJECT_VARIABLE_ARGUMENT - """ - parameter from the field arguments - example: - consider the following query: - { - user(id: 1) { - friends - } - } - Using the PARAMETER_SOURCE 'FIELD_ARGUMENTS' with sourceName 'id' returns 1 at runtime. - This way you can render the resource url for /user/:id to /user/1 at runtime dynamically. - """ - FIELD_ARGUMENTS -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/enums/transformation_mode.graphql b/pkg/execution/graphql_definitions/enums/transformation_mode.graphql deleted file mode 100644 index e6bcf723d..000000000 --- a/pkg/execution/graphql_definitions/enums/transformation_mode.graphql +++ /dev/null @@ -1,3 +0,0 @@ -enum TRANSFORMATION_MODE { - PIPELINE -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/inputs/header.graphql b/pkg/execution/graphql_definitions/inputs/header.graphql deleted file mode 100644 index e32d42d46..000000000 --- a/pkg/execution/graphql_definitions/inputs/header.graphql +++ /dev/null @@ -1,4 +0,0 @@ -input Header { - key: String! - value: String! -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/inputs/parameter.graphql b/pkg/execution/graphql_definitions/inputs/parameter.graphql deleted file mode 100644 index cdf3a2038..000000000 --- a/pkg/execution/graphql_definitions/inputs/parameter.graphql +++ /dev/null @@ -1,22 +0,0 @@ -""" -Parameter is useful to map variables from various sources into the data source executor. -""" -input Parameter { - """ - this is the name by which the execution engine will access the variable - """ - name: String! - """ - the kind of the parameter source - currently sources: the context, the enclosing object (at execution time), field variables - """ - sourceKind: PARAMETER_SOURCE! - """ - name of the parameter on the source - """ - sourceName: String! - """ - type name of the variable, used to generate a valid GraphQL query for the upstream - """ - variableType: String! -} \ No newline at end of file diff --git a/pkg/execution/graphql_definitions/inputs/statuscode_typename_mapping.graphql b/pkg/execution/graphql_definitions/inputs/statuscode_typename_mapping.graphql deleted file mode 100644 index c033ca730..000000000 --- a/pkg/execution/graphql_definitions/inputs/statuscode_typename_mapping.graphql +++ /dev/null @@ -1,4 +0,0 @@ -input StatusCodeTypeNameMapping { - statusCode: Int! - typeName: String! -} \ No newline at end of file diff --git a/pkg/execution/handler.go b/pkg/execution/handler.go deleted file mode 100644 index 0ed7d48a4..000000000 --- a/pkg/execution/handler.go +++ /dev/null @@ -1,109 +0,0 @@ -//go:generate graphql-go-tools gen directiveUnmarshalCode -f ./graphql_definitions/**/*.graphql -p execution -o ./datasource_config.go -s Config -package execution - -import ( - "encoding/json" - - "github.com/buger/jsonparser" - "github.com/cespare/xxhash/v2" - byte_template "github.com/jensneuse/byte-template" - - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" -) - -type Handler struct { - templateDirectives []byte_template.DirectiveDefinition - base *datasource.BasePlanner -} - -func NewHandler(base *datasource.BasePlanner, templateDirectives []byte_template.DirectiveDefinition) *Handler { - return &Handler{ - templateDirectives: templateDirectives, - base: base, - } -} - -type GraphqlRequest struct { - OperationName string `json:"operationName"` - Variables json.RawMessage `json:"variables"` - Query string `json:"query"` -} - -func (h *Handler) Handle(requestData, extraVariables []byte) (executor *Executor, node RootNode, ctx Context, err error) { - - var graphqlRequest GraphqlRequest - err = json.Unmarshal(requestData, &graphqlRequest) - if err != nil { - return - } - - operationDocument, report := astparser.ParseGraphqlDocumentString(graphqlRequest.Query) - if report.HasErrors() { - err = report - return - } - - variables, extraArguments := VariablesFromJson(graphqlRequest.Variables, extraVariables) - - planner := NewPlanner(h.base) - if report.HasErrors() { - err = report - return - } - - astnormalization.NormalizeOperation(&operationDocument, h.base.Definition, &report) - if report.HasErrors() { - err = report - return - } - - validator := astvalidation.DefaultOperationValidator() - if report.HasErrors() { - err = report - return - } - validator.Validate(&operationDocument, h.base.Definition, &report) - if report.HasErrors() { - err = report - return - } - normalizer := astnormalization.NewNormalizer(true, true) - normalizer.NormalizeOperation(&operationDocument, h.base.Definition, &report) - if report.HasErrors() { - err = report - return - } - plan := planner.Plan(&operationDocument, h.base.Definition, graphqlRequest.OperationName, &report) - if report.HasErrors() { - err = report - return - } - - executor = NewExecutor(h.templateDirectives) - ctx = Context{ - Variables: variables, - ExtraArguments: extraArguments, - } - - return executor, plan, ctx, err -} - -func VariablesFromJson(requestVariables, extraVariables []byte) (variables Variables, extraArguments []datasource.Argument) { - variables = map[uint64][]byte{} - _ = jsonparser.ObjectEach(requestVariables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { - variables[xxhash.Sum64(key)] = value - return nil - }) - _ = jsonparser.ObjectEach(extraVariables, func(key []byte, value []byte, dataType jsonparser.ValueType, offset int) error { - variables[xxhash.Sum64(key)] = value - extraArguments = append(extraArguments, &datasource.ContextVariableArgument{ - Name: key, - VariableName: key, - }) - return nil - }) - return -} diff --git a/pkg/execution/handler_test.go b/pkg/execution/handler_test.go deleted file mode 100644 index 1c145523d..000000000 --- a/pkg/execution/handler_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package execution - -import ( - "bytes" - "testing" - - "github.com/cespare/xxhash/v2" - - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" -) - -func TestHandler_VariablesFromRequest(t *testing.T) { - request := GraphqlRequest{ - Variables: []byte(`{"foo":"bar"}`), - } - - extra := []byte(`{"request":{"headers":{"Authorization":"Bearer foo123"}}}`) - - variables, extraArguments := VariablesFromJson(request.Variables, extra) - - for key, value := range map[string]string{ - "foo": "bar", - "request": `{"headers":{"Authorization":"Bearer foo123"}}`, - } { - got := string(variables[xxhash.Sum64String(key)]) - want := value - if got != want { - t.Errorf("want {{ %s }}, got: {{ %s }}'", want, got) - } - } - - if len(extraArguments) != 1 { - t.Fatalf("want 1") - } - - if !bytes.Equal(extraArguments[0].(*datasource.ContextVariableArgument).Name, []byte("request")) { - t.Fatalf("unexpected") - } - if !bytes.Equal(extraArguments[0].(*datasource.ContextVariableArgument).VariableName, []byte("request")) { - t.Fatalf("unexpected") - } -} diff --git a/pkg/execution/jsonvaluetype.go b/pkg/execution/jsonvaluetype.go deleted file mode 100644 index 66ece8e92..000000000 --- a/pkg/execution/jsonvaluetype.go +++ /dev/null @@ -1,84 +0,0 @@ -//go:generate stringer -type=JSONValueType -package execution - -import ( - "bytes" - "fmt" - "io" - "strconv" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type JSONValueType int - -const ( - UnknownValueType JSONValueType = iota - StringValueType - IntegerValueType - FloatValueType - BooleanValueType -) - -type ErrJSONValueTypeValueIncompatible struct { - value []byte - valueType JSONValueType -} - -func (e ErrJSONValueTypeValueIncompatible) Error() string { - return fmt.Sprintf("JSONValueType.writeValue: cannot write %s as %s", unsafebytes.BytesToString(e.value), e.valueType) -} - -func (i JSONValueType) writeValue(value, escapeBuf []byte, out io.Writer) (n int, err error) { - - if len(value) == 0 || bytes.Equal(value, literal.NULL) { - return i.write(n, err, out, literal.NULL) - } - - switch i { - case StringValueType: - return i.write(n, err, out, []byte(strconv.Quote(string(value)))) - case IntegerValueType: - if !unsafebytes.BytesIsValidInt64(value) { - return n, ErrJSONValueTypeValueIncompatible{ - value: value, - valueType: i, - } - } - return i.write(n, err, out, value) - case FloatValueType: - if !unsafebytes.BytesIsValidFloat32(value) { - return n, ErrJSONValueTypeValueIncompatible{ - value: value, - valueType: i, - } - } - return i.write(n, err, out, value) - case BooleanValueType: - if !unsafebytes.BytesIsValidBool(value) { - return n, ErrJSONValueTypeValueIncompatible{ - value: value, - valueType: i, - } - } - if unsafebytes.BytesToBool(value) { - return i.write(n, err, out, literal.TRUE) - } else { - return i.write(n, err, out, literal.FALSE) - } - default: - return n, ErrJSONValueTypeValueIncompatible{ - value: value, - valueType: i, - } - } -} - -func (i JSONValueType) write(n int, err error, out io.Writer, value []byte) (int, error) { - if err != nil { - return n, err - } - written, err := out.Write(value) - return n + written, err -} diff --git a/pkg/execution/jsonvaluetype_string.go b/pkg/execution/jsonvaluetype_string.go deleted file mode 100644 index 885bb9805..000000000 --- a/pkg/execution/jsonvaluetype_string.go +++ /dev/null @@ -1,27 +0,0 @@ -// Code generated by "stringer -type=JSONValueType"; DO NOT EDIT. - -package execution - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[UnknownValueType-0] - _ = x[StringValueType-1] - _ = x[IntegerValueType-2] - _ = x[FloatValueType-3] - _ = x[BooleanValueType-4] -} - -const _JSONValueType_name = "UnknownValueTypeStringValueTypeIntegerValueTypeFloatValueTypeBooleanValueType" - -var _JSONValueType_index = [...]uint8{0, 16, 31, 47, 61, 77} - -func (i JSONValueType) String() string { - if i < 0 || i >= JSONValueType(len(_JSONValueType_index)-1) { - return "JSONValueType(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _JSONValueType_name[_JSONValueType_index[i]:_JSONValueType_index[i+1]] -} diff --git a/pkg/execution/jsonvaluetype_test.go b/pkg/execution/jsonvaluetype_test.go deleted file mode 100644 index f34a68b49..000000000 --- a/pkg/execution/jsonvaluetype_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package execution - -import ( - "bytes" - "testing" -) - -func TestJSONValueType_writeValue(t *testing.T) { - run := func(valueType JSONValueType, value []byte, expectErr bool, expectString string) func(t *testing.T) { - return func(t *testing.T) { - buf := bytes.Buffer{} - _, err := valueType.writeValue(value, nil, &buf) - if expectErr && err == nil { - t.Fatal("expected err, got nil") - } - if !expectErr && err != nil { - t.Fatalf("expected nil error, got: %s", err) - } - if expectString != buf.String() { - t.Fatalf("expected out: %s, got: %s", expectString, buf.String()) - } - } - } - - t.Run("valid string", run(StringValueType, []byte("foo"), false, `"foo"`)) - - t.Run("valid integer", run(IntegerValueType, []byte("123"), false, `123`)) - t.Run("invalid integer", run(IntegerValueType, []byte("1.23"), true, "")) - t.Run("invalid integer", run(IntegerValueType, []byte("true"), true, "")) - t.Run("invalid integer", run(IntegerValueType, []byte("false"), true, "")) - t.Run("invalid integer", run(IntegerValueType, []byte(`"123"`), true, "")) - - t.Run("valid bool", run(BooleanValueType, []byte("true"), false, "true")) - t.Run("valid bool", run(BooleanValueType, []byte("false"), false, "false")) - t.Run("invalid bool", run(BooleanValueType, []byte("1.23"), true, "")) - t.Run("invalid bool", run(BooleanValueType, []byte("123"), true, "")) - t.Run("invalid bool", run(BooleanValueType, []byte(`"true"`), true, "")) - - t.Run("valid float", run(FloatValueType, []byte("1.23"), false, "1.23")) - t.Run("valid float", run(FloatValueType, []byte("123"), false, "123")) - t.Run("invalid float", run(FloatValueType, []byte("1.2.3"), true, "")) - t.Run("invalid float", run(FloatValueType, []byte("true"), true, "")) - t.Run("invalid float", run(FloatValueType, []byte(`"123"`), true, "")) -} diff --git a/pkg/execution/planning.go b/pkg/execution/planning.go deleted file mode 100644 index 5f63f624e..000000000 --- a/pkg/execution/planning.go +++ /dev/null @@ -1,436 +0,0 @@ -package execution - -import ( - "bytes" - "io" - "os" - - "github.com/jensneuse/pipeline/pkg/pipe" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type Planner struct { - walker *astvisitor.Walker - visitor *planningVisitor -} - -type DataSourceDefinition struct { - // the type name to which the data source is attached - TypeName []byte - // the field on the type to which the data source is attached - FieldName []byte - // a factory method to return a new planner - DataSourcePlannerFactory func() datasource.Planner -} - -func NewPlanner(base *datasource.BasePlanner) *Planner { - walker := astvisitor.NewWalker(48) - visitor := planningVisitor{ - Walker: &walker, - base: base, - } - - walker.RegisterDocumentVisitor(&visitor) - walker.RegisterEnterFieldVisitor(&visitor) - walker.RegisterEnterArgumentVisitor(&visitor) - walker.RegisterLeaveFieldVisitor(&visitor) - walker.RegisterEnterSelectionSetVisitor(&visitor) - walker.RegisterLeaveSelectionSetVisitor(&visitor) - walker.RegisterEnterInlineFragmentVisitor(&visitor) - walker.RegisterLeaveInlineFragmentVisitor(&visitor) - walker.RegisterEnterOperationVisitor(&visitor) - - return &Planner{ - walker: &walker, - visitor: &visitor, - } -} - -func (p *Planner) Plan(operation, definition *ast.Document, operationName string, report *operationreport.Report) RootNode { - p.visitor.operationName = operationName - p.walker.Walk(operation, definition, report) - return p.visitor.rootNode -} - -type planningVisitor struct { - *astvisitor.Walker - base *datasource.BasePlanner - operation, definition *ast.Document - rootNode RootNode - currentNode []Node - planners []dataSourcePlannerRef - operationName string - foundOperation bool - isSingleOperation bool -} - -type dataSourcePlannerRef struct { - path ast.Path - fieldRef int - planner datasource.Planner -} - -func (p *planningVisitor) EnterDocument(operation, definition *ast.Document) { - p.operation, p.definition, p.base.Definition = operation, definition, definition - p.foundOperation = false - p.isSingleOperation = p.countOperationDefinitionsInRootNodes() == 1 - - if len(operation.OperationDefinitions) == 0 { - p.Walker.StopWithExternalErr(operationreport.ErrDocumentDoesntContainExecutableOperation()) - return - } - - p.currentNode = p.currentNode[:0] - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.EnterDocument(operation, definition) - } -} - -func (p *planningVisitor) LeaveDocument(operation, definition *ast.Document) { - if !p.isSingleOperation && len(p.operationName) == 0 { - p.Report.AddExternalError(operationreport.ErrRequiredOperationNameIsMissing()) - } else if !p.foundOperation { - p.Report.AddExternalError(operationreport.ErrOperationWithProvidedOperationNameNotFound(p.operationName)) - } -} - -func (p *planningVisitor) EnterOperationDefinition(ref int) { - operationName := p.operation.OperationDefinitionNameString(ref) - if !p.isSingleOperation && operationName != p.operationName { - p.SkipNode() - return - } - - p.foundOperation = true - obj := &Object{} - p.rootNode = &Object{ - operationType: p.operation.OperationDefinitions[ref].OperationType, - Fields: []Field{ - { - Name: literal.DATA, - Value: obj, - }, - }, - } - p.currentNode = append(p.currentNode, obj) -} - -func (p *planningVisitor) EnterInlineFragment(ref int) { - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.EnterInlineFragment(ref) - } -} - -func (p *planningVisitor) LeaveInlineFragment(ref int) { - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.LeaveInlineFragment(ref) - } -} - -func (p *planningVisitor) EnterField(ref int) { - fieldName := p.operation.FieldNameUnsafeString(ref) - - definition, exists := p.FieldDefinition(ref) - if !exists { - return - } - - typeName := p.definition.NodeResolverTypeNameString(p.EnclosingTypeDefinition, p.Path) - - plannerFactory := p.base.Config.DataSourcePlannerFactoryForTypeField(typeName, fieldName) - if plannerFactory != nil { - planner := plannerFactory.DataSourcePlanner() - planner.Configure(p.operation, p.definition, p.Walker) - p.planners = append(p.planners, dataSourcePlannerRef{ - path: p.Path, - fieldRef: ref, - planner: planner, - }) - } - - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.EnterField(ref) - } - - switch parent := p.currentNode[len(p.currentNode)-1].(type) { - case *Object: - - var skipCondition BooleanCondition - ancestor := p.Ancestors[len(p.Ancestors)-2] - if ancestor.Kind == ast.NodeKindInlineFragment { - typeConditionName := p.operation.InlineFragmentTypeConditionName(ancestor.Ref) - skipCondition = &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: typeConditionName, - }, - } - } - - dataResolvingConfig := p.fieldDataResolvingConfig(ref) - - var value Node - fieldDefinitionType := p.definition.FieldDefinitionType(definition) - - if p.definition.TypeIsList(fieldDefinitionType) { - - if !p.operation.FieldHasSelections(ref) { - value = &Value{ - ValueType: p.jsonValueType(fieldDefinitionType), - } - } else { - value = &Object{} - } - - list := &List{ - DataResolvingConfig: dataResolvingConfig, - Value: value, - } - - firstNValue, ok := p.FieldDefinitionDirectiveArgumentValueByName(ref, []byte("ListFilterFirstN"), []byte("n")) - if ok { - if firstNValue.Kind == ast.ValueKindInteger { - firstN := p.definition.IntValueAsInt32(firstNValue.Ref) - list.Filter = &ListFilterFirstN{ - FirstN: int(firstN), - } - } - } - - parent.Fields = append(parent.Fields, Field{ - Name: p.operation.FieldNameBytes(ref), - Value: list, - Skip: skipCondition, - }) - - p.currentNode = append(p.currentNode, value) - return - } - - if !p.operation.FieldHasSelections(ref) { - value = &Value{ - DataResolvingConfig: dataResolvingConfig, - ValueType: p.jsonValueType(fieldDefinitionType), - } - } else { - value = &Object{ - DataResolvingConfig: dataResolvingConfig, - } - } - - parent.Fields = append(parent.Fields, Field{ - Name: p.operation.FieldAliasOrNameBytes(ref), - Value: value, - Skip: skipCondition, - }) - - p.currentNode = append(p.currentNode, value) - } -} - -func (p *planningVisitor) EnterArgument(ref int) { - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.EnterArgument(ref) - } -} - -func (p *planningVisitor) LeaveField(ref int) { - - var plannedDataSource datasource.DataSource - var plannedArgs []datasource.Argument - - if len(p.planners) != 0 { - - p.planners[len(p.planners)-1].planner.LeaveField(ref) - - if p.planners[len(p.planners)-1].path.Equals(p.Path) && p.planners[len(p.planners)-1].fieldRef == ref { - plannedDataSource, plannedArgs = p.planners[len(p.planners)-1].planner.Plan(p.fieldContextVariableArguments(ref)) - p.planners = p.planners[:len(p.planners)-1] - - if len(p.currentNode) >= 2 { - switch parent := p.currentNode[len(p.currentNode)-2].(type) { - case *Object: - for i := 0; i < len(parent.Fields); i++ { - if bytes.Equal(p.operation.FieldAliasOrNameBytes(ref), parent.Fields[i].Name) { - - pathName := p.operation.FieldAliasOrNameString(ref) - parent.Fields[i].HasResolvedData = true - - singleFetch := &SingleFetch{ - Source: &DataSourceInvocation{ - Args: plannedArgs, - DataSource: plannedDataSource, - }, - BufferName: pathName, - } - - if parent.Fetch == nil { - parent.Fetch = singleFetch - } else { - switch fetch := parent.Fetch.(type) { - case *ParallelFetch: - fetch.Fetches = append(fetch.Fetches, singleFetch) - case *SerialFetch: - fetch.Fetches = append(fetch.Fetches, singleFetch) - case *SingleFetch: - first := *fetch - parent.Fetch = &ParallelFetch{ - Fetches: []Fetch{ - &first, - singleFetch, - }, - } - } - } - } - } - } - } - } - } - - p.currentNode = p.currentNode[:len(p.currentNode)-1] -} - -func (p *planningVisitor) fieldContextVariableArguments(ref int) []datasource.Argument { - // args - if p.operation.FieldHasArguments(ref) { - refs := p.operation.FieldArguments(ref) - out := make([]datasource.Argument, len(refs)) - for j, i := range refs { - argName := p.operation.ArgumentNameBytes(i) - value := p.operation.ArgumentValue(i) - if value.Kind != ast.ValueKindVariable { - continue - } - variableName := p.operation.VariableValueNameBytes(value.Ref) - name := append([]byte(".arguments."), argName...) - arg := &datasource.ContextVariableArgument{ - VariableName: variableName, - Name: make([]byte, len(name)), - } - copy(arg.Name, name) - out[j] = arg - } - return out - } - return nil -} - -func (p *planningVisitor) EnterSelectionSet(ref int) { - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.EnterSelectionSet(ref) - } -} - -func (p *planningVisitor) LeaveSelectionSet(ref int) { - if len(p.planners) != 0 { - p.planners[len(p.planners)-1].planner.LeaveSelectionSet(ref) - } -} - -func (p *planningVisitor) jsonValueType(valueType int) JSONValueType { - typeName := p.definition.ResolveTypeNameBytes(valueType) - switch { - case bytes.Equal(typeName, literal.INT): - return IntegerValueType - case bytes.Equal(typeName, literal.BOOLEAN): - return BooleanValueType - case bytes.Equal(typeName, literal.FLOAT): - return FloatValueType - default: - return StringValueType - } -} - -func (p *planningVisitor) fieldDataResolvingConfig(ref int) DataResolvingConfig { - return DataResolvingConfig{ - PathSelector: p.fieldPathSelector(ref), - Transformation: p.fieldTransformation(ref), - } -} - -func (p *planningVisitor) fieldPathSelector(ref int) (selector datasource.PathSelector) { - fieldName := p.operation.FieldNameUnsafeString(ref) - typeName := p.definition.NodeResolverTypeNameString(p.EnclosingTypeDefinition, p.Path) - mapping := p.base.Config.MappingForTypeField(typeName, fieldName) - if mapping == nil { - selector.Path = fieldName - return - } - if mapping.Disabled { - return - } - selector.Path = mapping.Path - return -} - -func (p *planningVisitor) fieldTransformation(ref int) Transformation { - definition, ok := p.FieldDefinition(ref) - if !ok { - return nil - } - transformationDirective, ok := p.definition.FieldDefinitionDirectiveByName(definition, literal.TRANSFORMATION) - if !ok { - return nil - } - modeValue, ok := p.definition.DirectiveArgumentValueByName(transformationDirective, literal.MODE) - if !ok || modeValue.Kind != ast.ValueKindEnum { - return nil - } - mode := unsafebytes.BytesToString(p.definition.EnumValueNameBytes(modeValue.Ref)) - switch mode { - case "PIPELINE": - return p.pipelineTransformation(transformationDirective) - default: - return nil - } -} - -func (p *planningVisitor) pipelineTransformation(directive int) *PipelineTransformation { - var configReader io.Reader - configFileStringValue, ok := p.definition.DirectiveArgumentValueByName(directive, literal.PIPELINE_CONFIG_FILE) - if ok && configFileStringValue.Kind == ast.ValueKindString { - reader, err := os.Open(p.definition.StringValueContentString(configFileStringValue.Ref)) - if err != nil { - return nil - } - defer reader.Close() - configReader = reader - } - configStringValue, ok := p.definition.DirectiveArgumentValueByName(directive, literal.PIPELINE_CONFIG_STRING) - if ok && configStringValue.Kind == ast.ValueKindString { - configReader = bytes.NewReader(p.definition.StringValueContentBytes(configStringValue.Ref)) - } - if configReader == nil { - return nil - } - var pipeline pipe.Pipeline - err := pipeline.FromConfig(configReader) - if err != nil { - return nil - } - return &PipelineTransformation{ - pipeline: pipeline, - } -} - -func (p *planningVisitor) countOperationDefinitionsInRootNodes() (count int) { - for i := range p.operation.RootNodes { - if p.operation.RootNodes[i].Kind == ast.NodeKindOperationDefinition { - count++ - } - } - - return count -} diff --git a/pkg/execution/planning_test.go b/pkg/execution/planning_test.go deleted file mode 100644 index 8fb1323b3..000000000 --- a/pkg/execution/planning_test.go +++ /dev/null @@ -1,4358 +0,0 @@ -package execution - -import ( - "encoding/json" - "fmt" - "reflect" - "strings" - "testing" - "time" - - "github.com/davecgh/go-spew/spew" - "github.com/go-test/deep" - log "github.com/jensneuse/abstractlogger" - "github.com/jensneuse/pipeline/pkg/pipe" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func toJSON(any interface{}) []byte { - data, _ := json.Marshal(any) - return data -} - -func stringPtr(str string) *string { - return &str -} - -func intPtr(i int) *int { - return &i -} - -func panicOnErr(err error) { - if err != nil { - panic(err) - } -} - -func runWithOperationName(definition string, operation string, operationName string, configureBase func(base *datasource.BasePlanner), want Node, skip ...bool) func(t *testing.T) { - return func(t *testing.T) { - - if len(skip) == 1 && skip[0] { - return - } - - def := unsafeparser.ParseGraphqlDocumentString(definition) - if err := asttransform.MergeDefinitionWithBaseSchema(&def); err != nil { - t.Error(err) - } - - op := unsafeparser.ParseGraphqlDocumentString(operation) - - var report operationreport.Report - normalizer := astnormalization.NewNormalizer(true, true) - normalizer.NormalizeOperation(&op, &def, &report) - if report.HasErrors() { - t.Error(report) - } - - base, err := datasource.NewBaseDataSourcePlanner([]byte(definition), datasource.PlannerConfiguration{}, log.NoopLogger) - if err != nil { - t.Fatal(err) - } - - configureBase(base) - - planner := NewPlanner(base) - got := planner.Plan(&op, &def, operationName, &report) - if report.HasErrors() { - t.Error(report) - } - - if !reflect.DeepEqual(want, got) { - fmt.Println(deep.Equal(want, got)) - assert.Equal(t, want, got) - t.Errorf("want:\n%s\ngot:\n%s\n", spew.Sdump(want), spew.Sdump(got)) - } - } -} - -func run(definition string, operation string, configureBase func(base *datasource.BasePlanner), want Node, skip ...bool) func(t *testing.T) { - return runWithOperationName(definition, operation, "", configureBase, want, skip...) -} - -func runAndReportExternalErrorWithOperationName(definition string, operation string, operationName string, configureBase func(base *datasource.BasePlanner), expectedError operationreport.ExternalError, skip ...bool) func(t *testing.T) { - return func(t *testing.T) { - - if len(skip) == 1 && skip[0] { - return - } - - def := unsafeparser.ParseGraphqlDocumentString(definition) - op := unsafeparser.ParseGraphqlDocumentString(operation) - - var report operationreport.Report - normalizer := astnormalization.NewNormalizer(true, true) - normalizer.NormalizeOperation(&op, &def, &report) - if report.HasErrors() { - t.Error(report) - } - - base, err := datasource.NewBaseDataSourcePlanner([]byte(definition), datasource.PlannerConfiguration{}, log.NoopLogger) - if err != nil { - t.Fatal(err) - } - - configureBase(base) - - planner := NewPlanner(base) - _ = planner.Plan(&op, &def, operationName, &report) - assert.Error(t, report) - require.Greater(t, len(report.ExternalErrors), 0) - assert.Equal(t, expectedError.Message, report.ExternalErrors[0].Message) - } -} - -func TestPlanner_Plan(t *testing.T) { - - t.Run("GraphQLDataSource", run(GraphQLDataSourceSchema, ` - query GraphQLQuery($code: String!) { - country(code: $code) { - code - name - aliased: native - } - } -`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "country", - DataSource: datasource.SourceConfig{ - Name: "GraphQLDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.GraphQLDataSourceConfig{ - URL: "countries.trevorblades.com/", - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("GraphQLDataSource", datasource.GraphQLDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("country"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("countries.trevorblades.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("query"), - Value: []byte("query o($code: String!){country(code: $code){code name native}}"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("POST"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("code"), - VariableName: []byte("code"), - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "country", - }, - Fields: []Field{ - { - Name: []byte("country"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "country", - }, - }, - Fields: []Field{ - { - Name: []byte("code"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "code", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("aliased"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "native", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("GraphQLDataSource mutation", run(GraphQLDataSourceSchema, ` - mutation LikePost($id: ID!) { - likePost(id: $id) { - id - likes - } - } -`, func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "mutation", - FieldName: "likePost", - DataSource: datasource.SourceConfig{ - Name: "GraphQLDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.GraphQLDataSourceConfig{ - URL: "fakebook.com/", - }) - return data - }(), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("GraphQLDataSource", datasource.GraphQLDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeMutation, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultMutationTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("likePost"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("fakebook.com/"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("query"), - Value: []byte("mutation o($id: ID!){likePost(id: $id){id likes}}"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("POST"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("id"), - VariableName: []byte("id"), - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "likePost", - }, - Fields: []Field{ - { - Name: []byte("likePost"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "likePost", - }, - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("likes"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "likes", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("HTTPJSONDataSource", run(HTTPJSONDataSourceSchema, ` - query RESTQuery($id: Int!){ - httpBinGet { - header { - Accept - Host - acceptEncoding - } - } - post(id: $id) { - id - comments { - id - } - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "JSONPlaceholderPost", - FieldName: "id", - Mapping: &datasource.MappingConfiguration{ - Path: "postId", - }, - }, - { - TypeName: "JSONPlaceholderPost", - FieldName: "comments", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "jsonplaceholder.typicode.com/comments?postId={{ .object.id }}", - }), - }, - }, - { - TypeName: "query", - FieldName: "httpBinGet", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "httpbin.org/get", - }), - }, - }, - { - TypeName: "query", - FieldName: "post", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "jsonplaceholder.typicode.com/posts/{{ .arguments.id }}", - }), - }, - }, - { - TypeName: "HttpBinGet", - FieldName: "header", - Mapping: &datasource.MappingConfiguration{ - Path: "headers", - }, - }, - { - TypeName: "Headers", - FieldName: "acceptEncoding", - Mapping: &datasource.MappingConfiguration{ - Path: "Accept-Encoding", - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("httpBinGet"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("httpbin.org/get"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"HttpBinGet"}`), - }, - }, - }, - BufferName: "httpBinGet", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("post"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("jsonplaceholder.typicode.com/posts/{{ .arguments.id }}"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"JSONPlaceholderPost"}`), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.id"), - VariableName: []byte("id"), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "post", - }, - }, - }, - Fields: []Field{ - { - Name: []byte("httpBinGet"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("header"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "headers", - }, - }, - Fields: []Field{ - { - Name: []byte("Accept"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Accept", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("Host"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Host", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("acceptEncoding"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "Accept-Encoding", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("post"), - HasResolvedData: true, - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: []byte("JSONPlaceholderPost"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("comments"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("jsonplaceholder.typicode.com/comments?postId={{ .object.id }}"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"JSONPlaceholderComment"}`), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "comments", - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "postId", - }, - }, - ValueType: IntegerValueType, - }, - }, - { - Name: []byte("comments"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("HTTPJSONDataSource withBody", run(HTTPJSONDataSourceSchema, ` - query WithBody($input: WithBodyInput) { - withBody(input: $input) - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "withBody", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "httpbin.org/anything", - Method: stringPtr("POST"), - Body: stringPtr(`{\"key\":\"{{ .arguments.input.foo }}\"}`), - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "withBody", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("withBody"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("httpbin.org/anything"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("POST"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("body"), - Value: []byte("{\\\"key\\\":\\\"{{ .arguments.input.foo }}\\\"}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.input"), - VariableName: []byte("input"), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("withBody"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - })) - t.Run("HTTPJSONDataSource withPath", run(HTTPJSONDataSourceSchema, ` - query WithPath { - withPath - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "withPath", - Mapping: &datasource.MappingConfiguration{ - Path: "subObject", - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "httpbin.org/anything", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "withPath", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("withPath"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("httpbin.org/anything"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("withPath"), - HasResolvedData: true, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "subObject", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - })) - t.Run("HTTPJSONDataSource list withoutPath", run(HTTPJSONDataSourceSchema, ` - query ListWithoutPath { - listItems { - id - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "listItems", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "httpbin.org/anything", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "listItems", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("listItems"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("httpbin.org/anything"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"ListItem"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("listItems"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - })) - t.Run("HTTPJSONDataSource list withPath", run(HTTPJSONDataSourceSchema, ` - query ListWithPath { - listWithPath { - id - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "listWithPath", - Mapping: &datasource.MappingConfiguration{ - Path: "items", - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "httpbin.org/anything", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "listWithPath", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("listWithPath"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("httpbin.org/anything"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"ListItem"}`), - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("listWithPath"), - HasResolvedData: true, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "items", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - })) - t.Run("HTTPJSONDataSource withHeaders", run(HTTPJSONDataSourceSchema, ` - query WithHeader { - withHeaders - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "withHeaders", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "httpbin.org/anything", - Headers: []datasource.HttpJsonDataSourceConfigHeader{ - { - Key: "Authorization", - Value: "123", - }, - { - Key: "Accept-Encoding", - Value: "application/json", - }, - }, - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "withHeaders", - Source: &DataSourceInvocation{ - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("withHeaders"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("url"), - Value: []byte("httpbin.org/anything"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.ListArgument{ - Name: []byte("headers"), - Arguments: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("Authorization"), - Value: []byte("123"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("Accept-Encoding"), - Value: []byte("application/json"), - }, - }, - }, - }, - }, - }, - Fields: []Field{ - { - Name: []byte("withHeaders"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - })) - t.Run("StaticDataSource", run(staticDataSourceSchema, ` - { - hello - nullableInt - foo { - bar - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "hello", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "StaticDataSource", - Config: toJSON(datasource.StaticDataSourceConfig{ - Data: "World!", - }), - }, - }, - { - TypeName: "query", - FieldName: "foo", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "StaticDataSource", - Config: toJSON(datasource.StaticDataSourceConfig{ - Data: "{\"bar\":\"baz\"}", - }), - }, - }, - { - TypeName: "query", - FieldName: "nullableInt", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "StaticDataSource", - Config: toJSON(datasource.StaticDataSourceConfig{ - Data: "null", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("StaticDataSource", datasource.StaticDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &ParallelFetch{ - Fetches: []Fetch{ - &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("World!"), - }, - }, - BufferName: "hello", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("null"), - }, - }, - BufferName: "nullableInt", - }, - &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("{\"bar\":\"baz\"}"), - }, - }, - BufferName: "foo", - }, - }, - }, - Fields: []Field{ - { - Name: []byte("hello"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - { - Name: []byte("nullableInt"), - HasResolvedData: true, - Value: &Value{ - ValueType: IntegerValueType, - }, - }, - { - Name: []byte("foo"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("bar"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "bar", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("introspection type query", run(complexSchema, ` - query TypeQuery($name: String! = "User") { - __type(name: $name) { - name - fields { - name - type { - name - } - } - } - } -`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "__type", - DataSource: datasource.SourceConfig{ - Name: "TypeDataSource", - Config: toJSON(datasource.TypeDataSourcePlannerConfig{}), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("TypeDataSource", datasource.TypeDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.name"), - VariableName: []byte("name"), - }, - }, - DataSource: &datasource.TypeDataSource{}, - }, - BufferName: "__type", - }, - Fields: []Field{ - { - Name: []byte("__type"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__type", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("fields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "fields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - })) - t.Run("graphql resolver", run(complexSchema, ` - query UserQuery($id: String!) { - user(id: $id) { - id - name - birthday - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "user", - DataSource: datasource.SourceConfig{ - Name: "GraphQLDataSource", - Config: toJSON(datasource.GraphQLDataSourceConfig{ - URL: "localhost:8001/graphql", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("GraphQLDataSource", datasource.GraphQLDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("user"), - }, - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("localhost:8001/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte("query o($id: String!){user(id: $id){id name birthday}}"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("POST"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("id"), - VariableName: []byte("id"), - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "user", - }, - Fields: []Field{ - { - Name: []byte("user"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "user", - }, - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - })) - t.Run("rest resolver", run(complexSchema, ` - query UserQuery($id: String!) { - restUser(id: $id) { - id - name - birthday - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "restUser", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "localhost:9001/user/{{ .arguments.id }}", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("restUser"), - }, - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("localhost:9001/user/{{ .arguments.id }}"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"User"}`), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.id"), - VariableName: []byte("id"), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "restUser", - }, - Fields: []Field{ - { - Name: []byte("restUser"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - - t.Run("graphql resolver with nested rest resolver", run(complexSchema, ` - query UserQuery($id: String!) { - user(id: $id) { - id - name - birthday - friends { - id - name - birthday - } - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "user", - DataSource: datasource.SourceConfig{ - Name: "GraphQLDataSource", - Config: toJSON(datasource.GraphQLDataSourceConfig{ - URL: "localhost:8001/graphql", - }), - }, - }, - { - TypeName: "User", - FieldName: "friends", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "localhost:9001/user/{{ .object.id }}/friends", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("GraphQLDataSource", datasource.GraphQLDataSourcePlannerFactoryFactory{})) - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpJsonDataSource", &datasource.HttpJsonDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: ast.DefaultQueryTypeName, - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("user"), - }, - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("localhost:8001/graphql"), - }, - &datasource.StaticVariableArgument{ - Name: literal.QUERY, - Value: []byte("query o($id: String!){user(id: $id){id name birthday}}"), - }, - &datasource.StaticVariableArgument{ - Name: literal.METHOD, - Value: []byte("POST"), - }, - &datasource.ContextVariableArgument{ - Name: []byte("id"), - VariableName: []byte("id"), - }, - }, - DataSource: &datasource.GraphQLDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "user", - }, - Fields: []Field{ - { - Name: []byte("user"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "user", - }, - }, - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: []byte("root_type_name"), - Value: []byte("User"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("root_field_name"), - Value: []byte("friends"), - }, - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("localhost:9001/user/{{ .object.id }}/friends"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("method"), - Value: []byte("GET"), - }, - &datasource.StaticVariableArgument{ - Name: []byte("__typename"), - Value: []byte(`{"defaultTypeName":"User"}`), - }, - }, - DataSource: &datasource.HttpJsonDataSource{ - Log: log.NoopLogger, - Client: datasource.DefaultHttpClient(), - }, - }, - BufferName: "friends", - }, - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("friends"), - HasResolvedData: true, - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("id"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "id", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("birthday"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "birthday", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - })) - t.Run("introspection", run(complexSchema, ` - query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } - } - - fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } - } - - fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue - } - - fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "__schema", - DataSource: datasource.SourceConfig{ - Name: "SchemaDataSource", - Config: toJSON(datasource.SchemaDataSourcePlannerConfig{}), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("SchemaDataSource", datasource.SchemaDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.SchemaDataSource{}, - }, - BufferName: "__schema", - }, - Fields: []Field{ - { - Name: []byte("__schema"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__schema", - }, - }, - Fields: []Field{ - { - Name: []byte("queryType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "queryType", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - { - Name: []byte("mutationType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "mutationType", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - { - Name: []byte("subscriptionType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "subscriptionType", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - { - Name: []byte("types"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "types", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("fields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "fields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("args"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "args", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("defaultValue"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "defaultValue", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("isDeprecated"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "isDeprecated", - }, - }, - ValueType: BooleanValueType, - }, - }, - { - Name: []byte("deprecationReason"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "deprecationReason", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("inputFields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "inputFields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("defaultValue"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "defaultValue", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("interfaces"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "interfaces", - }, - }, - Value: &Object{ - Fields: kindNameDeepFields, - }, - }, - }, - { - Name: []byte("enumValues"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "enumValues", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("isDeprecated"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "isDeprecated", - }, - }, - ValueType: BooleanValueType, - }, - }, - { - Name: []byte("deprecationReason"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "deprecationReason", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("possibleTypes"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "possibleTypes", - }, - }, - Value: &Object{ - Fields: kindNameDeepFields, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("directives"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "directives", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("locations"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "locations", - }, - }, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - { - Name: []byte("args"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "args", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("defaultValue"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "defaultValue", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - true, // TODO: move into own test and unskip (currently skipped because schemaBytes marshal doesn't return comparable result (order of objects in JSON)) - )) - - t.Run("http polling stream", run(HttpPollingStreamSchema, ` - subscription { - stream { - bar - baz - } - } -`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "subscription", - FieldName: "stream", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpPollingStreamDataSource", - Config: toJSON(datasource.HttpPollingStreamDataSourceConfiguration{ - Host: "foo.bar.baz", - URL: "/bal", - DelaySeconds: intPtr(5), - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("HttpPollingStreamDataSource", datasource.HttpPollingStreamDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeSubscription, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.HOST, - Value: []byte("foo.bar.baz"), - }, - &datasource.StaticVariableArgument{ - Name: literal.URL, - Value: []byte("/bal"), - }, - }, - DataSource: &datasource.HttpPollingStreamDataSource{ - Log: log.NoopLogger, - Delay: time.Second * 5, - }, - }, - BufferName: "stream", - }, - Fields: []Field{ - { - Name: []byte("stream"), - HasResolvedData: true, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("bar"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "bar", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("baz"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "baz", - }, - }, - ValueType: IntegerValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - })) - t.Run("list filter first N", run(ListFilterFirstNSchema, ` - query { - foos { - bar - } - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "foos", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "StaticDataSource", - Config: toJSON(datasource.StaticDataSourceConfig{ - Data: "[{\"bar\":\"baz\"},{\"bar\":\"bal\"},{\"bar\":\"bat\"}]", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("StaticDataSource", datasource.StaticDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("[{\"bar\":\"baz\"},{\"bar\":\"bal\"},{\"bar\":\"bat\"}]"), - }, - }, - BufferName: "foos", - }, - Fields: []Field{ - { - Name: []byte("foos"), - HasResolvedData: true, - Value: &List{ - Filter: &ListFilterFirstN{ - FirstN: 2, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("bar"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "bar", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("stringPipeline", run(pipelineSchema, ` - query PipelineQuery($foo: String!) { - stringPipeline(foo: $foo) - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "stringPipeline", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "PipelineDataSource", - Config: toJSON(datasource.PipelineDataSourceConfig{ - ConfigString: stringPtr(`{ - "steps": [ - { - "kind": "NOOP" - } - ] - }`), - InputJSON: `{\"foo\":\"{{ .arguments.foo }}\"}`, - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("PipelineDataSource", datasource.PipelineDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.INPUT_JSON, - Value: []byte("{\\\"foo\\\":\\\"{{ .arguments.foo }}\\\"}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.foo"), - VariableName: []byte("foo"), - }, - }, - DataSource: &datasource.PipelineDataSource{ - Log: log.NoopLogger, - Pipeline: func() pipe.Pipeline { - config := `{ - "steps": [ - { - "kind": "NOOP", - "dataSourceConfig": { - "template": "{\"result\":\"{{ .foo }}\"}" - } - } - ] - }` - var pipeline pipe.Pipeline - err := pipeline.FromConfig(strings.NewReader(config)) - if err != nil { - t.Fatal(err) - } - return pipeline - }(), - }, - }, - BufferName: "stringPipeline", - }, - Fields: []Field{ - { - Name: []byte("stringPipeline"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("filePipeline", run(pipelineSchema, ` - query PipelineQuery($foo: String!) { - filePipeline(foo: $foo) - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "filePipeline", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "PipelineDataSource", - Config: toJSON(datasource.PipelineDataSourceConfig{ - ConfigFilePath: stringPtr("./testdata/simple_pipeline.json"), - InputJSON: `{\"foo\":\"{{ .arguments.foo }}\"}`, - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("PipelineDataSource", datasource.PipelineDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - Args: []datasource.Argument{ - &datasource.StaticVariableArgument{ - Name: literal.INPUT_JSON, - Value: []byte("{\\\"foo\\\":\\\"{{ .arguments.foo }}\\\"}"), - }, - &datasource.ContextVariableArgument{ - Name: []byte(".arguments.foo"), - VariableName: []byte("foo"), - }, - }, - DataSource: &datasource.PipelineDataSource{ - Log: log.NoopLogger, - Pipeline: func() pipe.Pipeline { - config := `{ - "steps": [ - { - "kind": "NOOP" - } - ] - }` - var pipeline pipe.Pipeline - err := pipeline.FromConfig(strings.NewReader(config)) - if err != nil { - t.Fatal(err) - } - return pipeline - }(), - }, - }, - BufferName: "filePipeline", - }, - Fields: []Field{ - { - Name: []byte("filePipeline"), - HasResolvedData: true, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - )) - t.Run("unions", func(t *testing.T) { - t.Run("getApis", run(UnionsSchema, ` - query getApis { - apis { - ... on ApisResultSuccess { - apis { - name - } - } - ... on RequestResult { - status - message - } - } - }`, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "apis", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - }, - }, - } - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []Field{ - { - Name: []byte("apis"), - Value: &Object{ - Fields: []Field{ - { - Name: []byte("apis"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("ApisResultSuccess"), - }, - }, - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "apis", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("status"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("RequestResult"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "status", - }, - }, - }, - }, - { - Name: []byte("message"), - Skip: &IfNotEqual{ - Left: &datasource.ObjectVariableArgument{ - PathSelector: datasource.PathSelector{ - Path: "__typename", - }, - }, - Right: &datasource.StaticVariableArgument{ - Value: []byte("RequestResult"), - }, - }, - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "message", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - )) - }) - - t.Run("operation selection", func(t *testing.T) { - var allCountriesPlannerConfig = func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "countries", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - }, - }, - } - } - var addLanguagePlannerConfig = func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "addLanguage", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - }, - }, - } - } - var allCountriesQueryNode = &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []Field{ - { - Name: []byte("countries"), - Value: &List{ - Value: &Object{ - Fields: []Field{ - { - Name: []byte("code"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "code", - }, - }, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - var addLanguageMutationNode = &Object{ - operationType: ast.OperationTypeMutation, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fields: []Field{ - { - Name: []byte("addLanguage"), - Value: &Object{ - Fields: []Field{ - { - Name: []byte("code"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "code", - }, - }, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - ValueType: StringValueType, - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - t.Run("select single anonymous operation (case 1a in GraphQL spec)", runWithOperationName(countriesSchema, ` - { - countries { - code - name - } - }`, - "", - allCountriesPlannerConfig, - allCountriesQueryNode, - )) - - t.Run("select single named operation without name (case 1a in GraphQL spec)", runWithOperationName(countriesSchema, ` - query AllCountries { - countries { - code - name - } - }`, - "", - allCountriesPlannerConfig, - allCountriesQueryNode, - )) - - t.Run("select named operation / query with name (case 2a in GraphQL spec)", runWithOperationName(countriesSchema, ` - query AllContinents { - continents { - code - name - } - } - - query AllCountries { - countries { - code - name - } - }`, - "AllCountries", - allCountriesPlannerConfig, - allCountriesQueryNode, - )) - - t.Run("select named operation / mutation with name (case 2a in GraphQL spec)", runWithOperationName(countriesSchema, ` - query AllContinents { - continents { - code - name - } - } - - mutation AddLanguage { - addLanguage(code: "GO", name: "go") { - code - name - } - }`, - "AddLanguage", - addLanguagePlannerConfig, - addLanguageMutationNode, - )) - - t.Run("return error when multiple operations are available and operation name was not provided (case 1b in GraphQL spec)", runAndReportExternalErrorWithOperationName(countriesSchema, ` - query AllContinents { - continents { - code - name - } - } - - query AllCountries { - countries { - code - name - } - }`, - "", - allCountriesPlannerConfig, - operationreport.ErrRequiredOperationNameIsMissing(), - )) - - t.Run("return error when multiple operations are available and operation name does not match (case 2b in GraphQL spec)", runAndReportExternalErrorWithOperationName(countriesSchema, ` - query AllContinents { - continents { - code - name - } - } - - query AllCountries { - countries { - code - name - } - }`, - "NoQuery", - allCountriesPlannerConfig, - operationreport.ErrOperationWithProvidedOperationNameNotFound("NoQuery"), - )) - }) -} - -func BenchmarkPlanner_Plan(b *testing.B) { - schema := complexSchema - def := unsafeparser.ParseGraphqlDocumentString(complexSchema) - if err := asttransform.MergeDefinitionWithBaseSchema(&def); err != nil { - b.Fatal(err) - } - - op := unsafeparser.ParseGraphqlDocumentString(` - query UserQuery($id: String!) { - user(id: $id) { - id - name - friends { - id - name - birthday - pets { - __typename - nickname - ... on Dog { - name - woof - } - ... on Cat { - name - meow - } - } - } - pets { - __typename - nickname - ... on Dog { - name - woof - } - ... on Cat { - name - meow - } - } - birthday - } - }`) - - config := datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "user", - DataSource: datasource.SourceConfig{ - Name: "GraphQLDataSource", - Config: toJSON(datasource.GraphQLDataSourceConfig{ - URL: "localhost:8001/graphql", - }), - }, - }, - { - TypeName: "User", - FieldName: "friends", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: toJSON(datasource.HttpJsonDataSourceConfig{ - URL: "localhost:9001/user/{{ .object.id }}/friends", - }), - }, - }, - { - TypeName: "query", - FieldName: "user", - DataSource: datasource.SourceConfig{ - Name: "GraphQLDataSource", - Config: toJSON(datasource.GraphQLDataSourceConfig{ - URL: "localhost:8001/graphql", - }), - }, - Mapping: &datasource.MappingConfiguration{ - Path: "userPets", - }, - }, - }, - } - - base, err := datasource.NewBaseDataSourcePlanner([]byte(schema), config, log.NoopLogger) - if err != nil { - b.Fatal(err) - } - - planner := NewPlanner(base) - var report operationreport.Report - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - planner.Plan(&op, &def, "", &report) - if report.HasErrors() { - b.Fatal(report) - } - } -} - -const UnionsSchema = ` -schema { - query: Query -} -type Query { - api: ApiResult - apis: ApisResult -} -type Api { - id: String - name: String -} -type RequestResult { - message: String - status: String -} -type ApisResultSuccess { - apis: [Api!] -} -union ApisResult = ApisResultSuccess | RequestResult -union ApiResult = Api | RequestResult -scalar String -` - -const ListFilterFirstNSchema = ` -directive @ListFilterFirstN(n: Int!) on FIELD_DEFINITION - -schema { - query: Query -} - -type Query { - foos: [Foo] - @ListFilterFirstN(n: 2) - @StaticDataSource( - data: "[{\"bar\":\"baz\"},{\"bar\":\"bal\"},{\"bar\":\"bat\"}]" - ) -} - -type Foo { - bar: String -} - -` - -const HttpPollingStreamSchema = ` -schema { - subscription: Subscription -} - -type Subscription { - stream: Foo -} - -type Foo { - bar: String - baz: Int -} -` - -const GraphQLDataSourceSchema = ` -directive @GraphQLDataSource ( - host: String! - url: String! - method: HTTP_METHOD = POST - params: [Parameter] -) on FIELD_DEFINITION - -enum MAPPING_MODE { - NONE - PATH_SELECTOR -} - -enum HTTP_METHOD { - GET - POST - UPDATE - DELETE -} - -input Parameter { - name: String! - sourceKind: PARAMETER_SOURCE! - sourceName: String! - variableType: String! -} - -enum PARAMETER_SOURCE { - CONTEXT_VARIABLE - OBJECT_VARIABLE_ARGUMENT - FIELD_ARGUMENTS -} - -schema { - query: Query - mutation: Mutation -} - -type Country { - code: String - name: String - native: String - phone: String - continent: Continent - currency: String - languages: [Language] - emoji: String - emojiU: String -} - -type Continent { - code: String - name: String - countries: [Country] -} - -type Language { - code: String - name: String - native: String - rtl: Int -} - -type Query { - country(code: String!): Country -} - -type Mutation { - likePost(id: ID!): Post -} - -type Post { - id: ID! - likes: Int! -} -` - -const HTTPJSONDataSourceSchema = ` -enum HTTP_METHOD { - GET - POST - UPDATE - DELETE -} - -schema { - query: Query -} - -type Foo { - bar: String! -} - -type Headers { - Accept: String! - Host: String! - acceptEncoding: String -} - -type HttpBinGet { - header: Headers! -} - -type JSONPlaceholderPost { - userId: Int! - id: Int! - title: String! - body: String! - comments: [JSONPlaceholderComment] -} - -type JSONPlaceholderComment { - postId: Int! - id: Int! - name: String! - email: String! - body: String! -} - -"The query type, represents all of the entry points into our object graph" -type Query { - httpBinGet: HttpBinGet - post(id: Int!): JSONPlaceholderPost - withBody(input: WithBodyInput!): String! - withHeaders: String! - withPath: String! - listItems: [ListItem] - listWithPath: [ListItem] - __schema: __Schema! - __type(name: String!): __Type -} - -type ListItem { - id: String! -} - -input WithBodyInput { - foo: String! -} -` - -const staticDataSourceSchema = ` -schema { - query: Query -} - -type Foo { - bar: String! -} - -"The query type, represents all of the entry points into our object graph" -type Query { - hello: String! - nullableInt: Int - foo: Foo! -}` - -const complexSchema = ` -scalar Date - -schema { - query: Query -} - -type Query { - __type(name: String!): __Type! - @resolveType( - params: [ - { - name: "name" - sourceKind: FIELD_ARGUMENTS - sourceName: "name" - variableType: "String!" - } - ] - ) - __schema: __Schema! - user(id: String!): User - restUser(id: String!): User -} -type User { - id: String - name: String - birthday: Date - friends: [User] - pets: [Pet] -} -interface Pet { - nickname: String! -} -type Dog implements Pet { - name: String! - nickname: String! - woof: String! -} -type Cat implements Pet { - name: String! - nickname: String! - meow: String! -} -` - -const pipelineSchema = ` -directive @PipelineDataSource ( - configFilePath: String - configString: String - inputJSON: String! -) on FIELD_DEFINITION - -schema { - query: Query -} - -type Query { - stringPipeline(foo: String!): String - filePipeline(foo: String!): String -} -` - -const countriesSchema = `directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT | INTERFACE - -scalar String -scalar ID -scalar Boolean - -schema { - query: Query - mutation: Mutation -} - -enum CacheControlScope { - PUBLIC - PRIVATE -} - -type Continent { - code: ID! - name: String! - countries: [Country!]! -} - -input ContinentFilterInput { - code: StringQueryOperatorInput -} - -type Country { - code: ID! - name: String! - native: String! - phone: String! - continent: Continent! - capital: String - currency: String - languages: [Language!]! - emoji: String! - emojiU: String! - states: [State!]! -} - -input CountryFilterInput { - code: StringQueryOperatorInput - currency: StringQueryOperatorInput - continent: StringQueryOperatorInput -} - -type Language { - code: ID! - name: String - native: String - rtl: Boolean! -} - -input LanguageFilterInput { - code: StringQueryOperatorInput -} - -type Query { - continents(filter: ContinentFilterInput): [Continent!]! - continent(code: ID!): Continent - countries(filter: CountryFilterInput): [Country!]! - country(code: ID!): Country - languages(filter: LanguageFilterInput): [Language!]! - language(code: ID!): Language -} - -type Mutation { - addLanguage(code: ID!, name: String!): Language! -} - -type State { - code: String - name: String! - country: Country! -} - -input StringQueryOperatorInput { - eq: String - ne: String - in: [String] - nin: [String] - regex: String - glob: String -} - -"""The Upload scalar type represents a file upload.""" -scalar Upload` - -func introspectionQuery(schema []byte) RootNode { - return &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.SchemaDataSource{ - SchemaBytes: schema, - }, - }, - BufferName: "__schema", - }, - Fields: []Field{ - { - Name: []byte("__schema"), - HasResolvedData: true, - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "__schema", - }, - }, - Fields: []Field{ - { - Name: []byte("queryType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "queryType", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - { - Name: []byte("mutationType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "mutationType", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - { - Name: []byte("subscriptionType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "subscriptionType", - }, - }, - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - { - Name: []byte("types"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "types", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("fields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "fields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("args"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "args", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("defaultValue"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "defaultValue", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("isDeprecated"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "isDeprecated", - }, - }, - ValueType: BooleanValueType, - }, - }, - { - Name: []byte("deprecationReason"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "deprecationReason", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("inputFields"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "inputFields", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("defaultValue"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "defaultValue", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("interfaces"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "interfaces", - }, - }, - Value: &Object{ - Fields: kindNameDeepFields, - }, - }, - }, - { - Name: []byte("enumValues"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "enumValues", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("isDeprecated"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "isDeprecated", - }, - }, - ValueType: BooleanValueType, - }, - }, - { - Name: []byte("deprecationReason"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "deprecationReason", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - { - Name: []byte("possibleTypes"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "possibleTypes", - }, - }, - Value: &Object{ - Fields: kindNameDeepFields, - }, - }, - }, - }, - }, - }, - }, - { - Name: []byte("directives"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "directives", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("locations"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "locations", - }, - }, - Value: &Value{ - ValueType: StringValueType, - }, - }, - }, - { - Name: []byte("args"), - Value: &List{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "args", - }, - }, - Value: &Object{ - Fields: []Field{ - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("description"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "description", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("type"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "type", - }, - }, - Fields: kindNameDeepFields, - }, - }, - { - Name: []byte("defaultValue"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "defaultValue", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - -var kindNameDeepFields = []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("ofType"), - Value: &Object{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "ofType", - }, - }, - Fields: []Field{ - { - Name: []byte("kind"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "kind", - }, - }, - ValueType: StringValueType, - }, - }, - { - Name: []byte("name"), - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "name", - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }} diff --git a/pkg/execution/testdata/memory.wasm b/pkg/execution/testdata/memory.wasm deleted file mode 100755 index a39b9ed89cf9ae010c07175bb6ad804fc5f7ae48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1845067 zcmeFa3%q4lUFW$U=l!_%+(_ zMF=?7BI%Jg{h%Ix^@^tk>_UYQ@a zYyBjzZ1JyMH2L=!1*z&K_IvD=DpajT?T5$tF>4{bOF`S}sWAVg^cT}cGi|lfcB_#C zLDosqZrbQ2Y0}Qx{WMA2dCH$gl4VJn=4oS)H|!#5r0uMcWhsDXY2HrTR+HM@uEx@C zrxd3tEmEm5Ncvfpsj!hZvYgUJBh9kBPpy8x*YBxrm*+iI;~M0 zL-25&1Nir(&wqY1Pm`tA&ir`l*4IxZ{o{$d^Y3cE?JHZY?|SujefQz-&63_LUh(a( zy6#o4c=c<)Jx}|uc*S?V`c>caif?<>>s}2&uX@dEzWaZD)pf5SR~!-A#@BuQ|M2YR zzu>ZKUgX}NelWc!{h9Ow=}Uhu{hz<(+g|lA{`voO?Ki#bU#|YMZ~lSwt?7@Y$KRd) zaQcStPkWF2YU3Bv_vUHq_|w<s1V!{1mx!eZ6t$g+q0nx^#7tUY6}B+C_TRFzNS;q-b51HHyR!A))i4p?r!~bPB;h^te}t2;#R3ji@%1K{=Gc z)KCWX7wbdGM1pc4_9aQ4^WW^BdQqD6i(W~n#E-5u==F;wVGd5O zJv}qh8dFGX)L*P4&FEhtZHc~UcL)bF)_yS@FF{84gy`zB(T^KtmxNgl5Pa@B(|BJR zboz{bBDN3`;4~_2o2}IDQ@UlgwAC*by}WvU6}Psa*23ssbzQVzcP;%20ov42kVJ?pY`q5Ybuqx&%YPf3tt)6oo4J3=#X4 zwB@to?aqwXI)sFdURQmjMrDL^9$5*Wzs$4llgS1>PBJItA`}WL%sB;F0{<7+VOVpL#+66+Q z#CYKlvH&DPYv=+418?NV1Jh;Gnhg6@4945^zIO_A7v(%VAgwWNraDe$%5=uS{b#tu zo2;vbjbfVtY=&J(@V9>mqiF!bW^f}6P$;_ypdA6~Er9^-7$0ua5XCbu8McF0fkxdY z?^+J_%%6Hu!Z?hmT7h}^iNZ%Zf{C; zjT$X&4h=4RU798d|IPlHQxvK+z*fuQ?biLDrNNF3$ckRy20OHUs;a0ygXT@&TnrsoJCCJcv$qXwOlMhghA08chS7u4!B(`md4#a7Ybs`R&#Gvc`md{ z9DQrT>kAJvc9WSBzr~^qRm(LFkKQIOLAqqwiO^ohPm3VQm&dRtnig2nvlYGdJdFqX zfrb_*_*OfsWEsZW0kB5{E^(i+xa0FC|0j)I>1o`XOW_SvmIod9F*?nq30(3T*CMqg z%-<}P`$&bD;+&~mr>I$vW@SAlp*Ny(ass9GcwuQbd{mAxgArgaQQbJD86~q`!5%Bt z1x46M!7hpzlbO`$)jAj13l$f^H{zm!=OQ`RB^UK-T-5hry0~bm=)*-21Z!?wG%%*Z z!-&kYBpwTFRpTStEBOdEugU2~KB7MqwD?G)iF{<9Bcnot!a=u*1*AZHiAG>)o$V{d z&CipXk+8^H0v0lR0@!L=a;8PXCL~(c(k!OKinU1=vSIiKt3@*Ux9X(G@M6aH(;4SQ z20(hM)BsFN4+ZY*#hInV^pFfxGWreU(3ILm=&4BiZ)s)SdYs0xiRflObg&HX6%U-tlvPa{rI=|IU}o%2A*jEBI!J;u~)rlmc!P?KL3N z%Y+3e{+t#oKs*?DOY~B?i$3dQ{GG4#jurj8R!*lk9s#||UdhvwgF7~V9l*wjk&I|L zt{wYbl)v#A|4x;uIN8leCJceB22*XTq*!{6dcmg~bq-u;#h#CXr3kUmk zMPqf0$CH0#ykKZ;6b-lc^|%Q|`*q;-=QB~_{-Z@>%`ms{f+YNT6%yQV$G;KP*XH6L zu%UO8t9RQd?mr6MiiH=Pyzg^w{;T^xdHg3yC-td?LjbgWmtW`Zz4_F7vic0P-Xa*c zwg`oaMXJhTaPHTF9#V#U=WGWs1QMq@CV&gY!aIv>_ctgH(kw-x|Al7Ot^{FJ z3Ie2*!{Y6;$Vn6-ek3wep3`DcuJDYFnEz}Q6D<@Psd@`}lBK5Z+G0k%E4~-sgMI~HWLr)>u;3QY4ETYvL;?3 za)*DvanijK7<*h@b!hkO8*3J=@0M5;-K+RVZ&0sj?dJ7P#pu0?(L0{e2UCnrgy$K( zV~nnM#pp;qvLWCHHActrC>gys&FDkXR&5b*7Q>$;=7mAI`iaTlY>Y14H3OG-V79>J z5WV8^Gu1&mG~I${=FQr{s5X68eDl6$7=BO;Y79R*CoA*IBK}inWo~VyooLb!t<>8X z&-K;6MIwun>8CNt3C;yE(Mf)s&;{a2#cn(ie&fzdJcO$~q2oG8+l z3{#{cydD!B$OJvq8p3>vsU?Tyd&%ruD0ee(E#Izkuc6&Z6YZ_^MAQ97`2AXCDMA+{ zuz^*uWW3Qd9T8G4g2VwP+zdGR>No>hy`~f+g21p{ex-CcSB&1q-WhAmmPe!K*b*ic z;djR{^onv&Yu=^^3`>0oWx#Am(cn6(z72=IY6g8(G|^TmStz|E2%OP83Aty(&<+~tEdtg zCMr%-n;z1}Tu7(+%ph%A4ktj02>L6UPlL^A$=jV%>NRT62}hk+4-XyvCO4dqEQZ#EW%r z2Vs5lSdP%;Xhq8Znui0caFvDhMaZV8TG0fdYp`HT089|=_ zmcWKWbzs{PX_>|#(wH?o7ns~Uu`x^mF5m~Vc4ZHtEw}?$tSjFRBP7!p+s4a)mn--2 zWlVeJpw*gdyRVh-woQ1|w}d$z;8)n}Gt!fcZZu_>$8b=2j_Tow+C!3fV2X+$OTNFQ zG>DQnlyybb&a?yDb2zUOxB!_Ev0XIf-6hY+PstSQGHlJ{xUcP z1(igK87dD~Et>aa5k0ZDpGzg7B^&@zH>j|#IizrO7-s2_!Uo(oqP!jy0-O|k*!O`)a!MqOg*C}5nqygEjN2MP$PMJO@V zhK7v;%3-}3+-mJe65T#wNjwsR?f##1t7R^%o~UU`@A&Yp93PLzI&uxc<_bmRw%z|i zFyZ>xeZ)mGryb3lT6(PhCK;k}zF7Xr!c}6wslRKOijnu5Hq=ra=*YHLObW8~$r+m_)Don`*ed zX~UY$q&+pPO7k1`5M!Zp*LzL^yNL8D%a8t@=t}m)k~`x>t44CiYLPQkLAb0pncsSE z4fE?dOdVeZB)My!u@$gqtu!}jML7d$wDs({=^20_l(%L`f6f3CDXKYI%!KeWTd5f! z_W23)-5I;m+KddlwlGLKYLI_+SgVLRU0j@xF3$@J0ZLTA zdxq+89E_n>sSaxdrRWv5RON;T@*w8EVLUeP4T6^WZ*e{g^u>$PqS+BI5aiAr3A?&b17b#u}HR%C1Q+_ zu$*ASa8=NL3K6PoetKzw>cIi3D$9~7^FFRXHE_-U#+$Gnq7yqN&atON9nzFa*|!{%uvmbi6{ldi z)D)~n5M@AQ@*Ju)2U^Ef3Vk%`GxtZkd_=^YuGYHGAUx#S`$f7@x1p`h-Ia)eu z${!g0fYAeFBT+yz`Z4RnQs6dKX6Dpi`IU$WCr%HsdKFf5leh-r>1k^G;~Itt)?_v(n7mCtMgqAfD z!|tT9Rv5Rb8&)2{_ljdDxY~H;Lhp4G!ViTYtTIs|b(k3k~+zHS+kn#T9kuS(l;XM@n+hOj9X9M)1Z6! z##8IiXv8wqb>AGBOnl|n5q7~=t79!z=@$98NA%DgD;wWiW6p$mxrn3qD^4f-HxMHO z2MgSU25}e6FJMW`ie0P_Kb%Q7UZAFgB`^A`mn4b%6})t?pycg<5$>?74p-ZBr9831 z%hA6PxG+VpV1eUMb9c-N6hkCzvfv(h4`Y(FO|%Bk+;|0jI6#X9-q5CCk%snQdGIq2 z8{A!kEmNis8TSxFhyI$!oiCliXX0`#1*$U0i&#IbXnz&B#jA@NeMUypN<0EyBzLpw zVgTT=3ma~aIg8sF%)sp=o#p;a6x84y%M~-Z<>!dJNH_mm3>J2Ii`>F2H-l+z@SArs z)Uf-U??($E1ROm!-9vx+t2gAAB@m@paEpiBgAw!3Nw!;A5V77$mxo2|y!Ayo3HX3%Xb- zVLb|~$}Z3=UVqk==f_!yR;}lLASv^*RFWGp`Xf^uaKr%HjlQ6n>aUMG4I+#f2p^;E z#uEF)G<69XwjIW`#0YJAn~=)SqG&`9>rlu1K53QIU1D|)osGvLUS#o-d_m^)%NEh2 za(o-^Zlh_#H|o}97(6yue!+Vy>(F|1Ir;_n*3UyJ|8^N`=}C&XM~$u05~TYQ&7kh_ z|M-=RQmr1Jxdh028H`8!@x5P zS?;8o9Nl^Yl~Mh33Gj2DN}ijH?U{ckJseeuf8h($DAf)Ql8_f?+s2l27VA!LjWE8m zZ5NTX;aeEZilp*8cT9}qZQ3#Vm#KRo?wcsuCaB5iiy9bfJfoXblTfh$Tn>-cMvO9@ z8nHnVMA|cZxcOp=f_OTuqu?G!j2rvx8ViO?XFeR(4@mLL#JRYJctqZ-z#n)x0%{%x zyCm>aEn<>gZ@6c#I`b9%9We3OOnze}muNNI+ujUWBwmeJ^AfslphGUBQ(ej2zo2NW zG%n9y&JSC2UPS4G{=KWM$}&|7yF!L8%dW7?kLhy1U7phAGH(IF2X3Onk%Sv`erGjy zW|lHPbjho%z`#_IEw(5!Q)>K!R?%P}qpgsD?FjgM`X+_6RaC$$G2P8d2^`foR(+Ac z34IBh@-Apk*v=fglH^Jk*-9n^W$w1O1O#R7Ux`SUWtUJpL&0gxx)Q3E`Gx)8ts2Ne zRu8Ej%c>eJlrVju*0s@%RWl}aR5;D0VQ=G z6+#7p>hGY|6<*^UUS)>gZ5%{r>FpPk`)IsnnJTxQj5Su7DPRZcCtzp`2f|Dr~oaTXZe8$Mw(FuJ6+IY;5+^R=DUJ=7smz{Wnyy zhFs@?q=s|yK*G6CdbuYwCIzn}lx{3{n zuPc?WM#T!5loB&Ka$SNsv7(@_Vv$@7=6R$G8&RXGp4X^jR36@7;PJG-)u2RpU}|$M zUDDqQAV8mvJ|ljHW3$D+WX3A}vC0pkqIWFMgkN7yuEXH6Hq&P3j^A| z&^QMP_xOfa>T<5z5z9*;16S*oGO3IExk@j|i~4I%N_t5#cy8EKS}n`CL0VfHS@D&X zR;54c1Kd;%*2UQ1iiti=&iO=NzE+r~72o@{5AdrJeWs641J|LgxU)oGu0)^LM-8vJ zLZZ(v^p$qu4J6Jd`k(_@Xz3#oWC*AdeIey%osSuZ&xF#YY9MO_!(L~4uY7}ILPN%2 zK4$*DB8utZAHzbLPMfco{$M(R%Frhfxzg?)xqqLtsGF(zS?}W?RDS4l?P_8fBNcq5 zsNDUp_UWS4<#A7%nnp0mu;fa^pJrf=5DDFJE0-{{heLT*cj8^Jgsups9IH)y!orq? zv!hGP)LPhcN~JlNVpJ^9U}4)QZWAj}FnU~u$Or6zpjGdgb>5~yW;D2ui{W)EK$$a1 zNrbEW-j$Q)Zp&NS+7(tNt&X*(g(NBOYktrnW~0K}n1bmRzs?=o?3I~@g`;7EnRMJk z3RZx$qm*i*`f@~Ua*dI^SUVs9$=09)ht|%NaHK3ZmZWP94NHPofl4d!CQT)xbH~1y z5)2LdH#BU((0G+uruIQLP0|Z{&UClNv^n@@X&>;&830nnt1R#%b?92}DMT z!|Ug^Lgmqq%2U=n7nEW9qw2CiOtTdL9Y{+KH zfbIjbN3~HxhjNsbJNL*mwvhVlcmNq)1QCpC_zWmO*P4P(Ku&{IchxnFHMbmo89m{}=o7oDrL>ht>gD;|{*||9_Fdcp zub2fg2Sk)IDHjz=>o%6$TZzf0B%nwtc9B(uU6RNyx#&VO&;@5#?2?&-Ofu9&g3y0E zSn*w%uU((@GP4>D{%wZ3Eq>cc zr)wK>#38ATlT<||`{*FQQW4n)01dYsC*vEI!vqcGFfT$Sf>Nbm7_Ha6mMbw;>!%5A z)J1Y|xJ78x{30H7k;gD-i?u))YfgF6nj^qF%3)$s-AO#8*T zfU@Q0DMe{#E}%Ql2hfGNfckAoPaW+Ca{=9PK7bDA0y=z(G0IA@Ins3D`2aeY3#d>2 zJarfy&IR;>^8r*AZliwkEj)FAcIN_$y^za8n)sJw1d)pDnW^nfG-pm!^<_O)fv-Q# z5h1x-zni@i($eeqGV77b;4~)ogY7#w^uqNNTf42L8IWF%)=rG;Z7#M$P;_K-@%;`C zy)KfAmX32-9`htn?PhbWq_Rado69)7&Be`HWrt$TMXTFfJi;0j>YN2dVd;IhFq`6i zU&CJ)=NMOBjvL-U@N@xe#w6yKCeba&)(8wNi#LfS7?7*7{D?>i#ZI~Zn>5&vjV&8w z(<7~x{&nUqD3M!lkV7Pd17I>Q!d9ws5K!qw(1bra$DEMBKw_Vf)>*Ng=b7miaSKcn zI3;5hhg)a*&JLS#z3aq7OiJ19VP$9tJ-GRG^F^ro=xJp@?}p2?#%h|)F2JG67_xV$ zi2T{*c5t{AUSb9~FIs<75`a-bH$f$2cF93#5mL9XKM$Qh1yoV!1oetgD#2YnLhU zEyNUUN2)&N$d|03mU$n!+&jdo7;9~{S~2sE13le{Z?%?rUn29K47LFsXA_3z{L)Rz z5co2tfa78w$sEcsL-ABy$J`Wsrd6NBfic!$18I3(ud~@T1Ak6}q%tN#tU8K3B5RW% zBPKzVWPn1X;}ajiITWehRKR8?L?=UhST;nIi~$+*X>VGbimK9m)LBm?J)8d(gZnTR z@+0?EOr=$CQnuRB$1}3=^HM2H@gOs3mk{{K?}xvYN)gdyy)qVoeZ~?gqGCv-2qID} z60}4Rls1Ewe2E}qe8ev`Wo-)>=P7H=u$s2k90mYoL0jj8QLtPIGrcwhLa>-XY5D{T zFdrOt4J0puih6}}V6jVs1z1UOR))hvM<{Oj589|=#?&WL3>NHV2@8i+d0hFRMZkpu z%id%Muv;;heK8vegjTTO?J67nqB5#Mq1hWMF*a{SSx%EkQ#;lFv zz#J_eYz-nrgxUxZYGdJAA7>{1&(uvQ+w{j**1z#Jf6W>I7(<5R$q&l{Rm1Jfu)>lr z^RJ4u^sanjpZng#8%c&3JS#40o>lH801Ch}5aTK4PxGuc<zj1~A2WGL!Y3=g5UZ;L-HrUqiR5m!RY;fLxXQQ&g z)glRL6aUvI(8%{Q+b&8pu0hy=RI98hNHl$Ce5%Yfm~GDXQMUN!{!2-!G`6U3(($jq7FLKoJ8rLOAu)r7eJr_8^|#O zLYbeFAeAi_fh=$hUgXNQ*wx|Hc4qC$n)^cBZdZSyHU9-Be!z$V7sd>v6-FB21p-pn zxQ;V5^>54mZLB^w%@}^mL<`|`kIlLwAV{h-H3V70w1yz^^d3QQfmCTZX#;++LnVFy zuEdY%A-mpsZYm`jR}J(pRBb$O)2*b|sbWibZcP0yBV!0-1B>nxaZJc%YY3Lh7LPzr z^7Se)kS&*;R(=Vf2;>y1q5b7CmAPy*vhP>fd{X#K#YC3>-+@8RTBr14^EJ4%#-#G< zl+88%vYhV}9J#@f)2mkR#=x4Fr{JjZ7A#-EVJkow78pEbUhR#XRL{`Q=dT&Bg&k?e ziSn&>r`zifh6{_Mr7c^xZNK2cL~};&_V*z{Ziiny&)`$jg^VDNqcGXJmw33~*lH06gP%C+>m29n*{LP)}t6uWy4JE&CB@4B; zKE9#kUMpFw)%mFnb#B{G@>VOU_x^=D1W$cjKVv1&tF`!Vh($G@eOs$Y|y^X>?VmRLyE4KT@$q(RLp&ieoAwV{o~a-)M^1!e4HeqSVNI1`WX?o0> z9;at+nO*g2s9=Sw0F$!d^&1=2i5uGRknMw2*Xi6)FrmMFXdQm`7nv5*YE5oD)s0FS z%VE_}T)ex3lKaUFS?hWs`^S_#@{f z5DM8CJzZ-9pjLtlYqq%9uCAa=Cxd09_ldK{8Yd{&Q*PnhVOfcCu+@5cREv95IA&R| zL3+=7xha?Rp3p`mx6j?D-*Q=RE%R}ni>ZIykMf)sQwQ>IvY6U)z(3H%)Di2pBKush zj^M?7)1Ph2x7c|xwT%jC5I^sh!i_ro$=ejd%^wgmx$fxSh(Ej(RsYJmTBL!9yNk?? zlJRE80L_eX%3wd=k`^*7X9vQmf~@qo7Ouk&dMONNJ}Hyy%C+#L4TLOE2)h+uq=W7lMvVO?Gg@M*?TC|sJ|nrws$zZexME-u6n1z%3YKD(2q7|(oaut_59KIu6@Y0 zuH!ILJB;o5hYo9lX@ep<)E)kQS9kq**Lfj6TE{*s(6wO#oJ%!yD%yfYGHj%;E#t}V zN7vBxdgCBRbNG`S@e~!Mv8KlFIA}a4xyaUqu*O})g%DDgy5tBqPRxwtVh7H0cJ-K7 zMW`V?rtCYRo;$9vnNuNNLaJVy5%g}a;BAg7WTYS;KW&jyJejmun{W{264jPfjpLo! zAh2U>DR7}Fhuq_BY;?upUrBkTyZWpoS$Y1AHx*lN)L~0Y1)tK;`S1K}FSe-{tpw`k zqGeCV%{QsFpvTREgKKG!eCA77%!4EU5|;J=h5TF)t9F9(+m$27)>%ksD~Z4=$9Wf9 zXk7U}&2XrZMzNjO)K0S)sDUOMNcj{+64TN_XvpJug`H9 z3HGy}(>-=OLKJ$52}E~73e!eH7XqMMq~&h6M_Qi}mu(sLn+y(o@P!fm2+3C%k|k&! z-TD-X(FYt?h&QA!7ESQcVMv=Je^e~$t0tV(4r0K-HvSH-*==Jt0)Phb!jkGiov}sV z{z)-V+9%baWmm+Z6RsO^(h{$k(GVbvKEkUJM#5X+b+K4b{|n}w7U7mICbMPNY2F+1<)P?PbXvaZl}T2IP4G@gzdp|Ra( zEE)QBnXbqf+5;qsq#Fk>!@!j`4e~*d=+z^B%S)-wMB2aLheFc=FT}0uUODL;*3vs& zOJ8OT;gUqVyQMEA?y9q=Bja7-_9P-%0bu$cDnP*om!k zM$r1MW6FsPnGTWcNL?i;D9*(s{a5raNjmPp)m*iupNu=S5!B8X?z3PP zlfU`PpZ<>@{IL%g-$Zf%`SHAA+N>$xc3_`*nne%%R)MRLGiuP%xpLAztbk9~Y~u#{ zP6@q~Iu&(3IOws%K=pVUJ(MV|Zn|`uBE8G9moo@M6iVnIYLOGJwNkmKlLGm9u_iS+ zuG6FI8~yS2DZ;7UUw$9hL)uFxTo|928-}$U{aWA_g|9%CSoi1g-uZL_3hc8Q5D&Tm zH)Mtuk;X8MI<|qJU3+VzyX6EZL z@qsxY6niA#fQVbX0|Ia~FLy}xRHp&Ek4Yc7{qENH@mspK!uvTxZ6cC;+oK;QY9utI zxopRookeS*AXY_CiBMXysf(7s73(6>WhBCAZ7R#k&^lo&A46dsX>|YGiT4Qh8Mi#E zM~B7`bfzp1NnB+)x&liMKvRZiw^$W(6s`wA{cyS2uS-;*t(zgX{A5Z5{B$^42rJh_ zLjh}-{0i+F1#DG?ty<2tgU_~Ks?VIA;9)g=n zkPw4uc;DQXAF5jZ$@6HLNsIGn`S$Z@nY7l~T0T|5{ND3u znS;gDvaJ;rSIoil$*Se|okz=@N9J2D_n=i2gctYF)!V9;?>LW^@v;>AD^DV>R!dKO zAn-!UO^w)Cli8||Y*G~iJX`e>n^Yx=nXP(ild3oYvsLfhq$+23%~pNKCROplXRE$# zld3p8vsKqOsVX052Ctv@+Cmn53a`YdvsFK_Nmas)*{UDiq^b;CWJVKFA}XI<)FO*) zMh#Jw=VmrS3X&sNWF%zymayFGc%gO*%grBzJ6tE!n$ciB#mF&E_ulrd54`h7Kk@#4 zf0(S?_PhVrfB5NNIQ{O=ZnAM$dlu1o*e8HsiJ#1qfkO&C9uvr=v8A)KRrqu^l_bsfG5&QA)0lVtUu@S`ViTaafu`d^q9?Zr zFjL|I6vhQDio1lN{}ji;SuZvlij`#ALQ6Jncyb)kTncOJK+NB$r&*q|$=F*sxX*0#x>cwDj__SO_62UHr}(QpRwT9NugrL19h$l;HQ<@c*<~Wyp2rLEzrVw%GyiB;-k!daocF ztOnj!JbnkMqDN)mlI7&Sp9TEO5;%krxa8vGlnO4l0`BgOciD;#vN>hG7R2->kdq(C zJPYF>fU_v>6iMt(r;l7h;S)cj=H+I%_xp!fA#SQnvkt&0tSp8=899sSg(&Gfkk;TO z7|7V+gKEfDXZg`hgguZaM&qcWpwav?r(cnp80YQ+e-LwpsLig-k(%RWZAtp>K@En+ zMkM$6a@ohj?Gm>mzVs1pw{VNM``%h*K34X_wWq_ryD8ibsXXYr$M3e532xn|{iWN^ z6K)?2w|#E;`qHo0o_6}~gSA_75I+)bFQhWrrSA{718#{=-V|=T+>$Ewjg; z4!7!;!@qvt-||@xWhS%oR1%x35DoF854#cG)M))V;G(d%F()fyFY~fl?+6rx<>|2gbn`BxKWOeXj;6$$n87Vw;2yktjas_xe(*#Y;U9*_Ra9!g#L0{TowkEswi ztqS*luKWHdR!K&GWd;8_rJb3UGFqBj7#ahmzIi`R-$U+uFg3?&!&=wW{tFKb=tb2R zDSw&E_8MfIl^_~KMb>{epGYLdUyr-eX#7TRmlhxWff^js+~{p~|DfH|G}J>k-J(LJ z4|M`THu@pmlCguPqkpYy9o=Qw54l13orDyM5chEhw-nqJtL|25l-L7Bq&6N=H%b5B zXVo#E1ci-YO;WmGhvI-V96x-8Q9li$Vt$ZDq14a{T~GcUZQBW*E?EI0ju*?V%mQgq z{&ru(R)5(wv1`V6Sd@Hcp%f`0%^Zw=&_>E2#m6kjkT7TxJY*ktss=SlE8s1M`(avJM5OubPSt(G|!&3Zb=KM zKl-&!7(_~Pq7M?)-sp24p`WTDbjn(&OO|Sxd1WO(1QseaMaU>o#)z_}5V@E9?&B9t z4|+7zcxHx*0AB}5#UfzWF&a|#7=vgSQRa3q(JqQHF*X;?s0y2zI^ULc2tBC#oI2Gcv~hy6QsxBc&{jVnwKTE8!KRvYPN0Vln!QUH z;#gK@KdY=n0oO`h84nY*i)&>V?=%}}-i5RZ<0zF@|3p@uEK$QTpa`*HSVHvQOAMPk zu33V!U>LTlW5MuJ$HKEvt|6UMtqp^LKo^#wfU7V9&|>s?;e8i;+DPml*Xe(DN7m8Q z;{p8zl)u*54^C<*b-#1^`)vJ~>qAEO#zU|w@?!@HqgpI$2Z^t@u)^(?qF{OA>Gm}s zJa^1Vea9qSV*>AbJ_f5nUbp6+$J~uc&zfHmM3Ef3jZ{}JA9heJvQf+On=Sl7v6F4DEbMdOgr z0D|a7C5OIqW>k4U2fv_CKr_6T(3uDM;34~zD$hpRvmN2o6jmyY$Q&Z@ve0ce;{p!l z8i53_Owd7*Tk;9gA}la&8ii=mM4izWL~kQ3@qwNzpOzn%iRMZ%K;}}ru1$ya0JGtf(4GF5{)dluOaI&GE;%qNUyHY(a<`yM=q^0eG5*AiqJ3uuCl?pTq( z;ShKgkEkiN7bt0jt&j%mdu&mYqql*ueP=;50GaQA9b{f^VRnIFm9mYZqH~}v99fNwzB%&@Qn`ZiLdzqzCNtqEsdWxz)7D zHNzbJMydPII%{J2oagli(2ef6HU#1?g8dhAWpA7WeQtgI$RQRQOn{hsE5AL5e_=Ld z6fVndr*t{HjWWv=xI4jSW1MF1a7kVu`WbDi{Qh@o=e#tSXFVtZDBfQgyb}RFY9$!fS1q&!bYgGG6ZpsE-D& zg{kEDF>09WqssfZ(|a$=P6-c`+$mJ16yB2)+^d(f~-S}dvh~+_^+rtKDMFRGluIw zddQp+o~80No-(Ohl>UU;Z=~G1fqZLvN;eRf&u*iQ7!tQF*3ck`>R8C+(QL=RE&obH^2LBA; zXI}K+NeIGdr;XoO_~@)j#fK=yBg3E4W1MHrXG}=bh7{x>`~HRrPv+4T4Q0?D1UkO@ z04IaDI8KOZLY!z83$SoSgf}~92uaZ4Gk^8br(P z2^<|fX$M#q{Vcj_iN05@Q-4&+1jDjZELz&7CZ?Er?t7X28O_-E4pvJc_$V!!_zigAO|A=siPFrpQZ zgj@|YNDR3$LazKf_)Z5zw~!0t=R+zsNXzV++RNBg*($ zt?0~iGJ-~iLyR?o2P{cRD`W@E{6GYO%o9c=yOUY)1^_;Iqd5g{2^5lqlwp_QSc{r* z_Y`sg7b+0C#l9rq+;%23F1n)%#jEgy@}D*uIY!)dz%`+C1%?>g-m#xfpRa**j*FKv zML74L{yt<7j>|&mz%Pq6X&>w6!NM3?U?$AOzpzd2rAe9tq0#C?+kgZRa&lM$roqT> z(Ix*d80>0x2&YLcvO<$D0oyCe5`$?8HfsvGY8(z%Ywm`1EuPc@Q66AN6~4hYAOMf$ z5a+g={IXrid#2t|4VuKe1n?x$+h1DrCaYkk+;^=gXl_%snX2;DX(HHfc=$FGLYhH= z`)1-g`~abOW|l8HgnB6aM2W{Y_cV(k_H2? zSr?cODQ3pSy;4_py<6|iGL(?E;itn_myuUe240uwObo9W8J^5CR1Rj@n8iY80V|cT zIr;;<2Ixi_pm;^)4Nc782e$RdNuZwPxBa4jIRWGxq|$O3E;4_z^M`grE>XHlJ%gRp zC&G0MZjtv->-bf@9%6RJgfb$H!%#p2-=>45Q0lJ(YLS4~L z*BYg93>L$f0g57(cH9k@@Jtv0s-fnZC}=1n2~WGSB?}O#ZaxNW-~#*VTu>=6tI7X6 zeB&W1K~Jj_-nX0&AF7HWezWAzyw0JFPFUfG*=1qHEQPQFqfT>Zg_S87!r&>h!P?nA zo>olCLXNEL7|6XFVZ)Oj3SWiHju#_Z(879@x)}qn_blkPV zUE~A|0PnxEZKhu;Q-ReHv+UyH35zKk*#ZBTevBW*)#69Gg4cDHWLom01%Zl)ygI1( z5&FQ7buA%?0&TcrdKXX)2bJ5L)satkLcRugHkJg!k|o9CV#+))rDnxEQ_kt%nBNZu zZnFJMo+;T20j`9!8dEBWw_(j`$y05LDSdTuXB;>^1zY4-DL@R66xh;C!o9gLtRydR z5TcWd3Bpe{py@6)ms1h@ILjfErwOV^J~^71frD7{$PI59o>dS#xxpf!lKiLl`bjlZ zKOO)QqwS+6`^vCVaC)!(a}8NDDRf7VZ$a85g4=JV!B{xi+KF=m9x z72!b@csxMtPwmR&RFUl>okV}W;I7+Eau zS;!ocmtcE|mCCcghLGE&ld=+BgtzRu5EwlotTAeqVXGazjG6-~bcEETx|%594@2Y3 zG>9@<6*?dfqpib%4+ikEln~Th}<==j}f6a1U&SjAnZ$~aLaW;#KIhtHO8_RZgR9q!+kaSN7z*^jcYnJH%Z+# z;X9j_;ztzJel*)EBQ0ftA96{q5Qe0|agH2V6zNXdI(n2y$lK{P7_Zk||4CwWyG#XY_c{GzxG`kY4HgHZfkfW{o zyk}$ZIY=#dc<6C>hT$*A{XC(hHCy7AXG@^j>|4z_B|u(PyGgV2?jqkw6o5BRbAPrE z&ITw`df-CbrjbPMx7EQV_uHq2P>t^4`)OL-pGDEw$GaKx{9;yJiS3y`mr5|l7<`Xd4x_kqqp2Cf z3+WzQEZ9nn!6gNVFCU|n*6YFc`idqOY#-(QKQecMkIu8@@-X`}gXfMI`_|Yx=s(m> zYl&JL(i+0h9kVQaSoG~RiAayHu}D1B)S%wfLTrkpo(F6}Y=9x?G;p&(Rd3%oE3{P_8Xgo72=RK4kGaEhBkJJE#RhT#Ybn zj#aY42*_3_DS@7M*I@YWni?NWw3+2>-DnCvcBRYWyt)IVY)!j^yW^f$_o%|;(qzBv zrOU6}z0kNaK?eTAdyGDEi6Wa zMjW{&zl&#M8U*=V2Klh6Q8*ZW&$EV_pf}YUC;0(z>pK$h%!MNzJg1Ai|GwI%>>p*7 zXd`GVtfO2s^c6Y?81QH;Tba5Wl-dOi=^E=B)|tb!?nral%v@1zkQ3jqnb+@7>Oex1 zPf8^B@DWv^2UCc`8p5OOnIdYwL?<1ouh1n9pNTB@9~Xv;ll=k8=C49^M3(@>uv1A6Hsg_ENiA=IUxn=<_pbA*y1EJ~P$N zCV-U2D1uEW0+2cyLQuWq_s$8bSC&wD_;hrHhflK&0ls_HRtX=>BwYnBN$VKH1rjq0 zfDlT9gLpK!u@*dt8#RW~CU;?i0@XcEi*C^6+NvQH4uzz^O?~4;^Mcg3CB>n>9{DwU z%S3xyT%aAh)6@B)ro23{a7RP?;H0Doz6|6+qWly zN`ZH43OqZk`BPKC#*w(D`-B1zE|_>B?%Ze6qqcKjFKOq#va|BSU^Ze4q4*Nd0x+6+ zdJXsaY2wf4g?pnP?wQg)licdy-X}O+VIuBxbKGDC5hvc)46w>iYD=k*cU2zD}$KxP= zIeEkSI&VPb@L0sop`kp~)2yv;+`*v?w6Om$Fa7}qx$7O=ZJQ&c#Y_}#o-|gHZ$@bq z351dRe1l~sU=w$bhU274Xpn~vIMzl#5xTW~nw$4``BU4S*dGvrR+lXxqm;%^P)yx$ zBF{N2%sch(7@T6z%)z1wG3sZ{QR}~}Xll){sML+^oUG_n5hz~4#%<6npF}joAG{b3 z!$^q#08#8X97R&@o_pwY_3I&YvjF{yr*MBwIEaMW&_HV_R&2E$N;juw(L7dkj!Zhw z<5D3aREtpE52`wbbRpDy0@@Q)BM;xHIM4IyuI|E6cQn@1=kgr`7D?oDlI)Q zxaI(~vi@s-@XYgsi45~xn1E;mM0j49$dl>l7mT;M9*;fY5fds%q@dA856jQegW>eS3i#(Gnwx}dD3o$g!uk+r(h?W=`8ZA;|8ce7GIc-I9nx7bo zEXpPHgkV0Je%GY4vc7)eORZzYA{03?X^I$XY_jN#^FLc*WL$1M&* z(cEI&y-l?=GiSJO6pLzr1p(4|L!J`~YxDe2)F_5`jhm8zV#KpWirENaZ5xU3&9ST! zjUz?F3rG-;AQyqWf!InRK!c%ZIaKRCn~X$cEHYT+V1h|5L^DYRbRxYi8dy?DkaM=j z6p{gQ3dtpg16FIXcOhpQp7y(&3QjliQV6T1sBx)_Y>Ml}0X#I}G~P#_2zc?n96>|A zRPkKiH_qP3`!b?u;eF7rWPpMYUBN~zDGNIs5!(B5L`&s$UJjCR!yor+x|PVPci$c| zMQ(>nN^VCAR1PQWVEyB!i1D>6(_nl(^rqp4e|zT_`^UUak4(KOM}Ou&eflq2^O%3I zf%*UJLqGoe!>Xz`2a=P~hN_SK)#=|_sH)}x;6yJupI zDniN!#dfYGVZCuu1nX)~t4~=$UKOD*&=) zwdD)N)3bb@z2>liv5HqMU+LW(W52T@%a85vhnoYYWH3uN2ZWu?&8ZOf<+wRL@8*a} z{fd#S?&ZL0m6wxxCQZep3P5pebOzrpF=@BxM+kuUllNpt6n?VX#Eo8$Jlf0S0Wlrirj019iBjOp?olMuvmGf&-T__<+!~sQ zR=%5a78>l%v)*F}G#+jO(o8?**KO>lrG8qqe(u%q?j|yhUi3qKC0xmcj3xxA zcXF(!QH`+SPJ~f%I=Z$jO?$gNN;CPZ%zZe78k;mo0^shxUslh0!B9 z0zKa!H#h@usL$$gATPR6Bjjrn8r*Vrb7QhpjA-1J+sFbjZzl_sM#;?;hHD8GOLPjp zu{_Yov`C9CAWK1$%qR&>y42gO2Ven?4P-LV3{^7eT?KoQZk=%2pQeP^iDJj+nPWCI z)>yFY;DV>+1uG7#`I8iZ)f8uD?|V+)^YrFX1ohS1qIOL+k#oj6c}gH1Th0^i|x z_bmu5Pl@sjpsfYTE= zO9hAE8i554)4H5X%0e?m8bGoH-WN?+$jm-$NBEiK@pK9^ftk)5H8dZQvnXh`M&y`d zOHP@@ly!^*GIvSpMMW^=-7HFRcQ=CykZ3jzPqvlv!SS#Daaszv=d{bR2Q~5Wpgv!5 zxTw8wK`6~Oys+Nk(K?GDreC-)l;+`u$gApSG%>UUuPOJnoit>0TmjP)~ z52l{SySWNf-2>?_g2^r#Kh1{>K^D#=2{0@ek{|%>xeEe4?S)x2hebkHt09U7B*di% z`T|EJ>ywKYdaF~{4{YH*9~Hqo`<9>|*zDnX-gW4CLE6C3^nGEVZ4aaldy~O_0eyCYDT{pN53b?^r+ZNK3$_HYiTy1;HoeihT_?6 zX5;)uA1p!d9M!+)c+q~5+>(ucG&}ljPtE8{)A%%v-afOmSK5rxKTY!?TCDuERWP!D zRg;0y80_V0FBq|??4sgndgY?hG|sZbB1RDk%1ow^Q**s?ae_)fubc~Oi2kNyy>;GM z^Eo0hJa{-AW3I*~tft!*%;{KA$F-0hX5uJt#Auhf8ehJfQOc1lC?;bs!<6Bdtwu)& zH)G1U;${?x7XL?N?%foNaxF?MnxFAyxELJI&M|V{)5zdx7`re>V`Ne$uJc5aj}#pZ zxffEpXn!2C^K>!H^O{5}I^}Fh;s9V`0PHmY_Id!s8%X0c1bdz&1bao4eG!7l=8b|4 z;dm8efw0d&7#j#<4}u)x@hk|to+Jokf$)za2xEzjqNidkR|2N38D+#DcCYa(w8t^D z&oiKpbYT?YY#NIcBoz7jDgk%Ttt@m(!@TM?foXS2kMrS-HA`0n=*-8TqLir;U4I%`Z;_S&prH$ zr)ZBk!7?59sFl!cS#r~dspIyz+w~h4QMh}o^dk3(snXAcy6gAW>)xU}cbU6ys`NoC zz1-cR9?Nzu9q2YJsXa@{NwwiFbq{Q83n?s^Yf1jnqB@$99f;`-258#R_E8K1$UdYQ5)f$QPrLrUcTr9#Za@3sl6LU zsFFDT@rI`=iBD_2d?90-MRq{!t65Bz)iE8SRRSE|?Z2`Y-DtEQ>n2vUo{_YQCYNlX zDU1I6VyACl*^@F*Oi{AoK}_G!HRlCfnqUBBM`^N2U+fem7fpAvOe_&(nmaU3ZQdl- zrUSQMmREJPyZ)e7bI_I6r1#NKSX4Eog!i*7DOj+i59r;q)X#pP%bl%WWL*`FvsjNL zy_K`A+_$YJG$i%V@{1Cg-hEDz7UbP&1@U|AJ{X1R;Vh!go%k)40A^Wot4hdeBxT9% zRtKSvCG=8$ckcarNRH*lwwB2;cGWk%yhlu*|F2JpkqAqCN{mEUNQrfn5(8~Vik1>$ z(CTQ>dKvQ-sZwAZ)s7?3baxWB)l*>Im;!5^B?Z>=FOTgEDW$;lrH+;|Mt#NTTKooi zL3u4TMc-QNu5UCbg7dw{6xc4ZWg%a5w;)sWRm&GqayQJQcUd}+T)mqlIN#!VJsb9l z^mS8-pn6rU1>cSNVTt#2)sPOd?K*d-+SYa_*M<)Rjn05^GAQHNT}5t-jC03_G!i%v zSyCKHsdxY2Ps)@l!EF%hS!)t25VKO;RP=EmPE1-W>$iUHp?rN}={3mW?~fgY$8D=O zUL$s}>)ya(NYH@&!|8Tc+tOW+yZ(|m#RZg)-OVjK(71sR&5rVw18R%NRV9-)V@#Fh6k`9qxJv{ zG0wxYIj1G=jV+Bq##*7d$p0h22??>KqHhVYE+Lr`Vx%OrENSVWJOmPAi$G%uvA~6L zyT|}|PgNeZ_f*A%u>K~VYEx+-*nvg*%NfkEg{v*myU<{Qa#KX>(;aQMLQ-rfXN@l{`7G2>0?c9bd`w8a;_leW zCeENGriq%0GE0fe6AM>;95slxl{aXcWL?O?q6?W`UDLGVWNTT4=C_au(&2Rv`ZRJS za^r2Gv`ifZalI^CXXf5<9F+7(?S<{3v`ih9FVv;G_QD0cARQP}N8EbJA799&N9hh@ zW8=h~aN^GKE}xNGEOrS+F*{J~@XGLo!>0u@8?Qo}z>E4~hGOg>nOv3m6*%-9naZb= z#8cwmbLJ@svODq>3ou0)%Pb*WA}6pbyJE`RXO_I6S!U_U%Gy@(4wA$Pd2~)*BMg3> zW8dq8N4(B^@R0u82OkE`k*G>AD5pGc_}ic2;ct(_FLo=rv|Gs~NdI8Q=zVg@gnJut z{kiFriu6dzlNXw=!te1J4>^?iGqqz_iMn0x zgrM|RFk~UlqSZ^CZn^wjQK!dTegJM~u~qJ`dhQonWNJJ#q=zZn;-L|`x5(7UBf_%_ z-p!yG2ozReM^M7tXD~38R}jt17MYh_m^z!}&{WlUi|~a0m&YepA=MN}WoviUY^_GG z5F{AaC&vzv8?G8YO@m8^7ulT3R^lG|4gq_*YHOaWPz5Lww(iPxg4j$F>X( zYkmF1rld4A{G#EWVyha`k?33TSJ|SXXlAQMyLGUq?;iMw;)r@+|FD(NeT*7h4D8qS zB!;PFV1LV0X$@2s$>U*Oc1sOP|5PRMX?^5di(OjX4zab{n>%g(k$AiP zx?A(>^_gK{!q#Vbwn~XK-2<)Fee|}jeHy#qtS3U(v=lQJk8Npb9YuD0+p%V~Ax57- zZunQD`?dM64-C(|R)VvC;#vu$h6&f2V_&#_y3y=CM&wtAuUX90P06i@@VAgTvc)?m(7(Kk(OQONMvWI>VfqL6hn5ekc0u`SJ5w|R{Bc(8PYX}^U~N)X>X zM(Gh=@@*b5c(y^0L<;j#;kWyrx)6?^D!G&-G7a}#@Pwnj1k(tzjFM|E6=|<41DLY z$u7F%N9)xmyJtt;SLq%tg|9&KWA1MRW^&PymGsEuX+@izAw74??#HEV}b=k+o{MHqY1Z`cxxS07kpD8d%?At4RH{V%v=* zr6c-*TE;w>jgXMFyH*(r{;<1cXWdHGN$74lT+HuP!!qv%y1pfZj z$d9$m?fj7NAotT2IP(8K%Zm`sX%pP)UPycafObEU1?2ds=wXY0%kJ+`gfJM2<>cG=&J?6}+2Sh+3w|I5zZ z2ZS?J!0%P5?AwgMm%97wh(n2#J_^iY8@Ulkgx%)4b@T#OlqFcjJ~&i#mF!xSO$U{7xTGM~pbSN>Wj)@t&=fvgYqpn5K z@kosiX&m*c#``PV2u7sSq_SSFZJ4?Nwhdj#E8~nsn{zysj!ne#y$#&s6!S~Ef$Y=2WllPd&0P_cbrmYD}JSNMM-y{vQ zTj^o@BX7o@<1y(u9@Erw^O&px9+N8IG0jwnJ>W5^LSsV(-v^KIn8Lf!V``tl$C0rx zAE&bTe6Pj-OMU9Jf_kjDhcMle7 z?!kh&2Ugd+2cep|2MgvNU?AikX#Iz|2MgXkuy>++U~dKY00_)IunMJnpc?%Zrnhez zk0O>cRtFV)N`6U>XpBL%5HaLpUt}^c!snZ8y%AHxqbdnYgzb~C+hlUKBRVNw1or8* z%(R&o!I~(^@oUyFSZ4G)Az`uIpPNDAQVV5*d1%W#P+jH$UwXQ+~2~{93}>R zd+RL3*Y4H!UGhV_#pvZj=J<=zQM+PXZ~^mF5_<7NdJ_-$_gja2IqAt@gLYAKF0f~D7L zV8y(_HlH^@tLckIW%eMMhPR}g;N7O|fg;ImRrY|dpskLv;yf)?*%l9fq=Ghhi`T~& z;KOzE12(QMl6S$)I>P`L%cnPb_z>tyNO25T(zwG&%pzQK>Eyofv2i-IQ&zPeu={dC zKz@$e72_C{G~&u=)I;?K8im?;zL7>fpVCquWdlB#1h&-@Q}jC%KFovJ6dz1Z+#{Bo z@P$P&Hh#b=j@_;Gir6q*gJ8;xIGC{w1T!X_CZgt3 z>@y(Yc(wT1%>EL#ixit9)b{6D^na+!iP7P^N~g#M=Df(MuIKMEaOA>a1p!9Io5>=`iIcEI`oUl{tnxc#~GEFErqSf0BQhu z0!U*q7bVuiMhi}{zceO2cu zDf^tqH0b(*DYd~6`&s=Es!r@1 z4ZkFXtEf(A2=HIohP(X}k`5GP%xT5asnox5%sY7PaaFCPQV3 zd1~fKgED$9G#Y8rVtXuYFHa28OLP{Q4!!q8_JuYWqtbo^Ndp1yh6@9M0E+?E(d`1A(#+TXVvp&gj%Zi1+#fXOwSa#SA#}p9thtZG4O^jfJXW zH7GqDpH|(vwEufq1xoGkpbTF0fBnp69!?E{JV26%Q-khuX;iZ&ZN^N<4dRs_z#7M6 zgU)tpkZW8&;S2^;zgx$KHr$tSWKgZIc_#)v*{(Jo7sNJ&>bRi#&D7Vu+fai^n!f)X z=!?Xup-KNVMt>)z(|;P3q!R}G=!|fFI6+D(RQ9Pq(BqV^negew&`{Oj4(lMaiujZt zBma@KI<`o5uMt=PgW?acL;D!-_=Dx>kUX^xoaG8=^s(BH3Oc*f(X%>h?h*03>|7(B z%ErNG-0YX;vn!ppc7buY`&8*>U}c7OyJCkc~wN56B&;VU*HrL!qHhJ`~}FeejM2I(O= zNL04oXB`Aq&zdU+<0gvIX)zW|NWPL)aLRjX4F{g}?gGQBV=c+{uzG}p{Ewu^tAs&r?MdNS^s-VMOxx|P6d!B7P}i~r6BJh-U?&%VYw@cKAn9r*UyfbZy>Lhy)g zc4r12C21%o2ZxpKTr=tKW`R-zc+ke2ri0^B47Fqn{OU9So@52Sj1-elUkpe0N~@`a z_ln^fbvbE?lfnlpY{Z7rBuO-#yu$0xN)l!nZYmZ|@IpN$H}w~;fLeE zk5Qo2I1dB~`sMr(u$1K{TUQi`_#cDGr&MxeM|^HPo;Z1d;gy6SGoh!wcR6seHq zjVyo+Y$rBsWe1>Nmz*F(#y8Lzpbah68H7o2N?6{J}+2YXrOjUy|^(GKHalePYC5VJ52amHrjXloprQ)e9QCov9*n2z_+(JW+Ni}p3U z*T!9AqaL#sY&qorfrQ~vlSl+Gnqjy8yOL2TQI=3uI5y79A>|bF!AXL%@0Ytaw0m!c ziTtKeF_HAQ_@!c^<<+9^%Lp_E{z@Ms_E(&89N3N%QF^|N=+zQz`mVek(B=7W0lkmi zmTHMBoHq_+!(cy-&h#G~3a27g1cz|`bVSI+cYd$OgPUY-oyBvhJN5fQk?tansM5Ng zEF4w-sI8L}5_iIXcN*zpH2?BAAc0{quclY?CV$cbp~Dk_78F0_t&>Pan-8( z!6*9HK=s7E=MSNXd%F9q{k|`CZ~xCKct<|^kd*2euUu|j;vUuT+{NzK{-b{1o4LD^D6P*Mp$IfB|^SR}uP&oRMPdmLaQ&zY78gU++2XoC+)@Q#{U3(Rv zQw16p6hFH6M*A(k3C6;Q;4FEU`fmr&T^Z<00)#g)ha4RI$ufR_Z#!)T$Dm-1I`uTG z$3Gn7&nXyi*7qVf{2=z`Y1%|nWbJ|_F~&A6x8pjugRGYAY%d?T-20>fR7Hn)bsV29 zM;|QYM2`Z;w7&c<9Smxp8Nu7I75dW50P~!rdP-+4Ybl(|Om=Ux1_<=$H(>g5Y?)w! zj+4ODavZ7SG22>LNI2cI{FB0-9rrLBT~9LoXq&q_ew-Smo@o>8Nk09YlB9!4`EVQu zcT(23VQ#E@ilaGY|HG@lg8QX&MZUxhYoRH0cq}}s*a9&3v)f(eO}gFYz*Wc(&kZmK;{mKBZ?Pkacqz z9B#@){!fk9r#ZWSed}5Z`D=A0 z5H`G7=%4js!j1;;2p z;mDlw34Q-v>>JjK958iYJ3e!Q%5IL)TdGhb`k6V=oxr+(+n|YsRYb@nVlX<7GF8(E zR>vPXiebiRpzXv{P%eghX|@$Ycy>&R68 z_8Z*&Z=i^iRS8q@NOL<_+cmsRY`foigMyn-eT8^b+aqt$3VQrWj3U37s!2~1420Rs z38(h(0V5n(_XPrzP|k+PM<^;YOiP0fBo$75NyUuF)^IC>&Now;h|8NYAzgNkiG=wpFaX+joyYnz5jW z4Hjco)KQjRbJz|hA2@ySC<>vw&M6KHvwXG-Dt!%UAh%tEU+>5?8q)dq0ZTk;m#f1o zS##^_e4w3w>1Wa(-6UNSo08%K5jam8g)+dlv9;a?Zqf;RrSZ&k0F2b_Sh!8qcXU=+ zYvv1YrBue1vx~JHw#YQ4)ps}W?MNaoZPaUAnvC4D4*Kvh)?@rBCjp7YY0%IKk;OKK zVFXL3`rDH`g>YQ0+x7c5o(Lxc5pLsGL5T=tZ{vAimVH2XG_f`za=Duiy3+}XdE5o+ zB+pIn(Q^W(HLHDZ$9NhGQgs)abdSx_+&7?ZL9*{auqar%Tfcq;AMkyWan^Y{>S;po z|6;DI{(%orL+3jCMUdHeXv@X}{?_=SIWsjcWJebet9sRfaH2jVPBdy^@=iaVZoiIP zDC7^tRx5_R(3>)5#@^*n2fQh+G^E=j6Asa3&|#;NP~yJI-L4F7oJxb@>zy*di_>NI zsA{a@K4vfOb)Tu1{=e*f30zcF`~RJLXJBAhW)uVjb;J$a7!YJ}16MQ`az#aD8w6#O zMR8>`O-oBOOI%8_QYtNaEAuT&EK@2|%2F#$DlJ>3va($Gf1h)gxr10*Z@u;Vzn9Nt z&iA?Jp7nX2bIxjnX53|<=u`y?}Qe-uUF$WSOO;XWl15>wnjgGoTKa|`!*_Fm7%+1kPjhvao zQ6`v}NBCN?caF*j4dx))Jl_eei?g`35q!`ABu?gQ4(MSsd9I*C?b7^=1#v*t(RmA~ zB1)LV6X>_0G+-gpARsLbYe*T$XAH-=WlLZDLR-P2WAAWac?{=)4hM|F$RO)4vgQRZ zLxGce!P$RUj|mk)3oUhQEeAGcKv$5}m=0?YkVtC(ba7b2NsrJEqGQd-%uh}jQK=y{ z<0u?-I7N+$w9?0%$O`ll*7XL$EGs?1w$f-6cn#7-;o!Izfqq~tosAVrWUE4G=rcj6 zsZ&Z_SAka8L9BQxYxEGLF{!GP;I3us>QHYE6-+gwF)LJPIu{lu1rdN~C^%`3RE$GR zGWCP;%_x0CDECs)37`T&sxVW>>WYqwU`I1EDzA)A&4OX0>$P1Knm76Xv#TQaRLs}* zRLs;6j!B-5`@%BJ(Tuvq8%`kpip>H|HRN_|HRd?f8y%cKM{q^73rb=38l=L z^-mB3tby1@3*|#yhd7gQ87VN9Z*&z9H|te6dRZcOD2V&XawC4uPs=Hl{zQ9r)Eo=P zIj$KkjKR+I@ZF8mQzwFTT#yW@yKzl7!i;JVr)}F)w@T?mU{;6POFHRB>O#=$4oV5< zsZa+3#mC-bjdE`Qyv(`}vG(4B)OruZQ%snPoridmNfr>rAOl zZfa3trAT}7y;&@nkf#p{C~#Qi(O*ETPp?vpNDsOT@ucMB;3x=6H)j3OPr!nWL9hz2 zZbH2B9%UNQ$eBjYDAQ3`p9Y1=4zV)*{$?AI$4RZWoY$t?Y+@tYOiyaF8C12|W+c(x zJE4k^%BxX%QV8H_JV&l5a;Xt&Pi1lvtjL-_)<};H?y)Y;FxjO#?Zz9P|Fe=O_6qH8k^q9M_9O>x^Ly>ROM-*)v6tjlD>xD02N9 z_8kuyj}aTjsAeazjiVj?oZ>#=s1q*4Q8H+lgaH}R5x5ew)Ab`@O(p!g(oUTYfxsH$ zm|WsU$p>0Onko|44We%g31zhdo)>*!6Ll;~ln%@Rm%^u1_*z2|to_o^*}kLzAuy8+ zwZqgNYM_N^xgW|D|7b>8KnqGFbkk_AOD4e#P7mpmCH2|@loAhCkRs&_>zvqrD5yq! zVaUaGiKBCxsOjZUgcwrNI!pwio6(ki3r~hAEPA5nupe}j)D&{8MXw5KmL~?_#2q6L zo>{;+5~CXd^K51f^}bXm;8DK<`LUmXXGSL<^CvU0E{r%_WG+?z5Ymsyfrm(cLK#x` z0F13et{WY!$jrVp1xUGoEs@5D(4aT*Hj2ZEbrg{o^fb({WVp1I2HtUqnvTiC^m5!a z$K;8980sxiap7&80LS`aEUzdAb|^3Vn3JU+|6roK#-u`rj!1%ZYM^A6Sp_ z&AM{f;F?ugTTVbakv#e?gLp>HDQ3s8c1P8vL!*KYohlZGD&$ybA_F+ais^tq5G&%; z7?Rk05t2!hZ0z7jJ{5m*fzW{oTEk_neK}*J(GVNT zP$Qs<4ouusSYn*=un22!P@n8nDK<2Mg;^YSh`IqQp27a4CGaV;o+_a6pIK)gi!i~X zRZ|$R?87224xc$_Fdzo|qB?xzo}tB2SPn%9-F!KBwB2-EESY4gIfxt<8CTO%Bl0BI zJ%$cuP$=`oDLP}O2H zgpkE7@HBQ25f5XkefWgYD!!DXuikKs2ZlT-A`G7}VGu`)+}QBR1x8vJ43G>eKy2s7 zG)SBinQ>h3Ndq(+^);y!Xq_Ll57bkmVi@Gk%-V7x#UZEioE$QzlRFyF3)DB!B-n)5nski^JxEmF~oZ4f%3N`pfrG8N#T(gv|5PiTXPgXtY{eH(Jc+uIM6)P3kOmgI-vOCE-;3>$kybM&p-})OJG3E`Af^M-g4pH?6aL{Jq59W zqcUOKj1{lGae;{Tn)wa(Si{7JdM`*SG?o(z4#AWCfPHibzNNY%wc<)I@BnmTqqyxh z!&qyCAvWH_flFeK-WeakV-6Yw3>UEWg^o)#(1DFe5*%c(HArXf(w4b&-lDkoBZV%9 zhVOmEGj|c1bmlH41EH}qcg3T6v3v>vibph3P;}<55|oD=6xJVz31eGR;xi2?L~s@b zgZJ!b?iy$hC{lgWnY%2xZQWQ9Bq35MNM+$h^Fao2KFG~sJ_si?P}**AKFEUxXP6K2 zVDmxJT#%bG7vv_+1<@I$SX*=LB#| zEqJP?s%WOl2@_794)Z{mk78v+b5c4Q_&7ese3bYYb5c4=Dz9g2qSyXC2xkMitKlPWYH1?T5l!jZ!EK}6MqZuBu z3DU`c&f;>RYxn{tE)`$!taeoOj&5?}dIz`2s)zA|95Jb7!L9?@gsmCx+uI5cyou;E zl7@SeN0-FDnu8bhn_Txy%BbNNEe>#D0~gH7vNnTjE47twW{#C5*qfCjkII9~h81Hh zGAJuNN6SOsKXJ5VNG4#@SP-zx$a5A}FTe+8ny@$snIO9C%afsIv!RK|OXEPqP!Wji z-yP#`4i(KtHq^QyyNwkz2I%mBSSU^nydzKQIK`A9scmLqY{62-wNuzmO$9s7rn87hQBV=n zxjKunb^*;Ekg}8!1D;<$Kox1UkH$InB@EUw#c99=>||HNWnSZ4iehkP6;7*bSVlEi zs)a^2&UO_;YCSBq$bc&_nwYjo6S6|)WHdysGzilK!tIWv(ts=wBNozW_@N_K-0>bw zbh(-JG^tP1@>rQki*9LwCM^o3)u1#sqw*n}6gw>%16_oLcjYminXR}(GMw4k&c>mV z$hs@#qF(yxM0sNSZGv}Mr>HH$qzofMHu_{u5BsPrkQWz!1iI6@2~6`s2cV*{=8yIq za);d#rBTE-qbXot${^p+M@TbF-t-D=Ml{Wfy)IaKX~5C+5xwMZmf@s^*+SS-GIaKl zK5(T5KQMW+wMJ5z#&v=IU9v2Eo6FDQD$*!_q4p6ZlTt+w4Pzn(dntt*0iXw9wB%$-8yYXVP0;x z(C(J*;o$(3TxMk!be%xNk4DQQ_nb9=|c zq~#S@V`6er(hBklV`B1Ca4kG2*TXBWl96z9$ z6q)<X3A`Q1N@X*gs^j`7iAVcjCaHFZb(6KVNqI0534mb zDm^?SEF(3=YDrBEO^b+%Ot)B4BT`bWDH+i{qS8~sBQrz}&dy4u8V?bxI3y=8UF7IG zggF#p`rvlQ-CHo?KgXq*2WA!KXQ#|HXXWIJTqh>Bz*$?bKDNe z?+f@fz;AkSK8h!$$SQ{h+6g=};a3iiQZLH`(TT6rwC2EGxT)^x_Qu@;H|1Zv>idbm z?PJB?iQ;eUYVmi)E8_2ri|p67w0j(ftF~Dh`(1i`J^Qu3`6m6Er&aL%@q2D|d?fvD zUDq-Pzp-aGTejl2to8mq$M758@rRji12|h<lzcI8 z4Ik9C^Gfre2qEmb3p>XS;+I}MGwZ!O1}$#ZCgihD)q~m||MZu-&ty`!g-0eHIBy#IK+=Hv=VlHbdZ5SHuO4w)Ff^&+nWsA~eQIc7&4U%8 zXU`5@9rL<=(NzCo8`BrP>fwLuu<9$PX1|@XY?x)?yK_ z@JJ>HBY)kbM8QBNqOAOU`a>?t>>oh7bJy z_nXB7w|e)zfH=fbF{5d{}lf3iO{cf^oO z(H<{c**d~+Ud>y08b`UbC|Q$UX;89ecj}oRMzP_pZwNWyi?v z15W+4IN;-vYu3F}y!D|Lqn`cu(B>@wh5&noj&NWeq6$|OZB&&zkFwc|NTAh@&2$nA$6ek;zsWu66TN7?b1x{ zd~43QS4LAn!PXa4MPiV^ucetzjU{M_~_^-p3f-= z%o=@gVz7(n%q^o^o%px)^Q}imw;vg__o0>gF*{Sfdt%iSeaE;hoba_zx56=_l6Ib( za&h~Zw5Ly`7XNr^OzZrEQ(T^JHnzj?=x0}E4jJ2h%kr&H^j|o3;VbJp>>T>9u}K$x z&hDa+v=Nq^8D!A$GzUV9SdJipHO%1{_~z!HcVLc)XP5v_pP09eoBwRXGUlfXGU;kZBwEXU+vFb$oh9) z;tRpHsE?06l-N1E;=ubgClVv#;!8}IJSOf7>h|RqNdqQ+TX6A_4&fyecdnl884~xz z#6y0MWxaUrErj~TXk-{d~#UFVX7A19Bf{3I}Z zX_q9+(8Kpugry`c_#p0u_|kimCXa6RMa$E#C(SLqQ=hyqp?kz#&8JP?b7t<6{P<}FUrzCTXw{-=ot}<4f7a*eY2QwB znR)uuXVboZ?u|hc-ffk9Vf2=j;~yEF{8Xpq-FJ*!4(SMrnGpD5GQWP}(%BK;CBJex zufsbpcTBl(>5cAp6egvVEbRAUM9rF%V@a#K4v0CB;uik&Pe*Gmr7Y)a=PjKQn))cW zbi>(atf}vCXB%1vZc1HhK0j^D54EX}ockiOGEA3tWb4^Mqf2Ab_APsI<~^(P)54~2 z8eH=9!)aGz`zMaCdoOKEX7EoDU5)7nUjDvlK;*#mlBX@By#~!qA78g8W8!^JruTH~ zS@+Y6pQI01J>W#~PG756;n5$v3=Y9_Lw)*Y1rj#t2^irE|tbGit zFCIG@nBjK#U%L*in2@o0@w77yGw#axx$1>)PN%+{5q1BJFVhaR zVeOv0`$Ed}J6e4;>0h(%oBn0{?ccWcI5fTa9Q}l&D>RwM*S+3V|7Ap`d(4%{*R3-% z;|E?%eW1;QnUmgq@zS#C?`A$VZ0Ee``&_f09Jymh-R{_|NvX$=`+ioG^=-_X?x)R< zWgQz>k-2hgU6$MUn*L8@dCgcobKX(Er9)>FI!%l>pDmrCe>k#R`1z-2xZbraO7rEp z8N=(h-M+6wo0*pJK^MyBjG6hu%&^eXaVus%=2Uv+!x=Bl?3|uA^$q^}nGt;qJr}*w zDSL_A-LFh}W=i&32ctGVU$!>;z|RL_KMy~c9l85rSv&qpcDuq&G2`2Y<$O7+|7(vw znvwJACu?75F?MrK{^4E`cR%x1j@!$3zWh{Mr`**A-FmcstXJ-a>6cHB9yTktbn&J2 zpKX35_jJlH3)^Zx$nCmt&o}EnHs;OVJhO9*|De2ew>dqlPo0<7r&;@1gBDih9cq#D z=6##b8 z>rmNl)_AYD(2%u>vt~|QbLIJ6chCCd_`DCp!(N$n@-Dv?FJJv>)|hX%Y$~|gt>B#> z2R!J!H?`o73+wK9Eq8svhPV|-e~r!z7>hB$BdmFGP35Iv(xXG{X)vT8K?K{o$bAF)z&WWeLs8B=8%=Mj|9!h zzwJ`DvBI=D9m8JS?3H@YoT^1%y|N*uW=_%rpM}Q`y*lUTmyK;}z78wd{r%YBm`A6V zJYsq5=@s|fUow5_u>6PxZ6eJ~eB5Z7JI} zcf`Cot_Qz8Qwu3%xIsb$8F%e%LNtpk3pF8+Zg=O;x-__-|(*vKMKRoKvQ-+!K^QSq@d*JZ0 z_6vSo?mM{u_K6FA8GB^r9s05bQJr5o@VM*#1qUw_?jG;{^MZ@tmSyZn2wB)`eaq^Z zYtt6G_Gw$?G^c#w@KwP{HR}#9toms~^pyZ%(dJ@qMej3_i-dc)$8I^5v*_c=vBO3^ zwsq0_1+@X6j6J@nY_;}`e`oj7=ighBduvSp(%`aoub-`%UD~5)NAEWCca&Dte7WrV zLm!p;q9Y~u-~8ZiiQ6Cde}0^Tah%jozUXe`CL)d}H5^BMNEv(bj<^$W2RzsO#$_J` z!t+gDNW$O#qAk^K=HloZ2%VF&-bH%L)!^pt;d%Wae(U-5-~3CS{P9sZ$5k2~$KjUH zupZ$NJtL!{Q&Q8?tr^AAm0FZroKYYn`>$wi_OW!(Y`a@&YKQfGlu^=Qr zrHJf5;yAifGb1+)xqlOiiN=>|+*XC(Z}glnJ*S&4l5H9vUu$$Iv}R{?&nlb-!&1St z)V$){^pt|RLAlmB(_kJ5{&kBE$6Y}B)Ha<0Yg%zZAsIEYvvRVEFzimVTGOrR_Q5>N zS?T7y40EQn#B42u<;Yr80Q(0G<|zp&81NUM7-UjjPEJa8Ual1*`IL0>R9FnF*mN4L zXXUB_nQ5JC&Vl{HoN9$#3IV`xT3&8ZL0+~!Tys!Tu?1H*`UxEzY|fzkn&)J~{$kEg zLBbJ%{I+aDD253O);4BxGw0{Qnv`3dlM1U>UU3m+q#z}Cx>fcpK9Z4`KgIMQrb>a# zY^0#9bh7hF77ugse3+OD%*m6J?WC?EY2me`DJoJ-@}N4{AI8n*?DO*A>uHTn^Ur>2RIj;4nZnREy%+I zbADDni0K8^!a{Ry9^`8_bRZe~Wg_%laiNtSL9yjB%c$faeVdY+SAfK-C6+F3c#-ruh=sj$vNUOA9GTnKNy+H4QDEJdt3|n{6!s|IQiiXJj^1 z7YG>5Ls+hDz>tCLq7-xAK4yy)DzivKNJG-I=1yZ$z#7x72rB?#4988per-@UYJi8l zAS~kfEBK|ny0jF_Lylvl6bF?N$#OdGbI60S6USBDuHj<)dvdn>$~o?%A9UR78+)O9 z&)WAI{MJIS%?KdYUEpj>(YkgE)o?F=Y2emH%;C6wdEedM4!$^U@%bIgCdcJ;`-Tcy zx-@NO>`nhVD);O4+uy&y?2a_5alABr@9plg;k0li%G)#KOi{b9emHVee^R^u{i-+j z_?7n9CUk7``AAC8Z(N!M-ODF0Kl)O^miJC95AkkxAmPKA`MJZ6c%HcT-P~FK>R6R= zU}yWD-mNAb?cdvDY(rXg;kZLS=YO_-7qn;GPX|xhPJW$x;qdvB(|#JG;~LjoMs`tH zx-~5X`VLL~^tmDF1u4_>s8e)pt)+L*fsQx#HA6Wh`5U>;NcSw<#4kPar5g*Uus9Xr z}%V0uHG^0{*=p?8Gd8sH|^#GZvJBaWo-k+moug$cFoX3PuzFejo}H0 zcTJhwtoM?qE_*Q?IsVd!p6iS+zi~N$;Zf!BQF&k7SN7@U_6#44S<>N+WktuiD_t4B zuzv6QH;>$2;eREZ;j=qB`;@zepO3iGo8i0v718<9^r(L&Tp7r4uYL#KKK)M3(wSF= zGyMFUM_YCpccaNfJ3e^+N;<c)I|ZhxIc}-Tx{D>z{T8=otqR9I?d|;9{KM<3qqz3WcYe|r^ACqD zT0MsA%5bLb^T!{Kdi&iR)=F~Rpumkj9XpNMvV!Z)o_D&m|DDjSX#WF7P{_?=PjNn+}@~W$=d>K0T)G{O>2VC|}IK!*GnH&H9tiR(!mPKgsZYPk)j$=B@WC zckyQ!?mck(!|yHFbg7pAieclxhqn(OKKq3)`3nrU+#I{>{N0bQbP_Hz+;!=MZN~F$ zYRv*^D2@vbUGw?bhmD(h;qwr}_q%O=@X{vZXX6Af@%e>bsqdMCcH|2I3@@yQu7sO(w~QZc zgdb~!A8&-ICe`onlyH;nEVasA%wh{@?rjbVHTUjq?iotylH-4(QFyM%Db26bMRt&! z{32RulAbji<70E`T-FW8Gx>dY_;*p^XbE4Np0?B&q7|kf=TbAQgmDz_{91diPP!cL zJJLHcezy^Bf<aLw@cDtWM`}316>H<%JYu+l%&<^$3gFNEvT{o5GjzmPXGXZ1lX% zb@PZ~nQWPY?oetcOD82fv*h2>y?eJVS-BY_Q$}7}qz>JSoRkuDHRSXhLjEYd-7zQ( z?_lHrxjwk*LeN}a+*!HlumMR{6lQrUj4@+4MvFGgS%qeED#lZUMUS9xTmr(v50{T$ zT7z*D<3Dv#=dmF;L}f3+A^BK{MA0vn)^JPFr>Ew|K|+494#ynTQM8lv#cv?uH{+Lj?^zf?5Pz~TrNSsI zN+~ERBpVDXCD_y$;B0t@)}7pkUn+k&j669Eaooj5Na$NT7#sKF9h&pdAu=ip8Amk2 zJtgdrUxX#{>~Bm^{OOO8@IQFTTXQx2D>S;abg5#T+`W7EDa>>u)jRmsfyb%Fle+|o zr&9|2srY=0nqE%~FvpI+|QHc1|>8(N79TCPi_(gEs zkNBl^Z;j*fmg2IMz}y;Y3A6ODgj*skJuQ)zC`)vxB{VcNEVM^xcxXgu&(O%wsL<#z zOIT=FSXhs+@UV!mo?($;QDMx~HXQXwR^oJ$i=sjOf|3XJpT)p3#w( z$k52J$R3g5kr9zSBO@cDBBP@$QK3;`Q9YuKv=O5)C(>|{Mg}`LQ>D_qv%=0fCc>VB^GiN!iy9aw3(`(S+p~I%8TbHicbpLCI zkGPwH2MwK&ZoO;GqwxIdYp2hgt=GDn1`SQO+7>VU*PfU5zI(j>+uN3{e0bYSdtW_x z_{jSo#FxML=7GaUhK?LHVdB(jcig@Dsa?v!^Gge#)@=q4896F(Qqt5#rO&?l&bue;zx|=0aCK4fed|M}b?hFp z{mJL{9z1gV^v2lr<(AcLs`njk7&&UvWM{pnu~W!5=X3KS`}FHSsBF#EhB4ENYhJ5; z>%@DXU2VYPzQ84?wMz!-{k2Y}#XCG~k4Lojw$%xKdW|+j8?JR0G|o=WCf5YdX3pdE zyf(nqMbHb*0uRmPrqu}sCyj@3+(kFowX4=ms}VvCU9~Np41#S3 z9<_-ZuI(li>3a*FLT~3NeHY!529vKo#MDhN8{2x?R%w^4_cM5}Sf>lo^>XGtd|hl+ zmLfOXv6gN+TZ7KFOV{3Q(*f7FEyksH36U;~le}!Z^|phS2(7DAlzy<@&8f)HT9~Ar z=wiFgH^8-pOT6B8r_zau`O(Agd_EzU8P1a)>AuC?8zwY?DEa}yPoq8sC@LqdoGb>Ybu>xd-cu8TD>-J+BfGXrEc8RDQMjN6%Ri2 z@b=1`&+pmqWN`Ct71M9ft=qOAdb7gWuVr9|zWrW3pf$Ja&@re-R80J^;R$2LjVI1Z zPP1mrEG$`AdgsHBJy}&<>sIj4!*3kQ&6^rHUnigg?hiYwo0V zbLlC>=vq2!-JBDKM)q*;;oM#Cy0~K-+u|U7XWQ*QE+e(AJqLLBIlDRyap~kzZ0Hx) z*{PS#)#+AjnP3!jww1}|c)hD_+tk2823IHd=F!fsJ-cd+w(8#LW85^hib4MI`Z2Ad z7dsDjZ6ypD8Yy__U7g@*aZf+n!7%sRHf0nWZ2RxrvovJ&TT6yK`0pjr&YiVo4k;eE*31;x?gzNvmJH>JIHpox9-TY`iDg_M>Z|KG$ck zZKIdl1Q$Qs^2I}hW&J(9mnC$uz1vM_spS{v$LKW6INR~y;aXQMf17FG@IJPedpl{g z<8=Pv{9=!;+H|+^uI|DVp-*%x_pVwOFtL+u<88-4Gw6!kCOSh%v{6WWkiPZkIYOvl z+vetlZ36{&r)4upZ*tX_&Qk}MQkp1T&>vG;UQLo_vn(wP1XDQB&)+M8)y+R%+GWsO7Wnh zn`C1Y_U}7qTd5s!+;?rbehS8`6;kw9OHbD|VB6=0HnGZMIO?us;QuQc%m$~M#pZ*k zxN!wYH*&{PMzpGau~$9K^(e=eDRq*#_~wCK{dEHbdiNp#pASj7tUm(uQ^S?EMnPJbafx+`m@lGen2WPX{t+1w=m~oungpb( z0LAtbl}0st#{LQ1K=g5v;fC26?+G^iaMkc-YY@W}>$!%eMU(>J7G-dHad;vA=kDLf zvTTVZZ=4x*jVqS^QA(uL5Tpe2EVG1~xKJL{ya3n(S;))|Tu<8XoWx}ATxtBM( zoIbvOE&W-|(0nPb)@`K71Hp6cJ9H#kC;ImnUTj?M5MO8No!sn2J(xyUHw;8W8qpd- ztb=Jp5g}C|*$Z%mi$B-=k6;GtYsexY68ufQ%IiG7S+bd4khmAFYUkW~qHxRUUo!o} zMWkwp$0d_P zH6%&=D!%gbBQ)+*E?e&^q}8He?&5ZP+CdH4OONXIh(b-m1JSdbpE_+k@$GrTh|J1Rm z^v8AMyr?SGrah6mZ`iv_c_=kuC=oR$g5$PqVMZR}IJ}`M2bmY4ugyUgaZOW67)lae zOTvxxNgsle*XrrTRd~==&Cz#j!Bka1D<~-YkR0D*s;|Iy&{%vYd|b}+!JWJCUAuJ; zvG9B-V3_Q$2hWGg?i>7#z-D8Svfn5^T6X^L_y1A}#PsS-+3Cacef!16^&c>B&|ttJ z|Ch4(SLY>O72#0k#u5h&IoO8xT3+X*^6}4fI^Sfn)g~NTosyb09Y3NiIkvZv*U_nHA_=N9*I+?}|CZ^xe6?_*YMuKnU37W^sh^5*#KzO_pG!2*)}=_Z=sAF6t2q z#$z{}32=68#~4FTm_yIFth}qi+WsLvjx3j-yjuXh2UXIkbLOKM}iI=YSW&f zq96LkgJtVTL-^K{~x*ikgt5X=YgRk}4U?HF`s_ ziqQR0UTer!#n8PQuQ!d{Z+|6VgN6#yez|Ph#BuN94vt5C|L}!|>-?pL3pVI9x|ZK) zIG14jTYx(l=Wn?Dh<(?FcIFx2Tzs&f&T!o1*+uBWb78oH7Xn1}db-+~+oqi`|MyN9kG{k6>V&NPuc(jZ`bF!2D4w^(cXSJQWCh0#F9vP$M*y z>Dp9{I2PwhHpZEs`81Ts(cX|sq!l+bEtSDReUu8 zRJxHW{R9D2xRENn9)K#_NR_RB2mlq`oGRK3pj5KLql}9O=x7d-Gd3*2=o#LEhwIvS znGf(>B0$0=KjVxaF%1lNPwew#TmrSQ0$|iCO><*^XpIVhPEYIgUOd2VfRRVK8Gq0U zTrJ$gj^mX#0L~G(Q=|79_ZH7_4+A{lXDmI&bG~pl%g~s-3IQwtrtNy~pH%{EO7-&W z`5s=vMe^Nw2TQJZP_0NC1lq7Idc*jmcHHb^$jE2gRD=$CH`8i~;pvUmJN0BEW0!Fb zG8m7jkte*fX@Q_>_mAz+-36lCW1;gOHkI$L&c}Rt()~w zl9FyV!`VnTQ*oULr%uGxaX~36A{IMTNvI~Tq8$*zJZ@pkY@G zXb7X}&>P)fhYA401#j1Q7&!n7K=cu3y>SrOKAyl%rvO9C9b!N_yw`e=TX)ksNd_1p z)2$74J@7VNBo@(6IC&W^Ns%$a>(0#$1?aZWMFd3H-sB-Ao)KozQUF}0`K4k&q-`i& zhEJtjP>T{=iNcXH%?NI~cJ!M6mp^N`;ovZ#SflYDctyiKj9Zwk(X^t+q%Yk2YPkho zD2XAO)72H1>V>+ zOT$$FLhvAI|<-Jtydk~v2eSe*BgD|DU;kf zO&hPR5Ca>5CymBO;i;V5Q#7rcAD_c>RRmgUum{vGJfe#-Cyl4)a;ZZ_ZK~n4m)C>97xBP)i zcmmX>jt0mFU~OtksLyf&)TaJ~II97aHkC3VUdEm9cn;5m1dZ1HK>$5^!vVY87ogaK znA7+&N*s2N6}E~Z>FM6j2Xfog^> zQc@1JLj=?gJ%jS#``RlyvYnf$e?L18`!~3UGt`2`=_1t}wO8ZjxgC5?7ZJkyc4Tfv z)?R?DF@<=mC~L{60b%qXk+m`kL6)^@s!&PRPQb0mT0K3GWX%`jJ4M!F0c2Urgjw{0lr_`c8##8dt{$qA311LA3zH<_i>Eh5;mc%BCVVU4{GaeSRM(#< zeCv38a00>OUqkP6vM78NR7puH;iCrGp;Ji&hfXCU*gKWg6oTB))lr2?4c$e!72z|c z+l4QP+_Lb+0?5Lb2)EMEI+0ocLy7h|=4+g+U{| ztb^BPqn!gy+ujv}XM}D7f?$RVi}-?`87>k46vIV60kz?RhE)!R3xNn~!vzr(!v$xU zIZTX_Yy?Q5!8BDx@Q={Aa7rFYkb);_yo@n0vy~y{;Bgu^V=>C73c&vj-kaIAYU#;% zjTf_P)dR?OE&X(rUCRuh*tMbn6uVXefNa;wgj=y|*$BvXt#SgAU8@Ri#jaHYaIKYQ?T~k$`O1GG<=aG$q=#g5W{6YsHfL#_U?)|9dg$ zq01R}aFRyrR=R;10YBdCW@ zL~s~BF@k#dLvf zfLQeJrix8WIdU$5wSK?dqKZP0o0u8^xrwQRo0=GJvRlyA3pe_BhQksIFpQ=~8A%fX z&5bgWChWihL~vjMMo_T;VY&Iai1?M}$Cw2mRecb-<>n`rfJ4=@`uWe>G!iKyb+uDd zjcWHMn+9Dl8d4KvAiIW)sTnfRcuOImDKe0KLnbg5BpZi9AQmJ$hfJ`uAR{sI3sTF1 z{oPsh8{ck;$pWM>xPfnGTm%zq8Gw)hTY5S`6+rASEsdjL+^Zosj#*&V?sEXtf+*H* zGOal@8r1$cG#W%u8V&E|_fUE`4(3@d_L7^ohm>#%C-GP_!}qU<86h0ASkRh2QWHk; zdKet!83XFzCZ4uW7!Vc}tM@Eqg09xMW3T89ax{3Ii|wFkuEawGhjuL`mC2U`0Hu-21W+0&8-UzMmBXzxQdI=xMyiH@ z)JWCAtu#^>0o08Yv5|W6h47y=`C^=@YNUb)$c&Nn#D0o6W12hBYH$JE$ zi0y)5k~Ae0Cckw58=@E!A^Ia1y*EeSPvas&vc+f^p?ag=M;KkjstD0R&idxJBO&=n z6`PluB|UY+>uk>HQ7Jq|=-}MSuvuy_s7Cu$^Ztfas;)3H($&=MYdpe5K7!q763QU# z6jMc+#Y{t!JhGjH`Tt`4XeM~a!(4Z1Q zX;4ja8^u^ri-{P&b`+(=i#kmsW?a*nGu{JcyhsUf(YSeSKt6qQP=jBzX&#L%THp@$ zLiQNX#3PV?{ACMPn!^VOI{S)FYw|$ z@W6 zKgG`0*8Ps>3P5|Z?$=&%O?9IaVI?f3#}Vf$e1EbwFDf5>A&9(q`sTF zA4ps%_51dWhS?zzM|lk z)mH-Ciu%d~P}G-=fTX_4;g;1`6}e^gRZBopU-jgc)t7NLfJ2FsO#cb$%R&+Tqt(~l zU9hAAxe%xlNqr>~XbnKCLu~;62=!&ufP>5Bq?e)PtpZ?crM9E9Swn!2#RxaPR?4`d6l-S?Gg~L+tqR2ZxW=dPf~z4-Ex0m$ zFE&N&6K+~v1$l8$;caecg=`cOp{Vc#0+>P!M}p1q{8(jDiv-9kb9s} zlC?lwQphR%!fii-+2TBA*YTy>H-`NAbH57wzLqp0mObJ=#6!EU?!J9DKZvM%i(bmPsBR$ZVppp z&3@9laV8T~EM4B@<$}gbnfoLYV{ARXq%f8Y!Fq8iNaGSjrk^KGetwO}%m9e2Q*#O_ zia>WVcjHnNEk!Q`suV2|&?)`zeuqLvcJ5`|m5_Gb08BQScq5HB6Oaj^nI!2Y1mv-1 zC4emHC&(>Hx_-W0(k*Z+lAZ{lNV<)HBu?g9u zB3l_eJ*AbI3EVW;4R5hH33Z#x*+l_gVU7ix)mRrsexD|P- z08r$qhJYkb^>EAbLy@OCxD|QgY$|y& z11RzoOF)*VWPnC3V-dIfaV(sTKER?Zs6N1AIbxsBg05Jn`Tz(m zR6`pgsH{^WRIF13)q1%Tuv#w@Ce@&P!axL456UMDjG$V0K^SU6`Gmnt7^*_~gnE0HP123rk4yOeuLcNj5% z;Lre3hs~h@5{Tfq!-!ov#|?!2i6TLm9<*$zl0ZR6&PaQYR1?6yBkr{C$O!-pxyja3 z&zx+_3H@CNU2c=j1Z4dfML^b%2>^jYt#G~ZZWY%D5sn1Vz*Y z*DH&G$zu8!8GV1BGz1KRfC6YAgR|C8V(UAArX^t#7NP-6u)Lma$5|pI}F62YK zvkN1Dft8JN7y(SIY?MO;Vq|5b97X^$D;wnyLB-HbZ0i$@ywJ4{H)X;59@VNfp~TDZ zf@+OgYg)9X-p4>(1LS>Jnw#rRf#97-r8R4W*_t)?L!!zc0J%Eh3_jc-D)hEg}*qC-N2%nR2#nWZLsj+adyKRn}$_cM9`bH`?Us zrN5hT-QOEVTsE(^7s|K*;3#gPR8+SwAQP^Gw4#Tdc6EzZg%h5T)U6F=uc+H{09oBu zky}!?HE_%7whnGZ-ChJxIvK_?ySfd6TUNKRXtAyoXWQsj6ixv{`P_hOz+6wUN8db9r@b}BB=BZ5M95s^YQ3#3=okER*9r; z>j_k=)UDiyP_{NRBDP;wx2&(CR=13xR=13xR<}fOP`8YrR<}e@WxEM=y9;@t%MUkY z!SfcWQ$UJKSlqFZ2=4p4iC}9=dEHb!@8OmL;u*+_I#dBOpndel6Uxqy-W9D=3#(Gzul-xV=A z^m24WXsVY3Tf#qXM?uEwH1$*sR%cUBPfMd#Du-tzHm@ZhvpIK^N&4b7-vw1uLiOn;~EwlLw0)GXYS5ibxusNH`t;Ium)LIX> zGHNy63jo$;Q@IuZVrwHcAPEG((rhX>AD|IC-_X?4@9W6>qZeL=7^yaIbn2-J{*|ex z8UT6fsSa*s>gghYGWBGdBYf(kE{gxUci#pFZ^zkGQ3&r(`&9X6os4uq|CQ zmn1xkHu{u`fT^eZ$=HR9o~sr{6Z|huJ(VDrin=H#;GiyOtmt6mVg&V925fjq<4t)# zGe)4+NZvJz2zK$k+0VXdO#B;DPt)Lq8YX4WTh?!)Mu|FxbOqveXrj8V)~Ubu&bZV@vt9ehXyI6D811umeK%Oa!FtgQuQ;^pjL=kx zDb@?tbNTDL)3WtqBU1c_truYwh{}3F*ui>11hw^ou!Hr2y+L2xk@cb$#rlu6UYtYX z73&4{eiZA4FM%7KgZrQL0xTk4Oc1dSkE7wNqab1&$OO@XqIDS8`oQ}?LlFPr<630~ ztJPp>R_g#S?j4J73AvrvJC?TU6~6O2j!|ZE0-Qg(dF|hZg-dWpwDD#emzKjF-dWE! zF0CRrHUQx~FT{!M5^2Z?b2G0`5JC;T6=?Emxtrt8k=x?uH5ywnbGKrL$zngY8-Op| zO?QpF?m?qx!Q+USX2wW-`W+9qpuvXJw1smrKvZS(YxjOO*1wPC$)Z=ik-U}x^a$1X zUh9|h9#bbKy9Fh?x5cntT0iLt+~ZZj$5hr&^gx8LNGFt_*HmPo5@AO4?!=N(19y{I z@YZ0B*y2?&8q%0gZJ0pU_W@n6G-|Q?1aVk5}!~@7X z(Iiu1z=&)I-4c2r?KD_MZh5n_N&tC)S`D`{Ks^DV3{dL{NCQ;;81xpU9dym)mItU& z1f&6K0=eY@Y9;}P9w+tP9D1CLpzd)Jfz`I$<75PNkCO=Y+GgLi+9;yy4NxoaP#&P} zhFck+))J5hsOJEb0V+3EH9++Ru*ZkU#mnCd6*~aa5kebj$DtgE^9d-9Cuo1=SaHW8 z3tkrDz|Hbb$;2cM^-KhZdS(QBJ;zfB@{U8v0CGK-!0oW(P(OsE-f@Uw^^QYCK%FZ) z4iTn$R~Ehzf$Cma_{IpTg>Qsq9w^aj3kk2 zTO45rTO1>(ZE-|kyeM0}8G(3Fwt5qx3EnWqV}+A`oLKe7@c?Fk;3VuA9s>|XfOfcR z2aqT}2{h7&{3Qe?I|Z^m6Dk0dZ})2elyCRX0XS^oLAv2)zTa_?X0vvBG!cfMwu_1mEglz~>eR*Xg^IuucS=n-js0oH zN*hFw1h;;{;A@t5j3B~f4QHYw1?Xyq8y;xbrX-GxbBM>DI3ipxakMP~UF@ZqPI_fW z0wS<23Vz>?1W@&~E1{W6PTrL;7T~6KB}^1w5O*ak0btuOP~OW4{N=k6cEhfOyAdexh3mY=C8cS-M}W9e{9pj{z#tC{~xoxlMRKXv?CP+9NH1GJUR3w7(v~aAc8|* zf)Uhx2_o3__sv?bNNuUDSA=h7dneAXSdU|Ka0~0j8EqZ(p9ent-(W^fy{$2}Sc`Tf z7w%)&tcFG(K>+gTBNlFX^pQwzHu}g@ceFA32t*M1^cF@R9e2a}O>T@nW>D81Zh7=k z4R_N#?ezjOc7k5R=;OgVuo4Dtp$?nMtOL;Jp<$YU_1?b#mG9iv@eBl(wHKrt+Sc;xh2jE7|X}FmVbaUPcf(2W*NCTTm zfb{hv+hNB7hw_zHB7i(2Y$LZcRaObNJQAsaTN#O*15idH`dI+dNF)euxfdEwZh0h< zNkHm_t{}JE3#}yJpgl-d9kd4{sI>@gZ`2Z~Lcx_2@qa^~=ULzi8+jcUZ2?@F;FtF~}K_6@$FMS5XY| z0^gfg48F*ptQahCONt>LPDwEwP%8#70_W5n3uq<9kPk(zQVg^nmaY6w#{0?~`U(J9 zF;tOTQVb{HmKDQAxE00V3+suZ7@`PBiXjnhSuvE5TUHF^1SG|gAPz)C- zqU$LJUo@SvVz9uiD28|fvSLUEP!vN60a-DW0sJ1t@Vn;F{UcDnOfhWWHJsmtzC70n zmO*r3bp40%oXc?h>+OsBeV^C33>qnclkm%why_Yy9&E1US2)2NAI*e0vz&R?dTj>C z1VAMk`sqpMKt155iuCRzoe#tas7z;^543_jQ)NC_gq{=us!XF79@P-S&c?>u@hN#7 z0cdyQT!4!JtRR2DB(8CTRFJJ-<+&gLdqEnLz^}0&QNDo-#a7Cx zzl31~Oq?}Oh=uJH-lfIw@nggnNJh!P&lxL_k}@$oz40D^N&uED&*@nFP5||5YkfNB6@ z^JX`~=5^#*W^)chbUT}y3CV08ML=fr1OSE2X z0Ip^83ysnHm`&8rr6wN9_&JuxCKGb=w5@vkZBy!kc-nZg|>pR!#vENP!Ra|202p4qI)XIrU%stm^A2D%Gm;{B2(3(yODc2{k|KBtK1yrQoCqdCuN>b@ z1gKDX+Z+)p-y^$FR&d;|ve1JO@Qsyn05Kz|*G)458P4VNoQXiie8Zoqa7t>auj`On zBB)X;LM3qo=>sq&ag3l&93!X`M+Aq&F#`BN`G$rFc3wc&EJ$it+u?!GT+q6GE)Cg< zfW)k+j-zW4ZvSCI3&%*k z|5K4RUsZ-~3`OcI=-bLCp|fVTrSP9_Wo?K@Qa|Nz-i-Qj=>TmqhBOMaPira|(jnR* zS}qi~&{;4(vwkaz$^ zha?k_bw~+-oo|e{qDIT;O<9Lj0w_A98sKlDLrze-{-;C!TpbeLScfc^M)#5q>H7P0 z$VnPkRG|JyhfHm(LmVO{9r7QEl<5#(iu5ngAyJ4&(jf_O-i!|6bhklgIGxtQO09L? z2zQ62bPTs&`^_3|4DN)VG;P{GpyBAK+Jvhb|8;NTKxFt%_+BHPw}37RN2jNI)3NDv z#pAxQBc}ZCIHTbX;!fx;tq-7v_Nz!O*D*@VB^WiPbOcOSGu#O#jh-!J<;WL3VU0vf zfN*%vp;tzTo1gauZ65GWqUG6X&jOz#+AdLF4uijX;2Lj%OE{r1?3d1~r_oHpNln*l zhc|(E!iD1Yp_Dnf!Ca)*whKj>wWlM_HTeG9c?-%Rjg=zTLF2p)XtsoS=lfA~cZi5{ zB9AEbd+_rPUe;17cJ$*{?-{`Xp|4m|A+_cWb04#ZWXJVhHFA&RcIy&aOBT~ar`K?1W(pCrwecQbB zsYY}T6^s2Mda<3NrN>t^#?halt2+W-1-_lv<|8mTjO4f$9$MoPxP##Cv{DaSC623# zCGfOf??tD$Cj!XRrulFy)21s3$kV131f*%x-Eb>2EVTePIK$#CPydr$MZI4YVTWl` zMo>?i62U%g>N!U`T9eO3d=^?3-XazgUt{l{diKKJN2{HW_w#!7uE1i3zCLZkY0 zMgghnld1j_NK68Dxnz}F3JQh5Tk=v57c?9ZE+hJ*L1^hzr}L{zs_ z_c1YA?q1vp?ZjP9h_(s%tN+K|o4`j^o$urK&X$?nkle{kmPsHJwjpd95g{l-L{JnJ z6qTr`(Ym0brfx*giaRcCsZ@)5L`B@Ab&0hiTD4TGrmkt-QdeABv2Lif{-5VPOYR`> zMWx^N_y7Iw=W}Py^WL+c_q^vldls~zq0FC}Le3Gd!_^G8A3kvcz#;F5Ymr6V%&Jw zxdm_I6$r?C)^(1@+xQcJn+@p3Py+XJC(gl7(F^!|8b-_#AHp=_MWBO1I4Ty;age;f z92rr>2f`lD@!@k4-o^*RMIO)c;d2aLd!A3rBmhkP*!4>6$?^2r?{kE$iIu z9P+#e^m)6;bQ0>4PXwf1>1)sw(nr~#WPppv9#$Z z`SZX$naDGn$Ks7FU~_yH-ZTW>cz7sn^N@0%2Q$ez#IyKSN-=M_TjSH=e*dQBZo(P! z8SK+x-^Tj8az-0H2y%v`>IZWM%l$iWMh9YHIir)naKUW;S4!MyOr=yVNVXxUQA#P(e5A!iX@JWeQ%K@hiG?eFXf1_H30UA zF@LfIrj8h^BakQ}MB%GOQvMPywgN`t5)?2bC;>xh&`kS~1U@yyRsc!?pHg5UfRzBt z2#f?+L14exPLm513n~2kNt|hes zen!%T{b;KaFK0CE_agK~&%)buiF~I@$>I9U9H>ywqRg9~cQe5aQI9Tq75RA?eiGN=XDmXRSqC-|ooNwT%CDg_@$<| zANd&)1hZZ8+X!Hn{5ApDzD^5(>FX?j+4gnX2uxq6gFyFnI$^ebomBv)ufyz&;Wd37 zgM)n?(xCn4^<9Z=U&mO;(+y~&r>_GEIR^=JrUaJ!RuY&E@AUxdT<8NwvgCI%ESM#~ z%{1#JzpWc^=%f}+g)oJUnM2)Ja%*Hap9EeZOn}_Agw5Pys}L|tW{!fU_o7x6Pb6Ur zNax2vSOyPEe;-{-d8&_9eOr05J{G`(()w7vy))KRgerSyED0i|{r7Pe*9wL)I#yOP z7U-JYA^1)_dn2rmSexW$=A2vVpRHX0sY%B`q{co$WaDkRIAEK@)q& z^w3H$JjgR3XC6nHElo+~8?G}6X&&4XajUz&ah)x<2N(&}U@Nru^2Lj|i9^u@KY@2} zDxyZ9OAzd7$b5U}3VC+$C@gZSfx+Q`|B;i`fWzSa5qs!eF>MWqRC=3Vtg;(2m4vwW z{t`tP1%f{rLyt{MF%G!|1I{O*LmRnSeP#8mnN+k{awd9ce1tHo2x2JWoYALPP7ZHn^J4uhiU98*BLyK9sUPkT1~V)Mh6ZGg`A7<4qgQC9t<^M zfaM`K8u|n5P6jIY3U*i0suW zM14ujL$q#T)S8GkgXut`U7^dp^e<38z>fsB7Xo`3=`g@a+=p};%ZctmPy}?$qkqQo z31ONX^O|*Y3`Vgz+9$`AqS}Cwd!y?!!;)Yls20aG7rX|_m*|?fk@zQAKOtR=>X9MmXuLzu zLZ=2JnPyb9OF2opSQ0=dMFj`JNN3Rdt?LfBjBN$iQ{eh@u%!<07RwJoLbe$`LA%YCO@^TDmqpL8w9LYwe!KYRDlL2UW{uBxWIk7GN7N3UA>Q0=0 zjquQky@^_&zm?CIZ~Rl=mV&!6Uq*MoEnp7D`KP{}4Y8%&{ZhH(pL~;ykggF$+w+Lq zq$?uM=<|@)GoU5JevTh_y96KA2zNHIm*eb$H+__wIdh5YJdQVgtedHN$aQ{%H@%aa z`5gbFABK51*uno}G*5RkPvbxNJD8i?Oa}i4)4ac%X~F+}G#~6{Zh6dguEm>fb+b*6 zhn%bMrjK_shhXq~8D6X=ruyQP(#s3{NU*TpR!hg$UFt@px156=Y zuj@*-V!0!&UOMMSS>%~ZuT@>%bc?Hw>Ub8)(4Q_^U!dGkL)ojBi$X1Pb^fsUz$@M(Hz+H_ zhmI&rd*`lwI=0b}X~PWvrO7ALkO6Z_lQu)y^yOu!5QIgFFI^aNT4+Cof)Qae3AV3a zf<+2jKKoLE4^j>TM@CLO3b#bvY`qNgvy-B3snd@RB5Hid=az+T&t39Kuho^5Ms^9 z3$#@nEj;fv7@f?Hh|XDfM-D(UiGPkrjvVY}7Ia}J8s3rPdRo21AsE=|jZEvd_vve~ z9CLdRc6ZfmE!)PcVQT`iZRAc)^lLO|(cZ|~*dAaUOt>=S*9%2CI2d-`r!i8{3LBr$ z7%!-Sy#qZMi<~G2<79xdQaOBzbf=Zj+N>- zjEX~y7Kv9^v`{&6GPCb@WcV+(t7@CBM_L}f0R{EcGH?cjTWq&@I`$a2kmf%Wr7jwa ztu-)n{LU$!xHI&7`BGkXHNNoak2m&e#M|{>0tM%43gaG`fDbLCei{BYC&yhUZ@(W>()FR>{8!T#-Ru%)}eJ-_0yPR-MWcD|Iu6&j>qGoDNA>l89@L1VsPv#lEsWn`P^09h;2l1! z>9G?EO1S=)4`pZU#CTCJ9rb?1rxdvXh=}i`AsCbC*ft+-kq^z%9&Ony?a|OI?NQJ! z?IECJ`E%L}+Ldp`c9! z;f51IuC_~9U=}vdO9Y97`9s#f4b1s3ys#xHOYesC58~X@r z<6O7@^EcZydP53c0xfn6<)t$)TyP{RL`I`X!C&#MRv{-wi(0;lgh982wq189t+{ab z&2PibAPS>_Zf5iYVcEYC8^s}=VY;q!HY%FTtLyLbTmRvX^G{s#7%f$`c30Nge+&vc zr;mVxI(WB7*x{T|w6`m%z7Ns;>Q@oxDb%&-cscB#0aao6*l0AcGD;YhMN zNEioc553^ypDI_B0?FGD^j`vmDU;lIS)`-K#+1)9$8d8pSDP;jv>SVISn+E4S_qIYe6sO$8@yTb@I4_X2XL!dd8 zZy9!WK&C|x-3so0j2}I_dl}qer8BHiTXE(iPZ_(`lFYexgk`+E6>3}ZPN+S2TN~ZX zMOfdlg@y==(e1=X3rn9fL&NhMxm4+|lbwm538}LI9b$d$|rj z_qrToJDD9NB4PaPF((8;Sir*XcN7OOG9^u}vlre8B@l2Y!?2tn>qhyXdFBX}8xv}E zH#B+?&UGVSI9nkyA0r_%kgpTc>7q%f=U|8lWhw8QiK_V7-xyXMj(aEV5Fl(FF1FjN zlC&`+;wR(xDI08^g>aU3f>4}cP0%Qv~=xdX%e!U4?iGNO2!0m z*$W9LokNZ-WR8`Wc^R1bP*CI@cq)Y8-a2*`{@3@`C5O%kWIgw5m%XF28Vws#kS_XI zo8>xn@N+_4B)uEVjWF}TjAz=h z$c1Jem~k?MYYPE(+8%#6&RC$CJ8hpn31eskvP*70KCL3+F1bk$g1=`NGn7d3Q6cu!VBF0_?e}!@O>(o^;AHhgV zvv+qh@178LwmLEF%-+`(HE&O}bvs-Wka8Jkk-nzPdm@0jdZ~&(_ZMoT*Xv&e1L$J zOeGfuRoodxWqE3I;1+qKHN#&!OF&w1R}OLB$|fOTa=8of=uv^P?^Byd-kLqi_Q=1$3!hOBO4if1~h{L8k#`?4b7l{ zhGtMeK|3fwm^Uauj{FXrmS9`;N*19>IS19`4|r!!w$)@Se4o9OswVBoWK&I6!fdNa zH-N1sYY0p=@xKaG6XAe5P-gGiM>wDnX3GIh1cn1z01O8#fZ1|D8-dx32D9aWPJr*j z0VR*@rpin*ZU!{se_yrOwa>S!MOhxt>^jEs%s`e*56@I9Xn00L!!sHhp3%_ojDnVD z2sg|#tO|JpNhAaZlG39;4LPg6LQzgBN>+ZZa*$1BrV+%>bBV^*P7d3Nt4WQcIsl zFM>c%AUNrXYz{yfyLGYuYXr9f=G4C7k^XT2T>v$km&HAE;xFY(&Hd=KeT?RX4+&eJ zj)9ZE1_`p{Fd5P$Hoi5>%a{>JWACq(OLq6hR#$sdbQ+15|2>MImLr|RNZaq1o@S`GYqNi5=c1GQszrC`6WR~aO1jeV6~kgzb6#*ony z2!PLEI(i3z+_P37$=@LmKJ3#tE0Bp|PR$GZdR ztQcOre0BZ7o+xaa`KSFgZ5 zH3&8{1$l5jz$ySy)GOFPV(Lc}^&646N&qVADRNf>0gfO;eEgvgqI`feyTFecfLV0L zBP)LgoAU{%>|X&t7SkF0$YUPuPjU+_UYLWKJqwHd<=}*Ndc0R*X>y$Y+J|3{D;$`d zrfVIvPbbq_nDh4sp_A6 z&-z*kz`E+QuGSNvo~Bq&Cj;m@YPnB>A^Rqu_)_tKl*49Nb?Gug2NLqc zgAjt^frRx3ZN#sz6@s?%SYn4%I{rjtLNnr@IlmBTMwZS8sJbMYl?t$!V05_L3Xobx z@jF%kTm8L5b&*N%qr?4^O+f-Gf+K9-&QKe|`)7#G;lxAb< z>Q$4&l~(>q88<{KEe8rgIB>`VDjcC~!;wR&=8cTg;%Hi`c{6~m=JN?yMOm}k09YfF ztn+**MRf<=KLG5rQu)(2)dym>o8UTZ02V2*hUiiRK`G#)i)N(&ccn-WEaOH1IoORN zp_xD(<(8!Pd?ddwjrPq??d8$ZZ>QGVM+>!`;jZe6=;k7JTj6QdL!pWk#qL4^;kKJ^ z!Zd>Zq};Gr_6w2ZYi7 zyC6*C*VmE6mjPxG*d)%^pCpNk0c;Z62}}~Xema=MZslyPRK4-NQ^lO(!*z01Z(!eG zHF9eW19=mm7{CwfxD7+Ssv}_BvH*<$CU-vjZGfNQG`~`;0>Nk%tT|P|N+E=GR|?xg zh+KXRneKSIYyL|kz|7f&B_b4?5S6N(q7_m*S_vo+e*x~{BYMllu}bf(06~Pf(HUq% zbUdRokf4RQC}s=kCq#$UGDMXLY8fOb7gF@gRE!4rEcz7$R4VdXJf*W40W5qqIa*-_ zun@>E9;*Z&Ne8TWtQLkK9L%a=3FKf_4?{3z#45rkg|})lT0P@R(y~j`x2_~DKaR(7 z3`?*zm;x)NKOv=t{)Ce!gQ|8$Gfg$Aiz%Ll0--EfL%;%gRL5J2lLgWdAV`6jMuaw` zK#USaf+-L-JAOnLh;bni3aVWs=mPN}1?%WwT6BOP252NebCX{nmxs_o*fvUXWhx59 zv{6D}8zu6kiC#=aF6PM>*#Ca=#R?(Go9W1DBZMU7QWzHo8%vDKC-3}9m8gien^+i> z)_la5-4VMk6b2uTY*fvN7Nr)U1;vII#m%OVBMLDy&-8IfP??t^&n}>Yrf6SjINKB` zlZJBzz$R%p_lf#eMhNQ%WrPscEhBu&rB#g5!O^tHB?p~V;rV2z&JFa9oT}!iFVU~W z=c*&48Hs)aKrs3YDA?``4z&Bk>umRril)C;^d0{ws(Xk=W!R|g;_g*D8LkCD+#CoQ;2l~nEE1hkj{GJj6zcfg=cz)Yi%8r){h-u zQ=^1H&DPXG611PT|12`8FO(kBe-=?1>^}=3s34PIyfF%%6mV@gYZW{aM8Q*vksm|! z&((@iJ%Ck=rV$v$s0CnyiqT@_k5Y`<39MqYl4yZejJg4=Vzh>UK`jV9B`XAx~bL+vzDT|^s2g6+|YY`QQO zNg5$9-Qr&aM-r$b!rP1;Ne}{CB{PyBLPK?RUqC#X8IMlHBd8x$F&;)V2}4Lc@_M$6 zhfyp!6sWcv?p_xF&++1wb?Y8!xoAUa}?fYl5C|cK{`e!Lr$z=ccvB#51n~1qldpsElYSh*)D*N%1*2S&T4d)PBW zqM?bTh9;64nn)^WBT1MSNg)JJaU&rZNpz;|L3|u5f4&XdhrYp#VrdS@xfSoj9co?g zY?Ng53oQH1MD__gyWyRKot*s7RO}aaPQW`S?ne2aIk8#In9oUYvQTzlk`H8Bclz@f z@%_o)2o>SvbiCxoCsiSEd}jI#{0<+0RhcvJo{SA!(JxxC1oL0`!A7R`vt7NBDHHoK z4)#lhoVi_U{&OHg`vA+o#$Fw9<~~t!yx!KZ5}wX|Ds86#Hz$62JsX9ZF*R*B3bhiL zjY10nq$9{ZkIM+mMxhl1W}{FSfY$1rAGYb7g_XBah=lcT6zW-yT@HKmkPqDXJomKp z9OQUCVl{VuJk5QelWG2Qz1;@N7OOP44O9rS4HV(wqcaSpvo|u8n`Y-;=K6np6&vU1 z%k}P7c1s6q{@k(X?V2qeB-9*`G9U_PMbZY;TJj{oWWC#xQK_8ZD;#br1jc$?0nDL|!WJdaeer(lh?WT5{=oNzYpN zGWR~*@l`6HlII$Zj3-Qj~1|!Xht6_ST=-H6F8QeO5!h1IO_Yu5vKMskkZ)Vay4MA-q zyF2^g-2)xNvgtpg`lr^4CFVu^9e|tB(>N~VdOkM;v=W?%DN*hQSO_4y0pKE2@Pyjh zk~kUa9~HRhANj-3V=v;zaYaF8{eSc!Y;?R9D$WGE#c?uPp~mgFQazJgqP8{Gr`^m# z*bSxz75QqVGGW7Vdu=TFzZ$Q74Yo92P4jY!*C384o7(7Ki?;>A?)md_xMUT zvtn!QQ*Sr34SW%wYSsP#`ZU=1guRin^KT)dK`C-P&VXffG7b3Qn$_cnx=!{?L`J^G z+wStR7~&5^OTScRku|Z{%oj0VHwW0!SeQ z7eJB_TmUIYyEP+ddz*7B!GSp8ZUXiUEdO+z!Uw(&D z`HCe|tWJm`t?)NE@&a!~mEv~Nt^@A~R}m}+koK2-#Idk>1Z@v-{Yy}|s}XR;P*;_1 zysD>kYiZV{+W@mE-Dxn}(wzlhOLsniE#1WcrgYn3wxzq0z?5z`fiB%OFx%4gA*TLA zrCW!fZRs`=n9^+m*kI|lz=A2=1vKl@ZQFoD6p&g4T?P@kR#iTB0w}8Ts}oj4@UtEJ z_<@L1zdYjf{fWBd;FjsMS#b&eoQkUmDz3$^KK&_s&jm{U^qtcqe~yM1{UGW3P83d| zki7ma{KQ^NhPfPj>r=7)xr5^r5-K_9x4%_;uln}0EzqYRZ3dtE<}7Ih;DhvdGhCPf zzt&1rajB4KWApQ5N7bdZ*2w!{6&2YM*g=+k?GUwXY*Lj<0h@&j(E4%P*rakv0ZE6y zji3BIWV12q*4iiw$alL#Z5TUckem4(%-k?`%64vMU%g@M6zud)=?!D2a4UQChHbDm z`zHK2xVH>_`0QOXR8E%X-0X8#tNR+tN2r>|w(~1QKw>iv;6uhH6G299iMKrIX7<0r zbuPqPzK5H6;VSGVgBRs{qt$D}vUa@X2e_G0Z^4YWyq8-)v>d}cc*_s&N%pGyBTgS= zdwKO1@LmoK9}LLyD&M)zkoE#;BnDH<_qC*RK)Ra_XF1V^Mx<^$eqy`e$9D@Rl90w; zU64+N8N2UJ!e3t;y8`7V_72RwBLz3(PcHB%EVviOeG*|O6fbxP#)sZP9(e^%z^L35 z{Mi_>_jv4f7~hQ)Wbr4?V+BKC6z7qGEn$2P&Jm6in*)%?F};Bu=xELz5L+MMJ>-b= z5=gF9s8oj>8JA|s>D?o^Drwe&s~%<}xF*AF1y?hG6 zb}XvWu_F=tx}LW4^7rr|_Wn7cd^XH{3d)#sp*xi*P3dS@I|l4{BU#eR&x~H1JTp4L z?K(3$Vf-$c5!-jcT4~84>JHQY5#l}!d2q<>eGF+Npd=}UDi^&5BSItgnFg5$Ayixz z4R?+8oy&H|7fQp-PPc^}S}Cr=4&2+r&RLhjoWp5MFt6Iyb&7|%nK|uY=PSI$we+yD zT)WMF0CC5>-@Uh+-Ek>I;iay#dlu$pt}{Fa`an1P28Ik~-wgUtb;1Yr;{Bn9rdyuF zj3<=F-G}9`r!5T^W??7x*sU(xu+#qHIB&x$HacGp%2!88zvu}V3vPqsGQ=oz)m=CS z4Da+^v8xD&L}sB|Pap4QHpl-#G;iZZM=`OxKZy-&cxObR;{TkX1P+FLGDA6;dF^#q z&KElXL-(=26{F9jPH>4;%jY$q@c6Ltw0YjND%iy1CVNQAnM^EBCu-MJ^ zepj6uec+J5IWw1{H}oXl1GjSO_eZf@gm*gHkk~WWQ-c=~&K!jQMcO>-SzLgQm-I{U zzfzfH7kliLEfH|Ae<9*_H$-VP)C+F3KCLKy8^mols^Dq8l(=03v*`u+H85*&TL-fd zw~a7caoYr7#cd0K6}JljjJR!s*^1i^0wZoa3ADIf1+x{mPWC@0ZYvSA6}R;SM%+#Y z*r2#=h6N*TTWQwfcHssbI%VdJg25=U(~2YZkb-JpEgF`=10@=yilf>)$DkN*!h2fU z>H)t7ynQB$Gh+q82OtdqPn`ypLQWg7mR|sM(29sNztV|*0?x4>PXzG-yr=6u?d&;T z3j74#>Dx%NyaLfNe9}d;=9ASh8$O9cELc9N1+aY50ATrK8i3)GSuk5ZnNMK&WHEu} zlXjRbpR5G<5A`Ry5wzu#H3WuF{J#GKpVYyE;S-z;YWbvT0}j;z11yZsQ4oWnBJ09v zfg@8G3uxAb(MFH;sq7sv+rsDsu!XS-z!rwnuct67VYY=)PhbjTGJ!6PW|(bZv;zEx z3S%LHwuP~bz!b&`fDKmKE?6*yv6^OGY2*FZ?@$%SKorIp6vRXlmV77%ZAHWvIVgOqh?Et1`tc2MXMmK>ej5P$hFnn-_EsQ#V|4?Dz28*7;Xd*C$ z(E_l+!dL(crZC!Q)`iir0f!KV>K4bh(9u}$)ee98#K9tS*pRs*@7FvX zA@be@?@PV&a5$p?hAQL093M`8ubZhjO6Jgm^ylac)0ZZe!U^sc-^Vwn`e-PZ64T@L zeVrG>?+c67c+1o_S1xR9VG!52DY>w50Snq(@Ye=lYIFz8wnldnm>Ru`K-Xwz1WF3q z#nap_UI~C2z22?jOl|NI3}Wt*wtHkbz?972Bg>(U;K(U)-pHvCf+MFSLG(?fgP&<6ICwHId#txOzFYQ%XV<+Fc@G;71Wk?;sCXyj~W|XDU?_Vg@XAlQIalEPScv-tX0)sd` zHJ-dSfJ@7xBuk%^QfYf6g~xHHR+qin28@SoQtG34nYk5!IK5}wUJ5`g_mFAP!E!$Z z-tZ*vRM<_v*9HO}Hix(=Bd%J}vw`k{EuQh6%DDb#ZD2FxNvaAnJ;x%3O#tZw;{FB5 zxfYm9i?JB>MeZjDNZyOX|IJN{oS05tA1X<{cduf04!j7#9LUG4N#2Y_zIlgvZ14;` z@ice_9tk`HPadgjwJ?5+B=BhR)Nt1eUDNY1wHeyQQ*=htcKSzgd#?gHvGkabXHy`A z*N`=Msy}=TQ`MN1Ozn^B$8LN)}}9Mcx+4R zH8(Q@+wZ@|f=5`wv8~K=b-MTd;AKp?&tL91cjHYh3acxS_lAvLxriM3ohl0X$HHFA zI9TWviWl#`GqM{XeJP?=!`Lwwwu5z^3Z7~VCFj99pI&%V+u{5|sbz-&@n{k`lBAu! znFA?S(l>o1NjJ>4v0X!8)aUWRiUP2SDvDjC$y5XzTjIRNRtUkymV`iKTLUPI(oREO z)ZK)pv*sq<$8v-rl2_=;}8;aQ!7&!T!x)@-Y0YAk>w2yZ?&Z3v_Wjw$E z5SK^14ln@VnYYp8O$XQ);LxzEz)M`SH5$d#29kc}MjKFm)Z`#RHF~0oapVTKL5rc(jnf zM6w;gL{e2LM(iS!`!}tX`#1lP_;oVin|1tF1K9Za+XmuSPhjFV4In>$1`HphTo(qT)Ez(>W}hT=b;w_|1g#kaSE?2%tl$U+hQ2rHc`Dd9HV~E8y8VP0qsVVsqm=#b@4z1`=ei zfIW0ptehMww};M(6=`t2Lk?2`iK=l^s63f`w1=QJi^0D>cxC_NrFCkfL8>&|k2Lz! z2Qp18^aiLO9C04Ui>c`9t{h>tmUI`ips8yCCgSun-guE}14z#c%e^f) z{Kl>R=&rC5F1Wl3?Z9Tp-PlO{=p*3e_HA{VyxfYS?%Seh+@d!WX}sC}!ZtGVfR|N( zhSN-A*PvU48I2{dt8VsAoU+hy9>AO32^VgyJ`DZd!!d=j6J-ByVE7xsp}L3O4p*5N zB3!!}HgRnUH;1{!c07PBGYGXCHPj(oy&V!)Rf!ws@Mh<`KGm{TdV4x*2=%gs09G$+ z2guXQN)h0{Qw{TrQBs|Z&lxzh#N1v;<&OtF=kGw^;m}K=Jo3SGnp4Uh2=@L&7LA-A z%{#97kf8Qi_~iao4CG8VBkUhX*NW`#ll|)m{?n{4g|$7Rd@KrTDGTd%H~G*9ObEmh z-fTPW6|3%bx9jYPH(L-=x*sPXZ-;eW*pmIwO|c);hy-OF2)Wf; z{z8AjVGao_JCOsTv*+SQJWlROUp8?x>TM_9>~31+Is)+>g-S0KAA^SMD|Vu&vU|C` zrL(vSz;+fLR;|E*lXP$bXA?5FH#p$Lo`o84@=nEUEg#9{y)l4jZi*+N^xk;fJ6IRA z)QZ0Gc=AnMafE=A(tEDoq-0(9E+Tx8LS{nmFbTzYB@NHa)v>w1Fbn?F|q5JyKb<;l5i#NpmR#>q7Q6bc&x%hc>t! zgT{L8itMg7M%diSfRw${bjs2|1FDpkknIRn*DhC=TV*SvN;D#_&iTf|Lm}^wUMe)n z^xr{CqEg342$j){N6pR}bBo-9hOCRlrk)uEbJi(}2p)8Y;U z;X}la3TO7kkm!}u5b11JC@b<~7J$_&=K}=g2fc$hurc@_<%f0vS3lP$E3oFP7zvXi z0OzV|ouS)@y`h2J$WFw8PT2sVa&>59CJmIdXHoqcDiTL)v&V!bw8KEl^wCw~_^|8~ zSj^O)fWyDVMl*_Q4s1yN{3I+_Ww+DDX<>C$_DTRV57-T}od;Y4VCMn-QGr>5Ish|k z&2c_ne%$Hxe2gs36W8s1QPMpn`Q z+M0}1Wfz6hYUc^T#ppVT)3NXP|&XK ztGduxCn^%VmA<>txJc}U1V&;n1F#Z%1%Z;-;;c(Ks}^UggU;d@NU+Xo3A8f~lr#V{ zG&yv68b8XR%Tia4M(n;s>^MM_EmpCcMf)W>cJm2L>=x6pX;0b-0<&d2jm=tcex>bEtTw7Ae{pZM=Hv>0E2GT z6`(&xp_d#5VXQ`>uf!rgC`vbg@)F+c$q~0^-ds#Oz)e$a#JLb}_N}mVUPzbD%iHLx z38OB8t&3sfdD<$9B-zd7Q;RoS94S|}1_Qkd8@$9aduzm_dc>z1Z}v{y8blR|4>bp} zwMR9{5Xjm|vj>hgG<)~>U5%>3;qUBQYx(_lr1pFIE&0YS%nbPb3%uDiSkhe!X@wDm zC7}Ne+9H-%o(UD>Ufe|ziHi&BJgtym58%ySqr?wsj|2CjNVJ)}{j;5ML@3OO-)f}3`^{^B#z&~u_s zwUMFp0)KQ{8;Q}8wl{%m-cbP%JLd$vtKhEs!@EPy0BCu+a%jG>vtb*{;d$Mk*meqb zfN^YvYZ5;U?k3L0tvQH%u1(GMGV$|36K}A}RpOS8^q&l817umegI?gS@aQ^vB)!1B zf$r5PRB#y3^BRQ-wL=N@nF zt+-qL2v*uYzY{X=$^y4~@YA^b9B=OBgj>Bk#48u}<_Z7?W7etoeiX~u1#aR&DE05+ z&AlIUs}F~^|0}$?zrceJFm})vqi4Cd6RIr8&S##i%i^CgVOZwXuR(hoZ*H#wOZx}# zz`3B!E)c=p7xqp=-g;B;!>1B&?wo?ScMw)pTEctrZ1TMi1S55@G0vq$@#0k&xPQ)i zaR4n`RZwZYs32k8UU;KVRuW+|+G#6@C*K;Y!lfKi)8-P&9|14@Rwyq8BD$eacGscQ zGZZ*V{&=bih5Z*53d3_2fVu^;=LGbfbJ2Kyl49}HMkUE)Wivd?#p1b*a@2mV%7-(R zqj<7yhKeDFcGwMre1wT-^E!tihL^Dr`>hqj{@*8t{WmU#sRs~4-cg(Dk5jQEE_*-_ z-GF%fnQ>|8i3>DcCpTu};^H&6>ges5_^^%1snjY|lSb{pUv#MJG$|1Ge}UT6LQsp- zE$#y!Ed=09jK{exKEh>@&={F@XxCrmu8frccGjUAz|1;0$sB4PAL^UAtXpCUY_ve= z>sP_X8o0^TxV_81(G1K6eS9|J?b528kEQLMLy_di+QJqfl-(Pl_KiTeu>ns4FS0`C zFm~WNZz6a1=mtMdk9({Ee9ob*Ju!l0c#WD48GB=L&@;6`YD};;u=A;Ega32H$A3YE z;@^qJq7Hz3m~KOsHv(+FD&lqMe5EFkn}}=o4#R{v9}*1eOmJbQG4me)=Je39PoC)XsTFWOA$TP_+GzV)NQ|KPA^E@&* zJul+4zYZQgdMzG4=HJf4U5GD2Q9KOL!@~fZnui&f;o%kl%fq~i+4683f#Kl}f*=oX z$BZ*P+=;J-hgZ?Osd?D>GeR>wTt{GdcpAZmc(|1o3=c2VPKAe;5m+Af$isY~MF}5! ztm207-FcZ^l^?{*eKjvje8_>1X<#Jn07s0rKa#@_S8o(~ji9_czi*ssWwqsfi1bR$s8q9V~ zYZkz!>4Nr*d9kJj$GnL1#=L|O9P=U}Z_KOzHm)-tQOli+Dz@Vm$N++CajD`PT4q+l zNp4xBy6n~tRp>JI{8~k_Er17HhO1Q5|D=`%xRx9KwSiw{qZ^b zvzmZ+DD+ChvG{73pcwXYjVGf#3j$00Zg7RfZ61EJIp9_BcdS zGL(*aB|}0`JV^V0J%}ekMBYjZSHZz?bYQwnBk5l}QNA%gsPR^cy~rszcw#wRRwZfxovrYW z0PRS;xk(A{>Bm&TN>T5Sh$rv(E3GNzXYYM*M({4vlo(;GNC2zwJK;Qd!Xu1w`y{-V zwMP^`xqaag&%WV9!rnU<7 zSY(b$mX>Z3 zYkL~mK=p?=#_^#v=dE%13$to+%n{;X zju6`%S%?JL99c$Sa%2V54OPUaD$+$@a%44u$&vVi zX$KqG^38&E)AG%y`Ty>gZ!xmK%K3HzBj;B#bBvttCNOe-4S|vK{xh3O&i|LRe04~W z&5=d|lOs(4Hb+_rOpYudFgel&uxWIG@7nSq60A@2P_1S{R$okcJ)}ooQ_ai`jn-Is zErehbD1=}WNJ3r{D1=}WD1=}WNJ6j)lwu7wfkFs0fzmK_Ak%Uqqj5WiLlqN*lx(c% zR=@0Mnnf$9gKujkO74dWIz%& zo&jZAa5Yky+alUqrUm2AAzo%mrIr9wDn4&pXdu9ppwGqM(+F_FcZvhqvjA*|NY%n> zMB_TtK<-4&{VeL0X}!FPDf&5@zuYx2;UOWl3${eR2?fm%(z9^dxL!`o8dZ8hDC;=^ zLf+UUZEUT^CSj^R9cxXvzaqCM)VU`y0m7ZpROb>Wy%}zc5~(I7t4=~Fg5NCx|B9|s7I3T+@9$1BwVafLj*@clD( zaGeHt(dVR4nLiP$PNvbn-JtegrkB;n5gO+pOSlw^4+)ru6f?5>)J1BOOYY~`{<6<+ zanb;aG*^jLKo3AMR|)-J)XH1hb7{YtYr=wOn=3)mb$!*t_=<<^MDBwA$(I6n>q(J}ll~NxHMEXG8G`O?=(J>*W<|VL@i)Dq-(qlrkR@xKcRDmBN;=-qpeori@DK3Pc4Z z&8RGf*+!)uz(!>yfQ?Ew!4HlK+g`nJSx03J{3ZJ^D*i)(sMG=2s5AoDs5BA$;HXd^ z>xs(E$i5c%o4bB|>MEEQz}!=GZTtdmWh7Vdiz&J;02|5G05+2Ghc|sBS#-7VmsNmK zX@uEEr3t`BrG=pzE?PkFgY)a#Mb`#@S+5wC4w!9JIst4{RxxxF73X)GA}XS6EH5iU z34)7Qbd~To_nXmDboDSx(V-e&d3Q)w`$N9g&@ztkb_|1Fk=P0=7cX?Q%C> z60Ekl3pP*phQ}TJh)O#VY3!oMH%CVJT*<#00EbMBlzJL}1j)im{!Ld;CGc8!%WBHN z8)3GAHv!ndTQ*7H!Qz#`7cg*COa{Iz82E}{;9Z*}@L*jmX7yXmz^@-K5s5zvGb$e= zQU|lmg+>6I3rzt3h9YQT;HYj4d|@!~Wx>E#Y?8pgRRmoO92Ja#uL%b3KNd)N9l#Gy zd9Y4N5j4VER4Mq)igP61S5R?yfIzN)C>hkAas#m2(AwJf7;S6FTDFFoJ&8xaucu*4 zl&M*v#8ptuj(8oRLDxx~i)AU&@B&2V{5IqyF2s*$Os|HZ*eA@$@;fe0$Kl-AKc;JH#pwDw~)ad9_}mM z$_^cztTyc?Fx|@d9|3}wM@12Jb}iSvMk;kEl3xoqxg*21(tT|pI3YYx!fB>&ru({p zz=YFI5DbTTlot*Owi_#6ucX(fXs=fXy{>#R;B_Oxcl5dmZgOYn+?h`gOstm$z3yDw z>+ssKCc(x!nblQ>nV35>T%p8FE74gqNp7u` zc#iwzF2EsehJa3`lRF=$y+k1<_;`4?ZU`4+9*cXp7BJk!$XxE;cH}I>e*-ZdUwAAbt0F_|jz4vNK$>{=he3B0Iyw)*sF$O60T?wU+(DT8VryT)zImH(?@Q3=dd; zIGZ4mQIzCTBvRVaHDT}PCo1l|hfMNiIPERf?byv^60FcKGqb}apw8H_wFBrPI5}KF z!n()S?Bwufv=f}JV*{_I>tKj-0yuF2end@L7IB^G1a`^rESFpeH%@aqTcR)Of_#4o zV^N|YFyt38&MAXl*F=*`b<uFNEL(g%E-h6eQ$LPzWJ7J}iXb_%I2<@!=S7-qIQ&1STlF>jP_$5x;nn2WIgR zQU7@Yf07lH+xH+{yvRG}$CBlG9b5_MxnxXhyj1_n&>rzDt=x}d-fXf3o>6#nhhRYh z4=UwD*_OI49Jhy-3L$W4DRJ=7Qeu5*skfQ-WEefU9-f$mF+vC|j3Hj{GLZSt!AG+& zW-)=8KWGQA^9L&l%=|$&ftf#81F&i44_It@^9LlXZ~g$Eoazga!O}^1RIBD_@0}Bo z^Fll_mOop66ms71oixBfz7s-_??}kwJ0S%5P6$E1BO%ClGM5va7!yK}@66=93}`cc zW{2knM!45bRGgo$-;e2H{JwLMpAyUcw-&ihRL}O>4e)VK@zrAkv<$wTu~zY&`CndqjNf-IzB6Mz z^YfG#x&Iz9B*n-0ZA7AQ8$4z+6KCK@)P({Zbr8~h0A7?7&J zdLyKiiASUAbXqF!Y=UjG+l%?aW>>0s8mJmeqD93hFZ2#yqO>Yut_s}R9BjV*3ks%L ze|nm4HS974K3$EizW%OgJiA^)AT`(>di@eyR0@##WjJ1P*X7D{X?h3I1Dc#q@IDKd zRzW)ugxo*`Zt`kF3YwAg+EI^4+<+sMc81%6w2OEfU6>zy!}kfkp|GcVZdCA{2wtk^ zxV3^G|9yfVU)aN58w$P;5-uw?Yk#5#(k2xOH?V)T(9otA`Zo;2Xk9l7V^0+2;W$OH zmH4_>oZ-QaeX%Xi(yt&rG{KoWTB5D=@#YhldBu!;Zmd3>k}0|NsEG3n z-dus3{OLnVAW(VB#odVApGbuTgtQz&;9xApc@0jAFbAKjbbYETEANL5oIl|6yn${4 z3`nGS*1#G7H5g$AFc>TcFg9XzLJn2%Ih|jt4^^lK;0(4sRDn8w&K#;RO@Ecy{#gKa zetSMZ&xZ0?8Lkk(AvL3rSL(vSf=|$2{U@%rjKm9=Npeka?}CXKG2eEk>$rUib~eVE zL@iv;z?=IA)+!tX!({}m0N2CtCc&8ipTe*u2K0010c;P$DFpx0r?TP*7v~W0TV9UB#C?`}m@UPDxz-y^Ww za1bvCFDnVY3DwHrWdng3yqrd`-oeXR{Q6x7FIlbshrvtP=oB2hq@tq+FY~j`4VTE6 z$9-&OZBTnFd{ub*a zL;kv^4-)4t4>^Ctn|lg*^ac!l9|Sm6=g}z$ZVd8=vuL@OapMKH7S$n^xmQE|{FfdN zIgO0+A8^2iiC-CFFy_`+Z~t^yZNk?vx5d(a1xBS?X!Y@;iWFnMKzY&#+g?Z?)={|x2p@=at(0QFTz5&a{S;#wvVV?V33&~?-~R8sar!Oj7#A690pz9 ziC?un=rIrv;5LdNFsD*TdzO?H;Dv51-ob zilafuk6C!>+oWlM59b4z54Y|fa{hr=BGbKB4{%~dlXxm*0eN<(-jYX_XHUYX`|(OR zBX$To$Kz!=U^z?UBz1Eo*cnnbt#&crAtxs$|FToEu3GvTh!F|yZUO- zw|pKyzc0kGq!kety=6SFfRfl2JkIeNcVA2rMfW}urq5}^|)}~#4fWhu%fS$)&acpj!@PUuuj#(9!5_B zYz(o7(UXvs!{`y@kLF#p!T z(TYn>xU$2USG ziwor(xnf;2&Th!eh$@LMT_|cO39+|N#NYFHh^uP2**B8*PeOW{0VF*|F&r1fFZ*HX z@goT=>;uRi?50ww$Iyln;OQh|qSXo05ykmv(eWUMK!QEa{aGV`fK?aN* zPlKE42%8bZN5HU?392HQbO*pJfRRJu#g~J{7SKEZ69dVgqonzO;J5=LW&ST_LNwA{ zE)wtcDcr39!0qKXz*!fa?I8@6nD08PY3<-hd72lv`pEl+WvP-;F!PDw9r6^!jQ`|o zP>}J}Js^U+RPnhHV9PDs%5U3MIbV*PKO8x~7_WO?#4{{U706wP9hrvZNyuY)AqdNR zE#p)?*pZ^62EiSbv3&mqdD5e@V#mR|w*-|Mh9;#4Pu+`2FFBSPuU5(B2G`HazpvzGaR|AahJ)k(vBK`<~dH`>z z8%gt8o@oTHM$+9dx4_)%!?<4wOABd^;$EdCXu+2e-0u4~!qN(w_jhYjFV4YU1%fJE zYvA33Pkfj+y$*CMy(D@wmaw^7AN+xc z&T0k}b4yCjh3MwPk!SCCN6V05WzJOoQoaudjPZoFkHXt zFr14>fG|^^Bg_tfp76x`vcFs{|1z;Wx{p^@q6?b3>FB}nE2kYefR;=y@`Gp>D~fhrTYT)MM?KI04v=)0IYQHB(Tz5@{+0w+b5e; z=rH+7B_S`VLfAl3S0R+VhK!RXc?}r}c?}r}rXj2T$uUsiM!?415x4qg05;w3Yiv0R zw!|qK@d6T7{1`1qynq%%ki&7O;7J%Kf;l68!S)c(e}qVgqzj$}b;j8+_I48QLQ`7> zZp8^EZtSz^xL_b6eyu@!jN`iB2jzleU@U^bKy}0WAXGMKkTPnS2?lgVF%~l{@eLTuLaR*FzM&fnnh9YJEY!@tq3AK^3?Pe)C zMhg>Caqk)ZeGo9^VcE%$hkS$pnRq+|-?CDCq)dGJBn(RtP$v5G@o5zi31q9mTxuoIIkb>wlS3T@Hix>2Ob)FfFgfI>136SjU~;GtAU}t^A87%N{C3=v z!Uf5xT0)aB;;+G$81=|;=Y@US5|fZu*@X~ji4hzfNK4!bU|QmZFx!@R89(Tjcm>U- zCGG++E%9oYZA%=-FqCbHYYB8q+yJv_iKo$QTH;v*x+R`ZvuTMJ6Z~(q#O(}deJyb( zKAM(z70k9J=0#q%C9VXpEpa`8X^AHT`S16tx{_$K9ScmvpRPYD-V-bj9nH>kh3 zXNSuzZ;+738$uA?u-cz66de73?7aziR7LhaT(`G$=LXVEx*<(iLc$Ut>?i?|9VCbt zP$IYjK|nx7L`884h=Qny;)3D=s0g@4Q9)clM-(^2opB9r;5LIhgQI@$d#dj3+XNIH zXa4hhzPZm+-F41ARduS)sj5@Ut#YkDw(Mg4$rUY?_{DJcjjlWR&6ky0p|rX(MhRGJbK0dtb?&};ilTS9D?!mL;y z)07bI_%Ltra_u&DQfYP@5!!BRGU7xnh9aOShQS^fy<}H2#^!5C#SuLt==4Ist~tWC z%MD*tTOm2XFeZ9@l)k<|k8YZPWDVN(&)L4;?vFK{uX(|&m$H`oW10&4LDi3-DCQXG zl|6caSN~`)P)$)fy}&L4rWc6TgWu@|N(i{Uz$ijaFEE{e(+eyB;P#U%2spjK1^_AH zB4aAO7ufo%y?|J^Z+q(8uUNM-9@~oKECi5VU>5+V7l>l8=k@|c0GwW+7yV8zFam(n z3rvCE?FHrnaC?Cz1WYfm7JjD}*h0V43+y0ZdI5!@r(20~38Ymb(eyumJl38G?W-3k z!%L?Zm;k@q3se$t#$$^BxV=CX0jC$(1R!0m|4J`Vjo2tQS2v)L%6jLwdx7dd(hDHa zK6(KjFJW!lvljp&y%+f0pX)XS6yCo2o=VdT(9r30v{eC26Vzmwlh15eDd{`Uk0Tm@HcoU$_}CoUUm*LmoNbUItH0bs3g5Jm#_$c ztGiVMjP7oN-_hM_`W@ZfMZoB86f;w?Fo2S%mLsM$Xj4t;aS1 zk3<-=dbIb{rz7fc{uQvVx_pSDw- zyhjlRH#+S*?^o;8o#4r<5qt}rq_`M5{Hvi`_YvO1^OR&gdGgm7J;IfM_j7;1H=J;c zNmf-NS8P%0C%BSFu_p5A7)u>hf!73XpN$K&(EQ8vW)!rp{8WEWU2#~BYzCFEOld_T98g@MrEA&vLxxp5o?6T6SYKxmPy=`b5Pf2cQ8#HTeQ=z z>xHP>L9{4eYV#mW4MUsViH>MSAzn&?xf0o8gt`EcaU$ciBN8(}&!;!sX~XLzI7Q5d zjp1Hrlx4D7HA1Kd5KG-oesx-9d=6sS^f6+XSx?M>9q>D5fI{;sWyDp{*UI31f4#I$NqFTXmW53na6~ zTB;9R-)F4I75LvwKaM_1zKRMNLELyz0CJfI3S4Y#>uI)rb$K}EL?g&~CoL#|GX1k_(+ORK5D81GBE8=Ba)VEBh z$Bw)US|Wa*)pvw1M&|f%cD?UNZ0>1JXe8W{H6|p+*unf_)0_pH!54ZMHaJ$)c&Fbt zwOKfNhv#C%)pJ2Wm49KWsTr0%bBY!qYdYW}JG>!&c(KTPzQ?}O5;-kzq8g>MnBiu;swav1X8t$MicN?!Y>sp zV*=Ja2!MZkx5*HvwIvV3OdbS*Jg8V2MlZ)CxNgUX*$B4H%Hq-;AIa83?&1YOS;9*^ z{+bQ|;oy$PMs{5j0pU6`GorDG2cf@Di$9MrRm=hC<6xQ(W32ODBpExw@F^*hPZe(h znoXqd8m+YzVXNVX6+007j&{LYr)g%LDC5li6qaOPD*5{?w1HtQ=Xs{LDLfl?!O<4qSMVkF73zIJY(RTdSen-BcqY z*qqz#JP2x>J>L`zDMagL8ibTHYtH07YK}_Bm_@*x`?2iNo{TVE@9fOf?+{6i=^5KQ z^D=d}mGz&RdXZ*pG;$kWYYKg~3O(IfnyD+%luN@6qXq54MH68|>sgq$Ad#yerDx%$ z&bFeL%*V+dl*kGzp4Jpkeafn{KTUCztCedR!%J3n4wovo0FeIBo#^jCF+OS)x)c3G zq%DaM(Z{nSBCuykgvv=<#9a~*#Jy3QOCo&OL((RRaaqJgh+V>^5k53YWsXmlM;ru) zcw8dkLkdwQE|a(jG+{9=l{koWJHbA~=vgbgpZca1$U4b`z|`Au>EO_G(9s@tjUaZW z?F{Hl+iB39lanO_PTM(iazu1==H%danJU_oDIz>f8PH+Mfd3w*RJwj$VKv$x{fhNB z1r}yjZndKJdB$MC@{O9h(rO+%6H3R2h>izw^~E7!-Jg1qRp62kAtWkt^Id-RCfw91 zuwp)fCwVu3pD>o2hDwC18X{-{gRmTpBNoK}&D@Kz*&Jr$`X-ltV0L6|wy$`5rVlC{Mp1XzJ&ZE*u3 zXU=ph0cXy1Cjja5S!u!_>DE`)7V`n5SC;sY575y8eM;k~Y@8{BfA1S-;!CU1agj8? z$iB{qoV`t_jsAME1xDmVbnGIN(V^Ph<)??!;cZ-QmZ2HV%~$3IRN|6=I;DBy9>mIr z?ZqiA;&xk5Ih%01oOruGi6)jA zf?!^RI|XBOnehtcH}G=;V?mixz2HUVO&nyr z0U76DE=ApsjC~Gw>I+ts^|%V6I`u`X<$tI?Z$ff1P-myOgMeF~!ykLM+ z>vI_a4wBgcP5`i%`dkULQ=b>X|10&milqBlpY3~$CbDBabu)H;tTPDHIXaqZKu1%5 zUtcMrsz3_gKupE+AgcE)d-Wx{4WKP~>ZexB-ewF0B4iZzng=1HxM#cw+M}-;W?g&q zX@j6P%P6R%hCP~waW zI%cXb4zJ8`L^B$~`}NBxi9lonc9;AGO|@?TW(h+-Mx`%riuchlI%t(~0KCodsRHs6 z%EH^GdWTZalcgMw$J>?kW@Y>X-W+aLYM?^TGJK%$f@>|+v`L87y_w1w59F=DAf{$k z#>s#l(vS-A6(*KBUGO#*K4C0`_}-uvGkHf)!DGR!%rC&^V1RRR4mu<{20|QIgWO)xn>-tPX(pvO1)v zVn<~qoJ%a(?Z(E$-F>ozTiwOklGJsl?9;vX_z_OK$4?M@Jyf3Ypp-YBhrRaT#CMcc z5G_Ks)&h`h`LLmV3*U^ehD4di9RLQsiAfgbk=J3ndCVnX^4K1JH;)4Wc=N~#{d@CB zQ`MVC!fAOFgg1{wr0yz=Hb6#3ff3(GYj89hz;v?9jJ%1AEFdrshkQQ)O_KD#+TavP6X?<9W>KP!mjsjS|WHiZETz=715>pePS3w_qw6G%k6_7&SUsi z>JL%4!mspw1)PvYcfbboKsM}AX)xCwf|eESVEiei8@VF1gGsF3v32wv2;lJx4ba8X zdy{WRl!Z5<>D#5vpJ#wAbvveQ_)L zk4mJ6$bGq1flSNh18~-aO5m3@p>?1t;|sGva030#nouPGXH94k{O+1i6##clXcGam zCR7c-vnI5QerHW6+7y6U6Dp$LSrh6-K;~Zl&0FyXJ-%u+NJsi#B6p{k4XPNeoZyWW`Y8&fnS}8$H z$ZCuVx&+mN4-Gzc_I4-JZgJY(HwrUVGmttTnTJo!s1pn&*)B&5z{Ol9ns3#PCIGAe zP^WuFUF^EkZ9x!Za*$s28yO!qJleR0EJthK~ing%>#h;X(lU1b6_# z5hf#SLFAa)0Um_=xv;X^new4s<7;Hqw#gkIBGNcycG5T$gg$c3?$K6only(fLoCV;n1l;-BqTENCTnl-7D?2vWgQ#-=4nB-6hV{sYT?$&9+~|ul&>=7a z0`1Y#OaLIe^_>d@*%sn$nR|nvTd2!l*O3XroDvrcn%-D~bwQ+EV8&H41pqk*BZWmK z1!Z?Pr6Ow72~%$448uf7sW@GrAS8)cPopT5fv=|(b`fl&h_F{tet3ih6int6y?kD~|#d)Yv@qx&LXy>VBshtQ+bp5yNTh2wk+ky`bMC_TArEiC-34&pVRLsI7_q+R<1_BC)CNo}`CiD1b3JA&{i|x{ zaJ6P9{IU#_m}lnFr9*uv9J>&2`4H}S9QS&}=OChR0Rq1ij?-Ssr~e~uE|tJfb16>S zri?Fs3DlxlGX;M0jqd`|h&iKI1P(*g2Y|endYH)t%(72|K;iQ!(WYx(#G+DeGhfE>D9nFK z8LMXgjER8!D`jS>RmSN6GBu!DldeIaH3=F7LVN`QaS*f#Mt=ZFso;mOfI>gh46jsfkJy3l*a*{g?qI6SO2>yBJGea{_A82i~o97vs%$m0D*ey)MK| z`p}sM6|-F2atBwM!ue(yx|tfsEcCt5;EvH}xDmG)xOjUcK01YKIXj^4BW}FDv*UZv ztp|>yrAc%Bw%5Fxbcw&^{+L&8AleF(uGqgox{SzXVPr%L=RtXn+~H|b(Mg-R>rd2^WEqT-#fhIXSD|#Yw65WOYA3u|xhinu9K$nyK zyyovdh$XoIcQ*Pwh_2JIq3OHlQWRZ_GQ##jhT?n#;kj7$d8SkZfo(vs(@e2Z$jQ5K z9c#W%7Ym13$$Nr@IrmwZWCaKHfAH5;(UW%LlX5`Gs$lEr3;)0;<$QI0ATMVjlKxUY-Nm(1ncBB;=nh2v zEMF>qE(O-FV^aI2Qz@{qjVIxa*u&E9Xf+}HCC0qp5B1W}v z5c^aOS8W@E6e%^?AGMXTFZuuh9uGE)J`RcXBJfzSUG(!^J~aw}NbEfT(+OyaQ6>vC zVKWS|FNHF#04PVOHHRW?AkZwMVKn=0^qK_D@HL39gXZo8(C&sn^n55&_(QF^?!bv- zGYnCjfs+B9fs+B9fs+B9fs+Q^ffGRvoLqen1U8Vl`aneLYv`7=f8m^VTV7_ ztx&>z6jpL!Fgx1fM-1ix)L&+WYp;YL$_PvkqYZLu2do>Fye?Se)(+7%Z|z|JmR386 zkkW9g0EeE*>w_)bDnLU$tqQRHOsfJ!q>2;(<4^~{-HbMS3)}6w{@9u$bxE`FoK(-b zT&fSCH$V|VFFC1Gii)gH>g*54)Nmb)BYGlIkw+1Prpcrs{+wE%nt%eCbU1=IDX}df z0v5#kIeuCYql4H?_6co+jP>ZlzCM+^%QCLdM~1M+6y8;^Ci{rjH6Ciia5$L8Ll4=% zD}6#Az&u@G(h(`#slaic!=x!G+|9tf%&?16xVK2huJJK+d3PNFX7rBdSs%ML3!B=y z=#K}$P1=$&8wLZOL0qGNT%;_M7%dRjh`LBOGh`pX9U<``vuaXSD3HApR+@vTI~FC8 zx&9pXtT-p>ethVE{+F;j3}RAgsFu(>h$D^yofHFApbW`KmX8h{(Eb^$-mXTH14GzU z@GeZT&~E%h^|?Opyw5GlZop%%4ya>_k!Y2k8NLsZT?X9DgRw05vSt4b-}r%`Eazar)h1<;R}!Ae!EQwT5((JFTLcBq~udPe)szqm5l$4G$i| ziB>)syRnAlnuLZgS<#uGHa`o7FTN_E0^jOPoC4g>z%^?P+x4H8z1w7BAVdCy<*S2{ ziIOjnfp)p}-#q;Gn~e-?^B`ogB%Nd~GEjpA?A5+hv&W)kBDyL}1XOZOK>hp-mu7v@ zP&I^wlmkIuIL@-1KsGw%rWev5E=QF^Hs+cHV6=0|K1cxU1R5|*TIFp#$gi%z2Gc-=IW~DRUd@NR>nw!KCt6XmT=f~qCt1-bS>Hkc zVWVVw2LZ4wQdgg+vzv*i(%2>9Ut(96>78Rm$>u0BH3Owb zcISH8UEyVS(;n3P|e()(A~)wPDDcNf?bzAv<*E5OwbGBO*5Sb{B&@6^e+}-thHAIk%;LsIU)+7RpFQ`Fwcse0Y3P2feT#fRCrQNMTHlt4!+pJY9R0k zRY&IvO0J#MzE*E!2~5!+lnesy4B#Z>S-!NB76KR^==P4);x$llG#EI~haOSSBA;k> zYX=@yp<7U)O>@sGZazg}Kk*#4j7oFAiIP$i;8?a&rUO6ol<6n{-ZCZmA8+1O%`%nr zCnDBu52L-IO!=?@3M7qOEB{;`RNk_#IHM9SfYU_93SvX@1B&Dzb{@r+OF7G^^=EgBU%KZSZ#P_Av&rz6g8 zhAZEwrvwm4RRUf|+^5)j^d<*jI<|jE&`7^$EOiE4`GbBv@4`;v-M0D*#`0}?Cl(Ey zTJ7-V6kPdiJ;%at6w3h5BJN>-^t5dt>ZMfqI)6C+S5)v^0QK$<$6tiMJ^V*>566F* zg_HZ}?-hvWKaG(Q{AE8TqZ7Z!`LXbGVLdtv`=k~CIQ%jThw5Rye+7URtHa?qH|=Zy zFyy5+vS(*2{O+EeodmemW%$b|)ZPHho}GO7-90-c0Jzn~*{~2&fIa(=2=BQMsT?@( z9v#AIdvpZh-J?T9YL5=;_F3N}qevQg3P*SQ{b~Y%6TmG$39ST>dr#Qi3?)qPfI&QQ z`$BZ_ASnAW91mejPZj;Y6iUENzY-An@|XD}4jTKE3zX+F$Ql~3444zPQJ*4LIvQ{$ zHbumq#ij_j^7)ol2ddBktpaK^TzM_64#b@V_*&u`r*O9bevLR-{6QaLkt$0Y?sc?% zOtQShvim;<4)AcKU*6TK7wh|o2XPjf<=6>_YrZoalF0@k8R=@ZKDCivWI!&KN@S6Y4Kly_;b!ibUS(?`J=7+ZekqX0D(eEZJT6HKSJDW;mhZwa@x6d zK)t%1#gxL$0`6Vnu1ewF0*;K9-;~0&Dh{ane*@jp6mB+fufUbxnZmsZSkkyJg=^Wy zr14-1cM))s#)cH`ufRzfPo;2OP^l|lN4lF*xJ!YPbT?}pEBahiXil(}uTPDX8Up47 zYxzcvYYn=J4yIfd2iR50C}<6E?B~kOoMaL3-=gu6^7}{++L(r~vx)D%@Bsr7ezgg% zywYd6o#VW_O`zE>>Rku*n2YLskD+?bMP2HkUKP}AB=)|8dP{}oJ}>Ie=Jb3~f4A*? z9NB9Vf~Xqn>`?Td0oNE=D({$TPg?^%hBz1&p(|6-U6~%;Gsrcs$|#?SVd)_Uqo(Of zr-Ury1_adKtnvD@l+Rd75x%JJOQTBMzK1k*EaGrE|MF5;G zuNVAomp1}{+vQCG;C6X)0XSXW68PONZ!H0*%iBW0ba^}Ace^~*7t-={c@&tp%OkvJ zm)9RSZq(zB0kHsR6YB=sich9~+s3VmLk+^MiiTNdKZ^l>cUCG9&{V}m@a}(B z(wmVLsETPqTxEni^Ti;h1g5Ni4aG?yZe-XAtNR#th-oAnJ}E6T9I*p2COz5lhXO5tWD^ z#yi@oGtP}BYUAA~HROUr^vjfDr z$DokQtI$XG2>M@uUQGuq%62{sdb?-PzXiyxK!#q$PdHFG4|x44OaPz4tN`+EU;?NL z88_kg0S&0ud=n0Yh{NY{w7?#?OZI51;N37F<+GLCb@1`KSNn0j&--bbmdQ`n=`U66 zwN^{!;Sn%;=dA(R%Wbc#ec1vm+13Vkk3)3}61Q#8;va$N>?exdUVtzcyWP?`6bO$&W>S^>>F@a zk_qbagC}vIX{I>OWGRNlb2pK z^TMj+$qPX@FDlrq1mZgiKjuiWUD=qzQWO#BQWUBc*3tPMn-LZ zo~0K62u3afo}Vk&yx^wMqLy73;9p`=lW;yaWw*mCyCHa+COab1WH%0oblE)%Oq%Ro2f`ye4@lX0 zK*}x!itHTFl^qdjvikstG}$=_uk4V);MfwB&=mZj?Oz5&!&BMzhcAryRVK?))Lv%1 z*tvaxavHT9I=P1i!F5!eK9tNQ%*ykDq zJ7xI>_chZ~3PMgIaxfVralXNgu7!u*l$^R55rHB$8KfmeXHvcHVCt#Gn`%F9#GvDXnSmi zdq6c|ek|o4P%Q-B1F8k#IiQ*_KAdt7sOBt+oW0>3P%Q}a0ag15vg3R}RYu^yW21L` z2CTv<;Kx2G9KY)mnBMSDZ`mYq#Oufo9%{z9#aUwVJMh`@u)Ar3@3ji6#2m!Mhn35o zjO|~Dj}PJLy^2(#gV7q6j6J0wYaXf^AKjG6aH|^W>rPijFn8kZ!I0d^l-^aY^g07= zFHA{~aGLalz$-mLc%(E&krcS)}V{Md`M^d`XXl^zEY zUg;6`N{{efrMI}I^!WKS20*a%&w?;$-P^Y%oa5YCTJ{}z?rH7(~+g^yhSbPY}Jnw-Xf}Gp1 zG>VU2(wzUmffpe`R=%Vosm&m(bKPz1gj;->(aPQX&Zbtr z`*S`m6ome?FwQG$O33$`Se&=jjDWvSejv`9YNpd~?p|30zkCMFyH~0RpkneUwoUZ2 zV)De9odnzyXL7RuIVVW9C*YhoGZ27#;>;)l`~;UL&P)g3SO(x50?4@>tHi+CYqO&} zo<-vDbIv`^>!r5Hi{dD+TiOYK+EsukSh+Mwt^y3#!rOoGD!_ckQEjdQECC=VOuQP$ z$JhFezAS120Qa(}N&xOZhl`r5I~x82ftsByE~DB zOauOeKC~SM{dQw3_Mqt|I9j!vS}pAHk83GlYC+kBRy;A>h=qvrCO3(#GuAd?9utc{ zz2U7NJaSDRWikpZxZnIwCt$w$UjV-&lNIzk-~4YNU}UnDen%!d3H&Ey62@40pE4=p zK-yf-*9(4ECL;(qGMNIvmC0NJj!c#SNRx@)A$%MPZ2)9(9_7*9ij6@l#3vul?r&wQ zwl84BehZ+>LBV+->;#XkdjU7AovWvW?deu6Ir>X0sXGqr7^#Gd5x}*YT!fKV`#K(Zl@V~|wH{%`v~jLL za1l-&au71w<8_KI0%a$6;5dj>`Nes6ffW)hhm$8d}FVFz34*pZ*vK}fKLIQ!a!sRfa&$} zapn`q*7D6;I5goFkX?@1H0g`qLwCIeqz+MMpN?>BDPBfPzO$~;ycaOpm0Qnf zUi3Y@>P3iVL37M8j3Pj@APJxnfYj1Q(Y7riz*_n@G;A9HcqJ=y7AGUU%{VKC`5OFH z#D3@l&BtWm2Y-!)-3wtfRbd`+@F$VFwZ8-3 zpQzp_^2BynDJpNqNbm|*&=EH@J`B%f0%ZW2W97L%T)|iXC%|((fh9pJZ#g_461V`s zH}JH?OkctIAbS*^I|=j)S_Md2&4Zi&rMa;1TL2$|c{{dNw`%NV3c3ff>@{mrh^Cij zM`NqJh|EkBRC=I;{z#y1elEq|_)nK07J3 zp}11@e`0L97uEdl6JxaZi}?QR4lT9#-7D~o34k$w3+F6>zY=~k{>`L#Des?Z$os_q z$s1+!e@NboC~rtjF_ohAMO*_5mhp6B6@WY4QY{3P%D?HO6IJ7UQ4B9cL1>oSM zU}-R-TucTrGlS^aM29%<^ezku_dU(9f<=Ld-gj^?peKh0RMs$joW41b!+5L7?@JCv zeNeQ-+sUNJ2)gkID`BK8Ju#_ffnp=6+U`Ns4phPn7vMS|E0WAECet6U@*Ww3FSOwb zt_$eB|JBI;+lZj4a9>!#Nx`VwMq(d_l>YzP$p0gC z#%3GIM{E+*n*`fQ2Z6RS#HvJtO6_tb)spX}I$;(~6+`()u>!0O zMp-SRm=`X1I9S_NWE!spUQ3FIG@DHj(lM&&w>x3QGKxon3A?p1`|=sZAy#gzkq6Oq zFs(dQ04LV|OjwP1<0s)W-^+o09+u`mCi}#$E!geH?B_+ju;i`RdSBbl-QjtgFM~x( z;tTOfOnb+ay&k}}V~i<#H-JvCPsNmd!e`~3>=>+n_vu3#*&32*msyrf8nZ-bW`)-b zfcJn`0m1+tam-zo_9g%^zUCvPeGeAwrCAyZ%*}uEyp91;@Vr%93xl(`w+srXx8Mps zvfM~Sq#uJSZ`ScXwGOV}Ippdo43vL{D|j8bvPbz;Ke&QB0hGaWIe|;fE!kz@W(Q&w zs~sPtkqJI!a0Oj_5&KSqVAcw{`J#52nd%qB8yNYv{YnQRf)nzX-u}R3k{b#N4)R4~ zYfUV|a1S6h8iZ(RPhV8$leunmXh0naS8${+J)gs|TTN7xRL6tj4pL1^QAu29fJ%y# zb(g86M{=3-nlt_6D*g3cSVMMl%v=@R9SkFDL{5V3b3|pK}ldvEz0yZDTdX(KAlP6=eDo zy68ByQy1jJ7^FZ4QOiNmbk87#2$C1BFtx0YvsoywJ}MT+r3Huht-LcF;BWv7uQqS$ zhpfDf(8ZHJ0NF8ka}zZV{d2*RknUZ-0UM*if<)BLAI$*g?a4+5e4AJ(%CCxKgv_a(b<6`}?W(^M;jBWZ!wjyMUrO*L;260ZsT7A3=>#WImo^Ssn*sRT z30F|IXTdmu=Q@FPZKoN;njjk50>E8hMM_|d-xauM=vd^@sWU`qfxF?F4l&^-`=hLD zE11qH{zf?rvjKpn&r6Q>se_KdyBkr$QvfV{8^BDzF5%M=@r{T{kT{j-rmuCLh67(P z&)>*i;6=>x*UC8#X>Da%H(_zE#5Bfi$cS)TXClP#-IJtEO%jkwuBO4$_;AC^RsJY> z*~yfy_BV=>kMJD;93Jus{Fyw6a7Tg%CMDS{`E!#HjpPK^GGvlpGZidLea+OVOn;?R zaJ&ALu_@@D1x_^gA-~<USZg06{r4pV=1&z{{o8}lnYd%8K`osHS=K>KS$ z$_X2F{{RwWJbMzBc8*OELMin}I|7-n{; zz+R1H_`Jh%u|sho-%4_Ss6lictiPQE0-+-N?K^!!nt@+A6n7I03_gO8LvbZ^bR_}= zL-{F#OH!*9Du`}Fd_{as;57if0LX&fGXO>qIL!{j;&a&g4AFx)9{U^K^O0uF7iu6W zO<`2vGe$o7kQ4GMZ|CwY`OxhaO^YUIS)`V5X0`4QF!T9@ddjNZH-a0ZXGa?MTCejuXw3p7lSZ9?`$G%I{K@G58@!u@!N-$Ae`vzeBIV0sB> zX8?oH*mgDs5Ox>mrDb7a2OVh=>#|2;-Tu793dkQzDic@3=6yfGG`5GDJh#A`)nG#! z+hL&?srax=3x1MDwpaX{+s$)Yrq}stUKEa{rih_6;6w<7Z3%RvZCfUY^{x`{H z`kp=JfB*X?*<8teOAQzwYUnnRGNSaht3;%Ym;|wxsYGwPy5E7k?dpC9`v3DRcXT9M zqg5icaP%xRUbz6qT!1g>Ggjh?MgZOJ40Md{M$JW9x&>nk(P(8Nmfg}c zdYM2R{EDq|W&<&b}2TWx&Hdk6rQolJxW! zhH^L@o{rcGW`|K80SquFKI}H_{v<{a3h!v@N|k4>SauAV0y%=ykt<(| zvN?X|BR%L1jS|k3PCcLt7B_P1d6008Wsv<`TKQk&@E@NSRPGcXt0N`nPQ4M~o#G?x zSRJAwM?=coJz7!w>ACG&R;z{--o%-u1t3-87{% zoPOYXimNn4c$J25n$lDNaUqmO=GmT)bB$#!r)oAg+V@h6Xw+V3aNPk58)CiGqMNUl zfY%@ynbZ6z!O18-64NJp=qBf-63((t1XKmv8@Ul0$~xbrI#jx$uYGfkZ&3075P#bpcg%oP_sjYIZZWA^bl&TH1whrkebBH-(YYXkm+ z%X?wB!ngP_r-EpbLeDo8*7S6$xXBPmc!WAwDaMdY#+N$tW0F~I@SR1bJI!n*$ z4nhKV`tjN4dv$fU9S5TDbSp2>C6PijJ25}85M3Z25;PlC;BG`9YjU^g z;%uJ^4eafHf7Ki&0OsWTEif_~2(cXF$S4QEYXC$>U5$*W$A<^^lu%pHqlTv7F5nrWgc{Z~cxHPRGOjo3p}Bdtb%C^vemR9@MO&E zFLQut0A^od-kbp7V+R=L(}JRrx&T6=fms;SNAYwAuKlqFS5M>EguM(Ljn2XXjq3~C zQO6lv8;zq``7UrgR;Ta~eOMj04cv0PHsK0~`|MRAU6F=?w(uxlGn?hihaGC+C|~nG zr_7bTz$A18;~n8^7GtgC!wHhYQ*Z?tD)`EnmDgSAnbnli09)3nG_-h~VG9y*fMxS7CGc~R$=$-b-LTuRr zQm|HknCVk_{wY3n4qV}Ze%)1a#;p|^^Blfjz*6jqB^W93L3q^+dbf~{clx%DuaI8Np z>}++|QT9;0<5LD#ILzO~CSxw*L@Zx8ObP{=G!?cpJWNKS-|3A$dN<-?Zf*8MeAp2) zb+^M6gtt#3!fQ7O?6DgNJ9dLEMJ`K_`zSeX&m_UEWN#n=a%$67;Umf6b$a?20m;aFBZjYxo^B7qywni@nmgGl6h z5yjy|?*bj7EeZ0Y*Pt2dG-`Cc#J%gf*^-e?wP z`Gu~zef<9MWFPso&Px{JD4gwY5L^5idDWB02M&hC9lQH*O~Ps@Bknw>1SNJzdIh^|LQ0m06jDnc+-Ju}Nm4-64 z$j@iKH&cs+EmY`P3`Oz-h2O+{=Aa>GYO!7&Ij+D=Ew<8-o?6V;M+~(`N8wB@8q@`T zL6I*t7p`uOPbHiVMO1uN@t;!{6KNIa!aZXB!}UhWXb3o8j2T=RI$hN`fzh;#wI8+` z9|}LeFDR_k#~NfoGB1HtMsv4kb8y8+8oL$!vNMr?KHP^=xT;$=%Y)A(fs3*^ZsyaE z@XCIwfIxpZ1{7Y30c1Essuu*s(j5d8XAufNc2O4s#Yu$1pV2m+j?rl7Ec_^aB5@gp zq?R_*{6Ky@7K54-18UrJ+9V^c4d4@r`$6M4fSe3?IdS#%3P0)Y1-yf};uLNt;I`v{ z8{}7^&o4%%bh2-L#$?6xIsif6f>L*#<5S~q&HfZ`_^>LEyDgmE%yZ=iV4Zm;m#he= zGPrRc$e5j|kpQnJs<|HG5w{BPC&Zna!hHj{IdVGg7JSyj?`q#L&NhfpmZ#W0%MlY=)l~Fo$$a-|A{-dolita(DWHO zUq|AhHT=CBb)uaKCx+6f0yiGQO?#llb>b0(C!Urd=&{;iF;Qybp$&zJA-lT=mUx^! z8zk`ZgCbHFBOa5lDJICw{5bIt7Ji&~1fk9*uITX`4D_M+YZzx=|6RqG}80MiX@skzExB`DKCgnsa&Sm-0@&>}mMZmJwSJbhR zZ%jjzc7{(?@IRaWA}d*fZ?R8?tEg)wKbY=QP0rRdN8o<}{Y6&fmJ599eYgs& zza(>E2Ob5-h%U$fbMzykv2(Gd1+HSem8^e>PmP2l&2;=%(ci~PHk{{E$HEbR4*u5> zKU@!D4zrXxDHjVs7oj^IaWA;8497DI(Vx?wAB~?4`~tx@iLZpeivCG;;y1xxP5;<% zyaDK=Rhs@v;M>zbwn=T;re*Z^wQ+j(YRFnuuHJ;>MdD1YO0oy2Q)Tu#TL7<`?*icM{u^n&-|ySG*feEN!acbMePg{KmW&_}wOwm6FwX z_i~nGrHp=)l?n8lQmhnwDl6>YOjab0MG{A6iDRuNj;)?JxH?-gBoznSSSOByR${vm z-~Y8m6rVb(Uht=O8xfG>0pg^aB6J4{-CQr-k`&z)$oE>ItCd)Dhb{x|%&E8`D;C(8 zg5|{C_!z{xh183)qQl|e!HC9WhNA-ks0RVGv$LZA#26-*K(3va^LGI40qDUD>Xeg8 zjHxV6r9xOzsm(R%fe2D@W0n$N0fDE*gigMBjZf9RR?B-h{;#0Fy_WIqP?hT-_<9hRzz;$ZZW;00TZ(We&~Fr^l76EgO9Y=1u17&oINc08o0(eI zW{KwwJA{!+f{g$ldB3A5!Di8gJ&nPWKr(wyV<50;3^tGh(->@}-!uk0JzR#@5dUX3 z2Eu0Is@a;~HstTKu>GdVUmUQUR^zp=E56A3bL?wGo*cN?r{=)1op>7m>PFF<G}CE8(Ylv;h4g;=jv^=fPh^Kf->80@y@9!VW;#YWfitH@sqxdrGzP;jj3*ov2nX z`i*LhqTgwI1iuf}%5FVN7riK4*Lv}ZNNov2bZr)IkJQ$}?eCN_uVE^~Y-4 z7II)}+Yb6oZBy$~T;|gMr`ERY^I#A1VJBL#t4REbvrLiqC31Jz9&PgL);{kzwBnz8 z)V@DF4n^&|^>!GGa23^7GK_BK5IEMjv+(}_{je3)T|U(lPVo5WslUYUzQ?D!-mCGa z;r|}`i_9n}?>U&WeNP7_ZdpNkA}jF2(@-(PX+@qq%K-TRcEVhhH@yLT0d@q)1n}A_ z1GEOP`ECR7Ago|d*vQGl@UsH0qS%u2hm+IJbP>sZ=YZMi@-mrmkxzY6sr|grO7AoBdAJXXlW-m;zuxJt>gnRzkh_QC^y;6fSqezVt`0% zHF*hs1ho(`(56kc$B$r!07IKAcs_oT^YA0+TdiaimYMkPxAd8BouQr)G_9npxF!A) z%&lFt0&i^`KcmoxQ6~JT!?Yla=)bL*Zu;mqP2UJZL*sS2;8XRSbGXK2Qi(gfT{v1A zZk#AyTH(VNq&hR!F*yRCoeMo?N;*O>y3YhmE3-V z@qdO;k6(vS&*G;Es4EV{m<+wz6!vWJAA1Y53=V!3WOt^u_;~mvk*}@fFL*8fZ>(h9 zrN)n~^vMl38{jJ|xoes6|6nDrzSa15S;;<5Wy0B;L00tS1uM+k56tHaMJR@bCk3>= zMy&M3h)gU-T;D_&)U7bJDu75_?nPiRVs(Kg;CF9OjzrwRGDV9i+nI)5;7qGs_Uf5B z0DmjCg%jIQIr-eFVf*xE8Xg0fleXDiP+|CR(yZbG%1R~vW&+J64yl}JQf14!?Um*%ExukQ2)fJmdEqoTk zak(YI}zgiIUhXxs>r8%4q+VTsXm^X2V_Ws70$i)S@+J@9#qaPGP(N z;yd{ghM6WtC^D!3GxyGdL1UPiW#0X|z=WB((5#$^Mn@0WgP8+SLeC<7 zKD^Wnb*XmZF)soo^gI&VVwh@c5>6lhOX%hc5%>{ZLi6{FDUsLTkro#?(&gnWY_w;D z&cen(iCr&jjG`a4#97#QLUZ9RYzXWuY|JIGcVXiiQhOIRjs_xaVWX53-i3`Nl6Z4_ z{}wi6`mzqEa-(abVGc;}_aCe)j%8HXv9>H?-W1*w*VGPR7!R$+3 zF+?8~KdqaY%I=C3#$Ojud^@dcBF56iQvx@wTR0K$z&zfKxmxlCIOOqe%-se8PR{7( z@ovmn_)7r)=A1<{TVs5{gmC0ud@QV?G62&Ksuw*EWi!r*iRQZ2Q1SL%Cax^z;YfL6X!z$ zIggACI0z9VnQ##lqmwR!xG4!q@YSJymHY@l?5d~rH$v=U6f42}{D)y;fOo&2c`HcWDZGe{B6!_&BJ{H?t z0IuAY5b(;a7K;l9^tpiQ)x$h`{e*@aVXffPkpL%hKqU^s33MymR=>b z(QT<}0moID((4;9T4do;bfj~SUXNq6XW+HqZcHpkl6*KoF1;z7z2jLAd@ryPC!5p{ z5Qt4`>8)-uoh*~goi5c)Knc}@()X=Gz(LS)LFHI!UtN|atfsOXtGX3pt%o%lX;xbx z$WjDhQ(f9PwN|ymZxUOsKWJt~$^#}NE3MeKUd~rxo4wl^JPRsez+76++~fxhF4GtL z@e?5Mu%9oru_Z%7vdcIRRKiEhmp5vurOWhSzZGQRMsi?Ovc{AqaO8w!_j`mH6Eb|p z{r2D6>C$A=4XUu+6^$7mLG8O{-X6xhLX0`F+{EQ zXj}luDX*=5#Hx>eQxIRb1Q&b&$XODuJ#jN;mD*vhV+#81!%!2nKj)!k=tJPoEBDn$ z)H&UUV3-3K%oPC6+pyedOE0qpi-Y{VRA&o z(EM=hoMUu|0N^^GMrgO-j_wtf+;>=tLj$DbXz+E((3c>VHuBruJLpi^z?U{gIzvr5 zf*6Q&Mn9jT7}`9QE(wN>X}H&PRo=ZTEmgD%nl;EI%<8-n2@A4`-+s^}oW+C-knqVS z9YGw5gdI*;?T5`uF+v!OWIF{Q@5hKPsk}4qwA5s{(xK2EdLnJ^GTPJ9(Vkt1AU}*x zjYwDIx7&2oIb`K3Z3$M6Gi4x%VPIv7DQhBz7Vn`w{!G!HrqG@R6ft6m_C%Cx0l3<; zRljK=+QS>A9PKHB-_f3d+ArEO0e-LcR02lSl(q=+ba-w=CZxjQB!|`Dc@b&a``g9a zybk3BFtje_iA=e&nCh&G6uXLJ%FPvEhy+G)^d`AJz_4mXS)Dd9a#W=_t5P*1-+MK3 zx%<-LZiMD;7b6(y?;zYoJNzr$iLlQBcR#N(C1Cbgj|T3DI}HxEMpIzY!tX?TnLuk- z`X;S8LDdJ?hp2yKH%8UvBdzo9fG*+TG^WrPzIZd#q|}PG-Hv+CCUlS$kUNf}t+B7< zh_Jr!5q|f=NBC10J_1Nx_y{0%;UfU|!bkX17d{ejFMK56T=)oo>cYojw4|O3A1OZX zg^z^yyzp^6aNY|a38!87C963&a-<4w}0Y{FD2pBn5 z!SBj(6M+9ma;!$ut{is}aO4<8|MshLECPWe$6oXsIga?1fU!wNj;w+#eHElkM2^#d zy2+8_8Cs505Lf9LG^eCZp&{}C428){AjgAzu>p`HAE~t6QIVxpAeD`dv@=}k33_D6 zzVKkcz3L*uFMP=s5BSv(xYF-nCH}=mkH~mx!Hu1SJJI3Bue2hM;2hr1;l^LW3D|34 zrv%R!0XvYYmb?T$dd}>OQ?MScC#PWXZk_8J_+h`PBAnY73 zg2!*qdOQ_ghP!8Y5Hj4I>`6gpErvXm3X&>&q<|+ry#$ja$l#fsa-&~VTPnYZc58qjoD9^4ur zr=2^I;FNkf?c9Og)6QLlbK1Fs5I%U?xr-nlJnh^;r1%h2V%YogFGq)-*(IDfV!kfZ zZa_z71fl}~F95SseU=?PuLst^2%KSsbI$CEz0?5YmKsneRvT420Kl0gVY})ioooxh zyjM5twNWVqG_BEJHJHSEbD!c?#Fx4)F>nyHt^y5YVB^h7odW8>DPZ>#&<7iX&0tgh zw8T$nD1Iy}qdoq%f-jixhit_Oqi`M9V1e)aQTT!vt|LAxjl^>O>dNB)wDVb!5ddz1 z>-bN+sq?sBEgpk6Z=m%K9Sg>AP9fv0>W!UrDl+13*voJo%W(~FDWZ^Q-ofEbqYz3$ zo&x}1vg*{j0T^+brTI7(K(lWxbs}6xUh2EO&?LPK2NHz7M#p7Rn~o}m)RwRIr=q## zA-@}q3N=R=gE)-8L48Rae(^;NB*AH5Y>pR3wJ14Pf>*hposjZ^Dpa`P~Fy$FYzLi|j1`|3E>u8w~(A>_(O#<8QFY z9suyxDL9P?nU^=Uknw(S62W`l;OGfv{0Wd%p}fClnKQQIkjsT|66Q$c@=`bn^TK0( z<%2{RHRRk8KcPPOft)4A zv-2@C2`3pT!m7jsIGvG$5gSg>U`7}gTsTpv&~COgR>oKOqt1XNRFG8zbvRIl*QbRl z%s*YumuPavu48bOPla045*hHFJ&UJ%g!!k#eStX~!`1iK$UFY&cY}0YV>sEhs>1x! z@1|j>Y{Zh?N6K_;Ex){r3|@h4karkK48pp}1#lvxufD@T?t1_tmd{`enkX0+Y&lWj z0$p^ChOO{CDJ=f!q&qir!_Cu4-{d5H*#r2J7OTLb1WV$$ArnrL{$~T9>d+8?Bs~iQ z5R){+B55ZI6`I`2efO!3{$3~gHqXJfebz*Oe;c3L4kytc-3fc(;B@qVZRtkAu!!D? zLWK^*M3_mst!^dCPt%1O8Q;aPI>V8B6;dfeQXmqCP=)H~riPMvR4%Ix^G_Gg7Tt#M zU6YU`&OiMw2R%q`Sak5z(|HR*n1A}+yI6yW>UZnF7~V~cIpLm8y(2R1-3>huPV05Q zX~HM}bewhZ4qKr2sQsN_wV?*xYsez~N-v2kuYpr>$!=&!Gbo#mrfD9N@kWzsBA>>@t0C)GgDj;KLr}o!OpgFY zm@Y?Zk#|w%HqtLX&u4|smf!47&Bu`&?+Mb6kRo-LVN=jIO5!+-41^_3xgKWst`jMA|fGZ z$FfKfMTTM~>KZpf@aa8C>48w5_mKcO6__9t6Gyo*xKwMvGIIz4nL% z`wfg? z;V}R9!iOO;eAFaTq3h0Ie^mHPjif&Z22wRiM@v0LV2;bm-344A%s)x`WO!0yHAF=2 zl_+x8Stw^XT?8T6+|aJWk&Y>XRw9Y1I$_9#lDN*xhEbfCST9wWf5Jxn-d;8g5s@gU znnaOPk?_56d9TwbyX-MGhJ|mW*f1Kg+wh?^qA}WW6poez`TQRHzX{0m&(5oi(L!bd3%ph7V${i3nE&*jN!>|QraY1Q8C zWy-W;k4zS=<)1M1Wm*HC-q_V7ii}3etKisxt5DW$xTri(*!3`{Y#ct0116;_vovHH zJ6*+kz)DB)^H2C#^OCo4Frr~SByz7rk%3705;!TGVGmkrAshjWhk-`nY_7r7*J(`E zLthORHB%#qqia%A|ky^xkQoT+p!!7rxoYudqsiEkxqJrK1Zi)D)cR0K8ylO zFB?d8pnd#)kLDO6BEg5-%eq97c}V$HI4z|18>BqmtHFowaIcVBXy{kV|HJr#r+gR(K!F<3bpdN&cbqqYu5m*mk__LOJ3QmCVE12nm6SA-0v()JK z&6{Z-TIwS>dGq!RpE~qhm4>^pGvp>qovv z&`!@IiJ#dnANP_cq84RFX=+Ave$9xkN6wh}a}Rpw75GMHIOODSrUR zjt$c$?=nM$U54(d;Ku-ys{NH3N^2Trs2*_5{qW6c9js{@iNpkqGoDWoMZ(aCQaD}V z5Bf#QV|@)iK1|~yJj_$!O;-2hBfT|DFAtXwmnbp{DKCQ)qxA;A&jnOyxr`VJk3^zr zM$lQB3)5}f=;g^|yDm+873QC)!LJ!XHHji^oBPx$aJm=$3AG+FdV5bceokYf@CZ-Q z7&Z>pZ1C?l*{Der8H*}+8=Pii?vcXA7^GuVR(GNo>4cjF#3Wp`7dAfDZ17Lmc>YAM zO<{N?61rHED6$O+w;B#MIN<1qd1ePtq0%|z$+Qp(bkZBttl0dRUy@GAeGY;?1*hxd zf=@gVmF_#DPpWG~^gM%ZcOn{HhhsRy(N+77r~m`JJviEgpurprLZr?57(O?mxAz^< z+4t3GYI5U#bu^r)^xg3M-2ga_Hy@XJ1`1oCIMX|{LxD-v_bD3E_1#pVx|L#)@lP0U znbwgQA|lc5)Fg_`Y2sJU!0C>)ZcjglSoe~TXEKpf$Le?$nA8w!mxeSSX7rRX9~9v* z|AY^EQYP7N5k*Ro@;o@*?mR3b^TICWZh2^>J{kxXhqeqa&`?_QccoTp{s|jxdVAS0 zN=+n`x+YPi)g-@~2&e1Ti8Aspe0)zfwxzKVg6@lgdj|7sH5>dBHh!(8sYw)h2MISg z*6KLQ zaSSelPvR%^HGVM9vJ&||3#;CkwRshow@;FCO-=tFi|J)U_EUySR(qn56<@1WR)wZu zeb$g2!ttSw?I#`EAeZbaEZP~evJ}}Dnrx&QQL50@ZCtV-rbSI`({!Sz-la=Ig+>f< z$$Hdv$)43@=l)>GRPa?yJA^)I;1Zv#r*waQOH(8-T7f-Pa2-yylB*82)R%A_&Os;s zNfS5Bavi3}yC%#=OjL&-)L{=X3G;9ZH_TccronqA%s9+GuY_Ydr}wwiLvRx2 zm`-k(Rg&NE+wYq&a}I$S2*)rp$}IIboP_zfuN!7Pj-5oO*!xi(2J0oqy6<$sgx%5z z{bc}K8g>VLu`u`z=F z^-LH>(6NCD!#6VkNEp636UXkZhikw$z1mvpVmL`O(9XPJI)?+0H%wO_{4D${E z$sA+5^$bgW0VlEDJi`Et;8Oq{&NYmFb&aLEU2Dk3z_Wq?BWQOAHZH(5$VWO4ud#F) zFwr2s@-KsvY{GIKENIs%!C?4P1kVtYpjUa7!5+{d4gDsPTV- z|GY&SKNA1*jsFq+@6`Utj9W1I2-o0ho{O>+H$=lRqI2+nukm-g4ae!i0UtT*cC78d zHJF4cfhNn9ItETcKe-B@!oV@~>^pJ42pmJyyAPX@;3UMS@D$!}LY%V(X}~eW*tOV8 z1V{e`>v85k9Q|M6zxf93f8YtFK7}K`?UPtuhok>e{BJP+AMjuN7mYs#{|k)&*{861 z5{~r4Ho9>}IzNL|R5;;oJ3LJ`0bpr7{(@59z%j%nFDmso9Q;MSrzz!AnCkr;mvO^2 z`2W~@6L>49@9}>>=bU?ndv0~kz1_O!R=44nMw*A)T#`m)NTn!>B0f26HO6i!v3SRbCpTKtn=6@XNBv`My&3E3i@teZ|&Nhee3 zboEylG|SK6b4M zmlA4RseHU8D**Bn+FBn7xf^+e5wB^5+>Jb%;oHa~G#h#1vXMuA6#&`HlPjBf zKK`76e50cVIaJV*`w+tiY?yGC~IlwD9vcGrycn)nR2iC2@jl7iv~g6edj>;ji{ zE#z#?%4|m$t$@_}ezb9Er@|LaC{dZccr4(Ya2VMxDm+i4Gn;j~kS;kMJ% zHDvZlli}1CT=O=W%nu-H4Rq}wrMchgCc2VT3R`kQ0wvMIAXA2vsCR{gV?742rCLK3rla8CRNykmu%8u;*X<7f$m6>mKR_NClf{SBDqZ00~Kb(TZjL)({N7w{U&Y#!I$g*$oi>O0K`y_)s=i z%>{(t`E=%lK-p)l)T$1aItB>8QAZ2_f=}YQ%EpgzJ(Wqg$Pev;9zbLcaIMtU;M2LT z5geJRXMqDEbCm08XB&JX*OfMYkQ<09-3-4A*Aapf_i?Tt+x#2PwbXn-^lao>{5*}v zI&r;La4F+)Jy~}JbV;_o1WkaRpY*-VQd0nlK5dAl)&qh!8EvVn0m18z;iN?XJhp~e z?jf1!irRIru%7{tI!U#Bi~S6M#8B%k)esQ8*lzao0)p4Z?e+%*?`Q?oZGhmvbFCjR zxV+ci9T5J)!hkve2tK7UXY2uj_h`*`fdRowwPEcX0FO;&1>hq<=d%n?)Y<^L#oPe$ zq7X7EdzI%&`v8evja8*SfZ)4XX-HjY@X@ShEdoSs{jWL3577CXy+5Ef0}^5U5q5wA zBJ}N1&g}ce7V5&S*X@7^HAn>2AVBaZxsCfA5WIYTP@NA5{t4F@J1qq7#dU(gV+&Xz z+XCo3lrI-lJprA&&ngGiF+hhDRtc&;fDQ>&52_k~4(Si_xDe8Znw%O`7XvyU&z%-j zy8tm+qjpeT0tmjMPEZ{M1ZUH#ItLK^cCHI-{1Dgb4Ge!I*H>*k)G(-u0OVu4xJDa+ z%N)N6$aO+UGF~_{sP+Mx7~46ho(Hs8pbPu|0Uc6?y$Edq-Ia&+52|^9q~v3+(E$b@ zctuc62ZVo+Yn6cpzm)64Ha_=;pxO#Zs@B{YRFTo(l8~Y&$TpzM)DL?GoTaO>z$yQ3}{somIu{qfDWm$GN?KOnivc+TL`h3wVK_WfDSnu z50wyi2CLmT%wZ?Xthxih7GOr?bQZ z!&}U$lhh1v5vX#mX4H2VX!I8^t!R_DS&~)Z>&s~gXXQnOr&Q7mXIX`XXYuV;)LAo8 z;X$kg!SGgn9&Ml*Gg&CX^^)}aSv^6*Su#=KTFo@$w54VpLWO6Xt{IV1PLz*jE^hf& zMSkp~8JDpQ$|(JpVZ6-(uVK`^L`&q;BMsxu{+e;S8|8t)no-M@$dD<56&>&H-Wzt0 zW*p9Nlzw?gGd8$7dML7FMSpY|pZ%dFlJsw5wjiP<@?FN&G0kY>GHxuU8JD<>9Sk8T zb=G-Q_@Wy$V~H#A@dVBI0FPm;>}SP?DBd#9OV4SBw@Xnzz=yy1~)8r%I%iA6v$18r43l(G5>2mOQwuJ_gmWMx0DD) zhcX76suN506Kr8($qkE5y2DZ*0>+Yjl7VMv<*zwDPp88nPpoWRdhvzDZkrfTuLHVZ>pbNVD*SFqZTI05>@G>O`@wN`o#&LSSbKJld(f$3cQmuq z8$fOr!^|`HS?W6=_epBE{+j_c7|<#DW~)c2@TuGuQ4-bvb$m&5f#cS0A49kW;cTNy zOOW1TrQ9u6D)#9T+7RPK?gOOZwRf5H0=a{ORCQMtw*yw;3^8kWC)2Q3z@a}xc|Z+CFL=aJR@T5k5vsUr*Og&Ef#ue=%@S9y^kjB*~wRC9+YNj(eb z;g{Z72hFfk5$k=WrKSSLEtFt|kOFIjs`T3EX_Omxd!^qJ z1$N|Q1tv`LRqLG=ni-c)#1Bb~K5Cm5824c!{r>^Df(swJGk%I6M* zDK+GTsc=yf-L^tQkIzk2IIi+0hH%@KvwbVAZRuT9%H7(fV%HC_)boJ$DC3p|)yF_C zXEmtsw?%rp>@8x}eU>ZT;R!e_S=e3sMMD|8dC}H`G#;?#u273-hg3yabZe*IbpGqFIwtcAa`PbOr6DwCPULX zs7kjq%qX`rHO6m>vFV4jOxa_TFljb!SnTFD0kr@ynOfXJXKKj_rnVX7rV)PUw?v!x z{K1oCN|?s5N^Tlj0I0D zSYeU|H!N1>U2Y)(Q?Ng^)0XC)U}=p}ZWrvf<4j%E&fi+>Ius@a>xRXCYQsH7Tc@=| zF-7k#dBgFUY7EECR0l(tOrh=Go_HV!&kCw;fEnHPo~e7@Z6{coWt7{Q zdc|)Fx4tngQ?^?dCdqKaV!yML(e!-BWmU!$nc8=PsVr8$-At7;gqx}DFZx@Hohf0G zDK{)NcmQ{r0Q1t+X0CacgKwZWl)$Jvz79k;Bev1a_1^aJ@KpGuaq_B&eqCCZmsNmORPW53BQ0Va0~M#Hr#y?rR|{ zmE>{vFo5VPocFP=i0g(QpVujH+=`fO2)82Ma&MV@gRL;B2sccHTW(?S2o-+lQ=XwG zH$V852XE4rjPeShX!}zB!Pfq;jWAK}hNUh-_f$Y?c>&iS1>a!BzF)(uookH)jGeb4 zpzZ~gFq^?0^3PU$JF-2#P4+T5^86YW8B z6|rMqzaCVlETkIr%qi8Ke1r;jonSWOW?y-iGK5>+liiy~UwI1?vu+qW<_EG(CtBEw z*y&@~rEnO-OrC}s!YF5$8u+^3Rj?;XW=_K7#Wgo9)*9U-0F#YHOg_lQJh7BEgnaI6%fBYb%(V+gnOR;1<0EZV1hu7YeoNo^Ez#Exrsc`*>%zp6 z8^-p2lrxXXyVc2tvX?QM!EqZw7ekl=V;YlkmrJDA*wYwcqTCJR#ru2ouHEZTP(IbK ze4bx9qu#e^Wn_z0kxYH-v?As@p-R(Df_&Bq>(kjYs*}}xE8x|Xj?iGOXKv(Y9mTHbXK7(h$ zaht>?hH(3kw}R%&pfIuIhQ&ssdl|rZV#VfH;}L;PsBqw*HaqJCvn%~(KRwRuw2l56 zv@uf%WC1GO84U1JT#j|F> zSQ>howsgY@mLBn2dgeGwL$;p8k}$F4hQ*GdyQsEfsr%{L(vA}>1#g#l_5fAV5N@8D zxvQMMN)slQ+%Oe>mB}`@RV|2}-sJlkeRl7<&aa(m+cefzPq?oVCjG$;i+zmp63kX} zU*SpFk^2Lx;RFcg9v5(ZP;llRyXLTgdM>ygxt1};C#}LYk{-R-BO7tW_kIt@TPzCP z;hTsit?2q){`4fxVv#Uen03Qq+fiPI;Z>(+(Tsrl36Pc8i{=H?WWc21cTBNR(+wNx zWpX_n&*R)>C{yA%H~F%lS0=V|GoKsu!eWKQ>J4Z=@b!E?nD?AX5by2Z8BmM{s|j`N znl;gH;J6ii%n-&bqrq3nfX}Qw8VHk$cEe&l(ftsR`yF?KkB<(hO@Nex3a>C`TXS*D znj-HH$II^ZhH~x7R};PLrhQ5=>W0Pk5v!7z61TVe1v2=eWB1nas1Fq`M8dYq1UzX> zZ!^a1`(H!2O*`y9t?@N&VUlAvEH)1Hs{nofyQ)u6Sr;>(lw?d9>Jchj?@?Xbtw^Lv zM#xLX0GMvU-(U#0zPqONFuT5mNiy89*u|)S7%)xi@J!i&Ryf}^Cfld%Jb&aj_J!YA zUMPA)nlbwYJ7HqX4NFy;6;PJ|(#P)O`kvr&7kA%N+HU1BP9}YJJHd1_d66MZCb9d( z$?OUfyKY!)5$b;cOeQzdn|TNI0WoIxVbhLZ^;=r$w^Wjw?_>ThY`<fv%Ww7-zge7QgdNdd@399rVPe(|i!Da?k78DuZQZx{ z&>3I~c{UgiseTf(X@#7+n*e82s9^|`TYRDOR+zcnwjWaI*UFR^7JCKVKZqq3^Hun( zb=ocUMU}Bs)}BY+3CAth$%ZhNa7$PB@t3RZ9)w8--LP23`haQ)NS;y~K(arAcmu1K ze4?#>dVdbrM{wE4Wqliq*C%Osu+Lsj2AR0BA!cHs}$s6`IoP?^2`NzW?(Z zVgPK*{LV9E-zy0dLvC2C4!Q>cy8e!BX8_y*v5}_RdRIW*1n^NtG8^Bio9^-x((sir zYmdT5{E49Lu1f2ic9#(*4a^OT4MX|MfOdq@FFb;(<)jsNap#PCbi*-a$>Ppp_9E&m zs_;6kv+yz`(#z;BIBpYo*bqhmNhm$h-vsP7E=zLWWB%*i(P~AX8<#eyr{J{^~MRNcBYy7;W$%U zoVw9VDz+(MV#*DRjYjz!fbkgR+DXGGtj3s_UWuJ$Aa*=PZ$r41c%k!f+`o7uOe)b0 zQ{fQ|uH0;n@hLa=%ya$97x|TQv$^JNe|NQS(u9d}H!L;{-Jb*IChf?R@;XQ1cRovI z&X9etFB|f$PV!{3L4RHUli!lvUxkS!H!L>nsi1lhFwL(Xi%?kVi7Lm%nw7W_eoOZq zXX(1M0<$d%6H9Jb>}qt+2aJpDxtAgq_UM&i@GYT4UF;9mh%|LZ-qLJ1P%HG+GnX;XyNpUe8sl&yb zN~6MuCdsN*WD^(tz*|LjfR5MWYwB0fT9Yl+`FoymbG=OPc68k_-PwZ#2!ZmgIVk_0 ze;hQmi;M9ak^P`1Eve4^Ep;c*?s@h?GzqHT|IIe$*=QQul$}&H3Aj^hlGC!o7qjcW zK`1f`+*C~DE@8`LGZdK!x`f*rt4?GY==f`NVSVDDiO9?3G;<={yvRPdk=dXXB675B z8_`hBJ}UMR!t?{>1t2_7p2kI$o+(7>Is6ZlexCn)r21B>q%x-oaXE%vD(QZ7b>L1a z6jk94uxYO`NUs&OhIy(8=#`Q)pc)uT)s&!UC@eg?nVNkDlyrmnv73_fq4wBRAkqu!s7(bU{h^c;8<(&|OHW={ z;-<4|ih^jUro@cuXxm6xG*ngI`r0k4KC0?yv>nh3Kq~wO8^O@fm=;q?-#A3hf>T~s zs|p{?M%0S@gbLF(Bfo)`zfzBn;qS1)1iUO4OD|$aq@_G&dWu`OiCFYLrJ4eXBHGpw z{8z(E@R99lTe|+2x_SAt6sb;Kmcuzxjy@ks_0ZAzPVq9Jz+2=+oC1*3saT%uub#hg*oNbA*S}bwV z8D-L;9wCK0O+I3Q3+;@~jhKwe&c4jgg6dpAGAczRKhfi5lqWu_Hxf_TQeX3INq)Tm zPfDKZtVE*N=SJ6edqjrj4R})Rpc*1^t1Xq*q?fG70? z#T(feRA&Ql=ldh>0Ram6{tVopho|73JS2#}TXe!dbQc!^r45v}A8zF&7NXDvuz)*s#0J<6SrPx5FJw%3rlpf55ie4ZiMp@>N6mNx^En z1F*XaLfbw4c)QMrUnDE8-B`_WN(}|jXuOp;+)puCu*DQw|A&kf$Kj^AL0$01QBNaY zbK;CP@sfAN=%)Ox1+(ilLMdCLjm2>`+90Y!XM8?*jsmbw?oW4kipuFDQE>l-*FJ#iiX zZzfK(o=3tSvlBPNZaq$`i%+r{G9Z+HB#=t}!B#l=X~u(rhM+o|(&-nW#oA$7M_{-~ zx9cZ#>yVPEhs4cBO2@nv-eb^T7+zuph4~^zq;N_MmS)ILcCuG4Np!c7{f>D1on9l8 zCO!aK_Hz(5XE-re*=oEbK8M6%6DwK#_$2D&h@P6ef@&xrdL#vV9X+n~5rnQV5-x8W z^eJC>DY_p`t)a&nUUE!xQ*;C1OXf_fqzdLDA^T0>#$Q@%a_m;YQ#M0Nyy}=p%5|Tb z(I8sGb)V9r)7+8Tnd&kaumqNBP>^Hz~xQVAqwJ{4g3n$46If5sT)GV!!u zcScf&Az#kOX^2Dz5}I8(nw8izJD~as!6!5lYaoV06!fv8iDeKIg%})dJHKN(woxt~BFs>Z*(#>Hqw?(p_OC$(>Ho z{b-8sGsq5Plj4i}kGQBlE+fx<<@s!ce6Kv)2HTB?fM`A@{DPo@wl)Ev=QmO*u+1z1A6!q=z(&}fC>LiCXFObHpT<+ln*JX<>VGfi=Nyr%#6J4zJu zc1NiI`k!fQ)hOz}CP{`2Rn!N%7Em^(VKIfA#67N+KyYy)p>7gp69L>zGC8 znZz@^=nSq$z2#P_Eu)qm-N4@f*Q3~SnpVa^T3om?a}<_$D`SoYapj!km`)uGn>uQLysO|xxiLMaaAkMpnkPFc^o+Zn`^$?Qnfx|7eAJB199uFXir zw|S5^lK`F3gOgZEoeUxE@L@q%O4B8ED#$z`q@?yP;kIQd#PTdFL!L^-4nW=c2AtJY z>vRxJtjXfL7;BaVRD0Zg!6yV=4Dyu_`-yoNB=!gYwD2Z^mu>bD7qCB4hipepDsxpp zbpr~vS+QPRmkRzqiCF=Xxf&uyKJ!3yBap5v=VQ5+FW*Rg00j+-GmvkhrhtO?ARYlJ zh2etJN^lAvhz^-n!u~k$ye)Pz8W$%wRkl&8KtVfVKJ5_OA!bizv33f}fnvG^$o)cS zF9K5gAqeTIeL!9oLOOKCM-T&aoV6h3A2o4QxD?*T_GR`lnBvPcYJ6GktC&J~AH<54 zCqh4<;8Kb!JpCRwx;Ys!BGEN!qPI5DotMR9ZxTT<s^5)U7Hod`z(9bIL_Nk&Eq{)O}S_va4^ zXXugS&mJQ-;4byg;zl2uZx1fv>T)w{{h5*%8~(Wxl@Xm~-)qZsqv)%kx(cY>fgJb) z=D^$`0gtBUB=HbH?MJQDCB=ejDgdrB&VAmVf(=1ag}uC73Dn+O@+IbGO#&=c>pG4xq%&)6m;hI~6RKHX=t>{Kg}yoiar{It=l`J`() z=Mj0@i0OH@=6Vnf8)n6q+j@jP?LZ(e>vfw^1qOFs**lC{L&o31Q^=3@uj+pgiYGto z;bVLjNUC`EmWD${jYz{*9;4oc;d1b^*5QKWmjzHn&iR5uI_C?fdQw4?f!ce`aePwa zlc*!ZEAhtjMnw!Zb)`}pkWIYc$u}n8TjUL|!~t7gZgoUn-;+w+ciiXJ{TtN%RMa|k z|01|k_qbEH?xj%v%eud`EphotO-kJ__f@s7`vpFRuKO*=*Zqgb*Zsf~>OPI*)cv~S z>i+QYb-ypY?#rjweRqZc`MGr;@9AUw^Sa;i59)r^5~g=cy}Fe9p{J-P!^>SH6~hm2 zCUuqj&Kymu;WoW?u1AN@ik1w&%W5N0!mG1#9&FBCYtVe2S`}~CDWIxBg;$r#eS#4A z6$0UHp?Ft$EX+^nQwlPp@uz2LS~GGc2csokeaxgonr6wWx`(M;ISx~Pl>idwo{T9p zJ?j4*Cu8yu`2H2?b#Mx$^M_XlEnYU+JYuq$TR6>>o?QoVe;ov>TUojiTI-@VmCyrR zzV&V@VTca-AFBj8=udv50I38y^G|-G0AD2(7}7bO)Fz#C|7_AZ_s=GsbN_78IrqpDwTXZ~Af`Sx+n@@t=O)Xs9NkD;CA&2~MD zd({Kw)iy(qi!xANe}c12<2cUp=i{8^BwLR=P~L4b?18dYy0d&}t7&hpvuyR>Im>K& z!2OHrN$vcQid`oaVFpSW_+F!)46nqV*Gy8JfiE?MXOimxX4&K=`kH z7ElKPaFvnV>MTWAOD%ODP`fO52M7DIlGcyOnh<@4c?52|_FJ+^^-t!OD&vu=+yi{O zSWlLBbFnv8$}HS$_R}9|`I-6`fqRh@Ay8MTi#= zJKQs%n)hNuexU`sHd|gCP$PiKXCT(#(tw+Q*f0n;&ZFF*xN){aIO&X4;10tT z8wlZQn*(tGs9YDLv#<7r^k!Lb4p6xb34I+zHlJ30gcQ^%465Nk<)69ZzPw4$6MF%| z75k+q=oQH6P0fZ?T_8tkAgwP&!Eg$6%4N2;zMSB`^g})5JN^*0-VTwvYUdE5Z7hVVZ54#0O@+T=!>+w2*)%#8Ub~eRWZuoQ_x!4i z`aFOO_uwCQbB(#!4fJ%-$t+x0PJ8JxG@!--18%2GFTat`(*T-iHIiF>KofUe#KV1H zKwZkTuy;`Xiv`&MO<4Pmy$Aa@36h+*?-NwRfB|1ai~@O0h+P&PAkI2QxCH*l;00CczK1z|4d}|LsNo(aSaGp8Vh0^G8d;xhS9cTr zDC8H3pNQl-0(Bz!pt?OY*Ne7uSkc0f$*GCm2}zZ~NOzT%0Y$p?uwimX+1H zE5Ma^alSXGS{*rs%|zDm+Ug)i^<6o{PIZ;4 zL3Jb0@>^1^GJYYC;i$>4WKweH%Or1+n|w)_)n}pvA6OtJHmf7R&pTL-_$Mb{)uLLWt3sAxr%m&>_ErRAon)4mq<#ORUEtl4$3L(T&kA%ui< zJ{nNh0$RcDtf0zdsY(+slnbg2fYz2*5L9gd9p`S4=Y$x9f`_UE)lxukKkX2uZ`5ieiAJ8FBa#HVV zK!=p;YQFTXL#9J42ei>O@dI-=tUH%UHa{(=uu^dD|#JYkE z6+*JGX=RXS#kN>QkWNB~*fk)Ng%Ghtt8wCh*7h4nmG^A1o*b+@63`(FL3Rp(0+lfy z=cwO4smAn-+1t@`@j<13=f71t1}jjy1pkAjQ~VE=F5rKL%6Mf8m({!n6k7t8`4Eeg zuP~B!{EA^4sCGHTDi$qrUShdn5^wgkzk~t>s=dooomW62OlqsW&6iWS4ix+l0}^wX zuYqdw=~v+)7qgaS&QaOH!vXQOzb?jWh4gUoqs{80r3&Tof%n#nhiKy4^q?;x=NOVc%hrd{a(t69W_*pDpiwlyL9ic?ppPMrIdX5IX755CKmEwR!bKQu%nl5dQ5t_9tHi&)z^U)> zeWKY<@g@4hMIsi>{T@zH}0U=bz5tdJlOHyyJ{|#uw+q|)FIJ&aM<(45{ zc#O)OW)siyp80Qp7JK|74$%b~)h5oR+^8%D8g+)~dP_h(4QS%GG3@-g%O>Vs&qt;J z9jD9k< zq>oY1I5!%<&d->fTP$AOUVe%arC>>JPW(r9Bgsz~O>Yl|k~{s3vsoWi$$-t0JDh?y zbF)OAU%ci`UfiO)Gs~1H?_=bC8bc=bz)qz;0*cKap$tEh za(p^79+HCP$J9g>Jxe*3g3(usZhdAVv50aUCB(Ct72_rBq}4%O3MtW;LYhG+9;#Mi zHrZbYky9lY&3Oc39YjHeT*<62{gSVuRhi}8^b5mI|B~HoAp?qPkbZHbv58;W>CbV} zFUgG@WK;u+ie<*-*|+>Im-Oe5{!d}-#dJ{{+QGY|pIv1VQYo$4X$N)VW$g^PwcgHO z>(7Sj#b5E&X-=r|L{)^#>?gWu*o@!AH#j@YslbY~28g z=HXJRea+!sK+)R~E92^K=!@6!FE*TiTY#d~?Br`vJ>U|Q^o)2w?FMxGc3A;68YrrO zV3*p$svuLo1-m8yOfT9+JoOU>%t^;&P#h(JI zAD|T+1Zlv1RMC)tmC?R9&iics#m?v75}-&9pP*^!d0eMM0re74^a2Y|ci`mr0YV@! zcMgU33jb0o`Inr_ak>4hRM9-f7U105MP}Oq$Jy-x>-f5*&i`5Xj~An?v=e*^>=&SK zZN6*LlzqzpI5L4{$duq;s*ry-0fQd5QV)Ob;*!eQ;#YN2UjVDiFx{#Slb3Q#38w?C zKEzkQO?9=wM5}EOODM-?*bpLh3L8=<0IkYcsrg*1eF9#~irv?nS3~;*P4wKM9-%V2 zEp!a_1Ump+kYQP=PK#(izy*!0*kwKWGzOppy7UUFZGZ%Pcdakr&g9Z_#6Hrwa5O4aD`2tY&7ix3; zuS~blRCNNg#tWFqOv!^7N>Q2CyJ?bAXLN^EpUr#CCY#0Xs-y8AA7iQhUP7AFt8c*4 zCt|Hp%#tx%zu6;i7{#5pikMiWzg46e{N0Glv6~*{%TM_v>}7J7^E~IDVxsB@a<_3eCpbtUjU%Mr;-LEE z974W{&^&*ClG95=kr&5UcELyPq|#qsL`!Ap&yWfU*TpWCBS$I>-k_VX6tcdbin?Eg ziS<06g-9T~26fbuvK$Iz-$?E40x8%B(S?vlzh;pI$lggE{RmQXKg3gnGzPg!h{_pO zW|JGZouz~>UC&RV1Rt5lucFD3Sb{KGqcmnb3^* z_lREtBUc#n1Lcx?uQ3eTtV*u5%EYTNO}gCC@tzfrD<7ljGNwso{EU_|O;X7RagoCu zLoWuh;zwbObkw{a$ScukqsOQ*KUc*wU`%o(UJH~gah8u!V~M0t#j?*}<_KhOqT~jR z<%?uMc7K|BiI*&OCXjsy;=GqF^&pU4jCTJN$QMFf4RIKxG4~zWbEHSSO51-8;z6`s z`!>ThkiD6Z*Fg>lkxM-2&OQ7|9QT)Z78F9I>+Wf$l)|xByLO z8I@o+i`lp(Je#jsxVzF?-(sm70cjR0{At3CBR8Juah%Tw#Udju)eMl95bF!_h!71R znvb&7P(U}byV#(%1kjDF{{zeg0o}-M;t9x0fD{!8E#Vp+%AIbyQFmE(;JpkifG+D{ zY=(OskXEX~Kb`6-c=rSa&ew-x*PhF}S3q_v3UL+4F(IS_q|Rq(0(9C=>CQ*70G&4D zmmZ_r{2^WE96D>UG3L$i>4FfMD{9YHzVYN5te!f z(8OcZ=pRz6lK-{bKwl`Ixmgq-K}Dww#!BRzFfy1E?S3A#!aup`IdnpGyf|6T9&jCz|sv)s=D#hRez z1|WNG45h7iu=*X+y=Q->e)7=>j?onB3VJV)-773Z^a5;zvv9xm7R(PW)T!{9wg`M0 zUxZE>uUiuy z0^~9^i|bCocUZBJIK;Jp&T;Mqd=4JaIi3UZwGiakp1IYaZ9XLJ^ILAGTAs%#;j{uJ ziw=MMjQS%8cUQ6Uby$@GM2a;;rnVOV$z!5Mj=riHqz@=QGx!Ma0|GTR@@Yq|qXi#i zrS9dr$mY*_PN@$8k!iD7scQgma|iJHay!zCR0$?Tc?~|4c@TUrP=g^iRgJwe7XYH6 z{zld_0m0jDVi!0dc=Mwi6e5w&vr?CXKL*rTZKakvibh(g)6cTh5J2QxonxuNfZ+2e zhED;(zoM{9*5f!o@DE?+X*&R}GAh&k!}1kjo~OxH@};I$#cQ?UrUEAszTMJJB6ik1 zKCK4SUmq~9tzSW59sP-W8j867mO%0g;>s@y)ZZSc5TDGZaQW3SjA-syAEWI2P}T^W zrq{`~vR=%0aIyvao$+@OZ8nN^(jytyCHBQa~+&URc0wRZlsx2UOQkqdn zelqgwI%#bed1u3j<~Hy#q)w{&=>=J3)5%0S8A>O+j}u$GKMa&zkeoT#7?)CMJv|VQ z@3==o8E1gjPXu!H3+%#>DsFwy%8qwnJ}*C+MYIkFvXb&LzQf4=S#CPa$FGG~R=|Ax z+DAIOAWf({mI(RRyCDC3a1rhL7f;)HERExDb{_xN?WbQp$3g?9{miJqle@oaKhh#- zKTg9?;jPu&_EXuLiCkvd&&tOsU1>i}-pAJfZu_ZAHn-4rO4F~U{dBh5k5rIuKWTgF z|Lfd+R)?dV>pHo6=@iz^|0;KqUUKIoTZLEFcXQXn%iTjJcfGH*J=Sk$(*HUDj>o!% zT+GH>?X*4C$m4s*I=el$GTDvhuJAFWcWklgnh4PJ_Sz(!6|%x}OxNTmt(Q=7O!6}= zv6wigzJKbRvJTnOGJzqo;~Q<#@r}}#e7;dToE=g-ED#LaX6)g|Reh#Mk1q28v;3$ymF>Yq_uMI|NrO))}cg0Jr5{Lfi-GlWXjLx!tZ=r(Y(9 z(0ax)j?zh^CHq6nfS|<|>jAz{@CC)XfUYxW(GH$MXf(am$cr?8(`rQIgdvgS(Ev}| zd0YeB|G(4#XHr?80@^#OjC+f?^;y}Gf78LjT2g!OH+M@a+pCsryOEb7!SkMv>V+pn z^m1X1wKyaO#ymT&7*Bm0tdvL)d9G;wHds721R=kNfaax&=N<|8=$e_id)_xGi%WP> zc5;CISW4(tbvf}cw;NMQ`85TaH!Yr!lP;H`K4*(nIw7ZAelEmaRxI)S3|5nc;B?E9 za;RODG;y+JLQb}<04|3y<;ba)O@wd`VoJ!fv2);{F`AI)VgrTXnOH&|e2#)B@IMce z!9MMwr!dkUdTK`cLr=Z7VL$XNS^78jkfW9iC!VIRUIfpdZAFt){S`MbAd?}LTlSbK zBB}1?Wy-i`8p?!*Lm|C04TX_*rlDr|&omT5iPbL%XwwQ zCY@JCY|@!58Pc6B2`Q5$cc!Zu{u^&$_}&nSm;K4)PbxT7F<32L^DRGvSC$HV4E=({ za=SfC6nQ}+xxi-V(NtcLn8w1Y{7M65?bjg^_h4xiWt}PvCKC7l&O4Pt+!!lN#{V$l z-1n;dGNE|lc^F5eS}KH2OQv;?Wua;b=^qJdIe%HGyzU^?AWqsrawKJ~MRa+nWX?QN z)kBDX^W1%6FJn^%;`~*iMAA8$P!H5{@??(WVu;9pfc!Il`8CK-_c3&>y4jG{mcKHT zpR*3@V@1I`p^_@`2w9#XRMk+)#AnaKqtQ-1V4m49zIl-!D0`N_g_{sZBVidV4r;L@~e6F5fzmc&B_j2;r1(U#EN%(hP=65DCtaCNNQg z(#n;J`JXJ;xRXQO^2lM*$)RSDLlu{zmtO-h{T~*;E*5|B3nRVw$)d@TQ~c$HAuZ*& zk}Ml46_=JOzvd$2l;&J1GN&|`Ns-B^ZMrl+mmsG!4@%HKEzSR+U{009{6A1IJZH2E zMkTx01tIMrbz3ZvsLs$3#h<3e#PW0AfoKAee--|#9M7qG2r&fz6+dDMu(IenivL=I z{~98pM{WN#7UHD-%k``}9lwQ2y8b}7l|aTx+*VTDoct(ymCw$Kbk`Ljj?*z+SLZrx z-PXgzaSrA+jg&af!Mt9ab+#S+Gz}voE3y9r9Gv7Um62P#I(uLiLbUiOp8GQa@{^X> z;x`AKof^3!U66}NmkBI_j8H{v$Lj~o=D8*W)zeja|-ZS}2%a9Vv2 zh;$#V3tW1hGn5D;z4iZZ_~;>$s{i@E;3m~^5^i5`J(wEsW_%ZSUVBNlNvCrs3m$4}Ih_DUT@UdCdXzVsEsX&b{K{=d~WCQA1IgSN5I zDK2Rn>zv~H2W{izE@iK%b6iT4$*44zgp6L*AjF;I$gtE}2>gUQjQzQ9q5CF3w0((; zAgS@O>WMns=l4KIY9bpXof(C!Pv%FgQ}v8uxLAl-Wz3QR#7SoqIY051-CPlka>wg@ z;Xr$_sMW$9b?GuHKiA4~{hW5A+Rr6^B5lj;q$Ku1d@kyC1xn{^fjB4xZcXLLZAg@* zDuS|dWDuz)1W#S!)*R!ubT9rQP&$6dUUv|N99rq#ZfM3=nZ@1P4Y!};aLd?gL|OiB z^cMFqw3=E}vHawJfv73(V`%?KSxbq?PZxryai$*Rgil5AEaPwH725-{78ASt8)iH} zsyt73o7~7FOCZ&p?J;II$le}2E9^-Xj$>oOul;xp?NW&B3@i2N*X;h=Ps}^4*wzDV zfBhDGB->&Z{}?b*PeT-A9;v0+1*c*&S@`-&7Qbdjtnk@`lx%Qp$K|V|`Y}}}2Th!0 z;p|BQe*;ou*n1Ej$$l}miuFV59F|6S=q<02>KzLS{g&uxv&bp00j4j&Z6>B(QLDhK z!4KcUo3ucxDMZH+K{XRdHIm&GGfG&Jyy|smlqkW17&{lo7s~RCmHlgDzo0}LyN1R3 zSe#<&21xc}U$ecjHbs?s9%AI}LA4UlA+fvJp#!9bkdBOX9a%hUd^Werp@`t-g~&)9 zIA&MIiDi}Q)k~>ofc)K7YTH51ab=A$e=VmT{H)aDK>oK@YVr}jyaVKKwPG3dEY%Ch z5AneN(6d2x=KP?_FE0-hKR?TT_%T608a#=)muMhiG54mW&N$YE+i(s$-9TE;WYv^{ z`?)hZ-r&Vkv#&(Iwi%98L9mYqL?gF=UMc9kC(-@`2|isC$}@m7QmAT;_I`{+BXBPv z)qV?x&XLFo>m;#nDYQ)NC&}l25-2EM_i;)G8kJugr`3gjFf{4 zzfJ_ZIxj-epH`;?rdQ{RE0lU*AbNBSzK8n1)Kg$G;_9j8BzwcvN-e(zJyU5G?f=Ev zF$v6P11X>J9pNfHd0VrUx^2x>dd96hS-H(tx)@~aNJr_5KWablw|#3Ca;s=|)=3^g zMCBFo=MYF0qsFysU^85}_u+qDvEBZ*VjDUoROTnnPX+R4(sIWiQ|dcFx9K^*^NJ!( zP1o{(M}z7pkk77B6<)*g`af-CmzuP+#NeNFDK{zg*3&_?2goleO=KVgirwy({d%(YYc~-I)a}=4A}TzIp}~%N z6%&|0ZTb?J-t=e1E%k5~g&>}6KqWIipUCmPcs}s@?Vq#58m0-S~FI(OhG8&B@ zOR~SF5SrY>?)`BPy6 zr2&WD0=f>GG-MYskiUtLJrD65^{%F4YW(v+v-n zqC2sm3vySne_oKY|F$4q$9hh}Qm+EKAg`c8k4dFU*^STVEs!#H*|jTYsZD?`u7L%X z`Vr8@)vSW0W&yhJ&wMgyig*zU=FYLpZnc!qb=iMYLUv~#7}x)@1K8%=4&a*G$~H7@?kCJ0zKs`2 zM^Xp#Ar{lB*N=y&#>}Ze{+>S>qV*&`e=r%M8N~ZEo~5%Oo+M7=**FUdBL7aA z;67Um4+H2V_C3h!0%o?cSuq9pvo<4v>22oP?|BP=`JwKkjWdWF#)57pbH0=Bl>f8w zx7^?Wjx^fs&t0S2-E*kRUb=wgDpRC` zDF46IV>cyNkK2@np}8%oH6#9ln5*aH^=<2M>)X|{GLvsC#BDvX!`y=u(GBt^)9A0G zfi3_vF=Bd9Edw;M?TMhOgfA09WnBCV1Ns2|%?Fy-wNiI;)A9k(ywFNL{Tutjf#$`m z)X&`DH6IRuZ{k|GC}^dgJ*w1BAn!SLtyZzr zDW_P1%MGfMiR+-FbW$MiSTKIwMswp^3Vt3>po_~HsuK~_+b&a+rdet=AgVr`PPsg; z@mPg7@M1t-G3?#Reaa#Lq1d}z>%0a29Ug7%m%L!I2ZB_^N`J-C|x6mf8b! z`jl*a;lz`WQ}46XG(d+u=xCWvhcc&dX=SPSqwMnq&RQ${%jKUoGH5UBPr#LDpz1r2 zKKmeMNNn>;-fHeZ^y_vLa9jNG3qHzqv|yo-T$aVaE@yFOgdnnu@Cw$%&y=7ykqoZ( z#Gi%NlvUu6ei08utNt1R{`dtCd$MwuKFtv+hCj1K@<46tvI}QBB5fA(FA~zq8heuR z#dce=8I#j;ab7Bv*A_bHmkN#T%RTY-r7T-qD;nj6jQ12t{I^h~MV{0mqvaLEy7UiY zONYGSMb2;Igy#^W0x&C! z0-ima*TzA#%`=bH|PY0WiY)iivls`NK~_)P~84!=2-iz;1Th|*2?A5h@~cpO%o zeBVsD1CITQ&HbQ_L~|lC1+?3IoL|&*nN;x}K{aTXQr9z&!P50~>bm^91?cd+6~6s0 zULY_pJ+4XVQEVxBePM)Xh+IbC29x6OwczQu^(v#@J&c2`_?Hzb`~^Ah=$k9ZUjYMB zNPqD8YN)z~Qeg?QOITavfHDcUS;DI|hzs3oCMFQXS0yn*kOQ+Gb`3i|hROj(C zk*P4p=}jSNY~7FvNgA#eSt^o3MNqE%v>lup^TL=S#KORqVf#W_c_E*;_H?>?dLhzpOq|d(CSrpNsEpq?anuA)b;5hSLOP+# zM>{iQwZ?&|P@T=3wNVJta%(^pRRkFVa&C2yvfDUbpsL-l-jn3Z1i+Wb-Ck0J>kIka z3y~?KFC?$Ho8=35P0$xo&kGrt9@51N`60dKT<(SB4{-`Z7t<&&q-}c0qh5&2V|*!i z)e8~N=?huwh4jIb_(Jx2A;TCFOh`!1Eo@YaGTcH}N}UEGuf?@H)ozvLO1Opal-INB z!mU?_X9}HmQ{|>Ro#{yqf6yt&&`S>}wGm03Q#sSbZbaifk=mf$>)Imsc_NQ{A_vj3 z1(8r+wy59I0A%y_fT~d+M2^zhQ4d7!7BU;!YCiGQYzMXTx)=1W#**ysz*MN|eF1e1 zbf`c6>u4jIVr~A}{;NFqj7%c@{Z)#(P{ihWV(m{9+m0i>3yIJz=CnLrhnyMu;X~@l?F{VVa=VFtp$nPq6*^G{K*|5Ggrd zJ4tY(Y^Sdbs9knPuA_?;*~MGm6KUy*h~w_zh;;Wv`gtM)+5B`pBH<7A@M-lnL5&6gy+3JaWj7X@3ouk8^h{|y@y$q4+jz}JSyB!pIB5J2n=Q<+I zJdyUEhzvW|IU*N(B7-~;8AFCUBDZ@Y_j)3)9O8^ZN8~9_h}^6$b3}ggL?XFv)|zw2vB?oB58rMEH9V1@xQ9L9h_v-Yx_Tn@uV=Q`*3SI^ zPh^NE((y~BIyoX^J&{SCNN+@jJ0j0|A`3i`2>$jlL_%$ra;W6#AeVp)7evbALkXG) z=S<;zL%i*9I?4&mo#f1AygW~VvkB~M(+TJYpgT&*c9MUl;naX{7ezx*yCDqT6;M0R zMvXjIKEEr-CXivBX-ey`VVY8wYTM)uhls1Tm-vW`OV8nv?E~GETEP?QNmyHncD~S) ze4b@O;FbTqA~V%$pK|bNR{L^}%nYl2RR@2{YTpoi zb7|z~TI~lr{DoHg8^L9+5L#-rzr*1#<0kY`62T(sU0k$%6`AOup~w_aZ9N*1gV;5i zrNWzFv&CW+m!V=yMb?70&{@&@2O0>P7m*W!bP1GI;r0GiYWpFwM+O#?k*JOp{6|Y0R8Tcmj zL9cm8F3-1lQ&0vzSx>hJE$n}?P+9IKG}N#)Cz4GAIV+;n!_z?)laiv3Ie75$;TRo! z1|Np_hy+TrHwi@NEjZE>Ey}}9v3SsXXfKaK?ey58rvD%jDrAY_y)gB43;%cxR$8gO zy+zWmPsXNZ;tYwlEuS_gcPSoKofzum?$aGiL)x=)GXYySbhlKOPj4bq8{5&TFR)Zw zIqlY7Q477zW1qT%k(EW8oEvPUu^>a?{CEc`UBGh4pROciyh~{K2maBJHgL(h6s3mP#MfSngoq^@e3^|fs%a9jO2H|j%d)y4#U&r%LR%PvF?F7nA zRuWBP;1*n3PRUOwCi${mkNq|>h_NgrZ}(>%AwgdhXD{2IEy0AYxrYN4DpOdE%5cKW z=>fhwFbe7iup|(AVHjurp2fmf@kjL|A1MPFD=A!QDdt4v$Z)!u-p>%X zLvy>4`a+Q#b>NVhNpFmOG7he3PN`oxFcQYkg7+M3t7G2 z3GvqUbpDUOoRglo%5QH=4rkd5fwYp{y{gOdkOnI+a0q@V0^J_48Zu<`93=|*crGCV zR?YC~kPh3bC4o%}Md%T2bpSETs@eSi9;*kr%CAWWtkzx;GXH{)tPIIu7HR^gN=1nr zI>SLjp{}5{gd5Fx0rVU}6P(8k-d6C5Rz?O2G(OqNC^^o z4*rytQ49Q%3h0?@Wejup3$2Wi;6p|KQY&Me!(V2FFCGPtJiNa%q!PO*f@|p{j21ve z$SZ`kCtAO}FinYCUsYDIf_FpeV!)bjWnRhkCBa_{TA3?A!vBWo3o&zbNbLZu7kM=F z_L`772JnsA%<$TfIuo$AAa(J&ka`@jo`HA<M{~7-W+W)rhhW{ml zr1}F^6H<9C$U-4n3$Zz*UIVQ9m{|#uu?6CAz>4%A#lsv%+?y!tSERhZj^p9gXxK6i zTQ#g?ba4eA~rIBC#!)RlF~ZiR91P6U-^z zwvtkFg_uv7G=x|Nq01xy@wpIECWkBXW;TRdCXC{0`W@7VXx)e1Nided&_(byjGJNH z2SZoRm%(ffqPd+MMO$NRCi(rp*n1QBD2nubynCj5re`uqI*`dE;TldOqDDmw;1NVI zpe|7q170W|@eX+5jpBiKJc+t$))RM?jjLeX^@zHQDA-nZWOt+%Rsy2;)TC>L(7^4Ze}VK46z)N$wdb#9M3A_9$A zND&m=iFUFi+SlwW<6T8yj6dGB1k`xf1JL6=n}8bcCIFf@>e-2CRYW+}AI-TyU`N$3 z$6+*C<7QQ3LNp`8d-6H{@J{iE_d+1RwqZ{7hxZB~L_TVGiLhBi4X;M{!}|`!j7oD^ zX>SZ3N3(@IE%8TkF#$D_%Lu5ETnRvrq&p@sk`(|nw;aj8qKVK*eh5TpB<}=bm65Cl z6?3vbl3Sj;%1CNNZX|0|oqhe0)Ci8GnAs5!YLvWIL&|Sw4P&~J@^;aTQ8*2Ktz)y_ zmWt-iVqWpv1VHoKN0%85)x~-Mx{GrOs4mV2pt@MVE-vPE z1!l4I@tR;CMcEbrBLh@ymP$ukf#3vdrp>IFiAJ!a;%=Tr72Je1%o1Efck_ZGqV$mn z;a2IRMg;Wn4OGHN;$Ey-D*CvLT~+$Hl7P}jcWi+93ILkD>U*J0MQDBFm{C5C-2+tZe6H!Kc{55yd;T0r3Pp_& z?V+!pi7H?ikxj&vDjFeGu#09Kjw%kT+!IMlV4)F@0G+oS+B!tVvnzbkMzzP1{ya3u@h^&j~bjti4cxQT6uXRQR7cQ;KqYtjp2O`O4RG6?O5D6kAOc17D0ZJ@qIetw=rr%K) zDPKiIh-r=Rn3mw-AF9%4ksdMt8o? z8?ndVMvBEG;}`m>KO#CbpMhEp#9-1K4Y9Uq1PkzTAezz`R1R62Mo5#Qz%x-tOu9$Z zDWIavB880*SW!vdL#a}d0xC%(OQ9es%IYVSiaa4JXd+`o=OV;3?C>x@MkFFM`2B#G z#u{qy=aZxw{5Aq=@RtJ6p1gyA8hmHRRR(`EPz??K9zZ17j2is@Km-P#A>V!IzYJ|W zS|p>U5fUg+yoahPX4JE+1A!2E8POhjbVhYRNJBsQ&PXG~8GQqxynY_uKEu8oZ>I7} zVTIoUAx`q)NRjjS01uIe8gcw0(;LVvI5ba0eGcRX@MfWb)Cf;^Sm!42C(QiL%m_0Y z!8$V5_bHj&0=g8yBkG!4%@VmrBP8a{W0W!keMJuqa|hptR{|k|RH2GS*PcuUlJJ0Z=_j(!}eNiMRy_S-V7lpibVYF1plTcWFdURjx;!IH?$s zQc)F+5LF@FXHjJ^tNiGz;IdWeYJ^93MiCw@h6E&{ddg>*2w~Wb)26Ob zg3<_KNILhHYUm?GR`kX79G`!n>$DzIiIKioe76IP`0kJWM!r{#tniu92{C<` zen0f9XoU15e;AzCY&QF#nJV}WZlTEoHZN!f&;o$*RsLrH78CGdD~3UZm-}}5079wL zF+P2Okl}d1+)%dXh!DBG10U!f)PyI6VHrQbN=Cj1OR0+Fy$L$=fv2Z5cZw8?bT#6B zGR~%+K$SvPnH(t>bNLAfp*$s0D2f`t##gBQd_^q>LTV`aYeY`|!%!znvitiJ_r&{kenQmwul$!b4tY9JkkiZmHG&6?S?AC)Tv;ba+t0L`*aKm!wx<# z)R$~u1nDyLAVP&6GGY7y2)L`Z1 zB3JmL^N;mt9 zlqEojAaC^rNkmAH9|I8*nC>`? z*B`Ok;?iOwu5c)5wX`@Gh-pNq=(2*1(M*0~R!`Z#ZY5w@+0<-Q{Vl3W2YX`t4F_k>UIdLmQ=fpV zE&dMVL@TvJ*1(Tfe3!kum6zHLh`fvaah_xq%T{VTyFSBmW$Sze0kxHCV3cK$xOHAi zfP=)X^GX1!Bl%MicGLi29*;L3C0|63df;}D`38jF7n!L9-T^QjnLiRJwoP|2#_U>1 zcpUnAI{SNxC2pK}k=1^6>(0NTi&+VI|^}y<@rF3&_3`JR1xjI5(|0y zz%LbIp5^(#O|HT{D~{1^mgfVB2>HO#KoqlvavM7W5wam7LN=rk%5Bh3PC_j)@0-yQ z}4iH-s@c~{4d3hG!QvgC-lv=URq9A3(o=Wz@ z-VVyg@`4|&QbU|^YM$SdM=Wp0s5cNYT95goMMP+{HUnZS5>Y!wjlt2{52eDIH(Hd( zVL*u@{neMpu|S06K}1L%8sW=>YI6lD33Ja`dHLjKKHFUan!JIq1f|p1tLH86c2FBj zl`~#SKsnmndisMWX)5SQBB||0AD|C855oXa1DT? zkZB`uJ%ACoH+(Gb58nyk3}jjf+z#Md-07|64c;pN?1{`p1nvd!A?~~O;T=}I-zNDq zG6~*cJrh6)GW!s?3BX}kOg3{tc@lsxk=ghy02c$e5i853TwS&TSdL67XPwgk^h0J} z0xdCoyXOV)mbI)_{4+5AkikR99zt=r)?bm`m)TP5X=Dd8+dFwPIQX)b0F;~gJV_r3(LlVF_$N2$4U57ONn0Y*Ii%-UhX5<2Q^{etDb0rg%nw1$!hPs! z-iv+}zyxH@BJdtaC*DP!H1Et$!I#`|AAVDegn5XWI1T^rW_~~X%pYCcp4~hUOUQQI z`cAxz(@#j21=UdxGyDy1zY=PLyZbmxG&<++pn}9Fg?o+xKXI#=s*oO!ld(Ot43at( z_?`zyVdgsgbK=Dml~*Tglvr78lmj2YMvRhEQKbr<@3|#TakGR^H0+3Mq!^DDM9O&T zgHv({PR9_Mg%ADxg&cvC$iMT<UpXZL;0l@3&ACc>U#}{JwXgTbC33TK~q}Y{s z8eyiQHXA?_sI?(U$uN)=(kL+^Xy+C&}% zCutdfhaGhgHU&>46#>wVth!AppC2H`mX==J^QORJG33K}>b*^802FTg2o zO3nRqH4o3#JQmrjSo1R0j7ZJ%b2SkxD4Mq;+lET9Yk9hn)!EGb$e5;cGyWOQ0s@#N z`hNgkp1>( zG9z))N6LiEb|dIU~U<{7OV(1k~W>D!DJAY9U5Bc{as880H95e*l;J{V2$1 zTL=WC8&T?7$;jIv7t{Z+OBJnaC^O1qrj=?{}IgWsHGR_g_Oq}s$>QDb|8H23++wt#w>0iF}H6Dy()-e*TK*RX2 z0+fl^`x;@?iR1;Cfs6)8S5LV0bMf|0ra4!j)!e{=UeH zAzJz8A=?wtg5~5NtFo?Y5`I8oM-E6t)uq11jJbyy7Uywyd`_m=VS zrx5vt@#1DQ-iW9g`C7vrvcfWsMgnBICn57U0y{aTTzf9AZ^X4rkx(PO9M|&T6vpe* zpZSR06yh1K2XJhIWY#!NNf~1E7Bpv_5J{(>W}uFP`*u-$!ZULOms2%I0qdnlG~13M272(2iAp z75>eVo|H3^I+Iy2bsHQxjN=WI-Y%v2+XB<#msW_I&tHzxW#XvvKSXvR<`#4$u|H;_ zQY-%=SW%hGB>7}_3}+rE*9F%-4E3%S{4Idqd8RuQ837sq{0YDY-=So$r0L#*OeNGC_mMFGX>R~t1;raY z#-0N+lC|<*MD_{cqVQ4(&zrFhgtbEyykhIz6_WL?c-6b&Sm*?=aF4_V3y`7*rqEy# zis)bd3}Yc9pAAaZyL^RrIYSn?yeBT$6G<+|7m3ks>|2}?QCzp?5i5ZYUt=jG%Km#2 z{RSe~0sXUYuuS)6Nb@r!0rr5Xev4!`B1Xk71A=v=7hzv%U=O`{JGSPbAE?oXESdq!{DnwgtO9|yggvz=L5f}f5Vr7&7NhFV(kHumtU0K_hj zWHKAVh>q+ua zv$v6clH$NI7Kz2_AGvFYV>nXmi%7BVAe(X~^X&_Aw?(LLiG7|Ekg&Kj62*{$;RUO= zhyq};K_rxTPr@P5#BT&&^bcS*pxBGdqG9+ylld}yU>US!eC~_dMh8+NsV}E9a?m%^ z$g&pQ72lg*R_^zgZp~?TJQ^(R3yDlda$e2?k_+zT1w(=tyx|!A8=z+Fjq|+Oe?Ic; zjq^GL#A#5vv;(f+8>DFT&Nnd*ox6bJhoA)mfvOa}`w`_&)Sj^Z>ku#tFd5}CO!#kn z9M<%u72USW+cHeN8uH5f%#_xqB8qtxE%k;H<^68pmgE2jqu9I!sj@Gr^*C@32Orl- z4KkoBvtj6YOI^v&XZ{5b-^Tn)9)20~%Qg;Q|L&+kq_>h~%ZCjd2MLUvNUt^A6D5?BXJ7y z*x~4d_#zkmj{|ZHFyI&KkmCXE;Xy`%MgES)QN*Dwmiws7Jd_dJ4LIop)_WA9w2asa zS?NATAvR0Z0gJghV7nOp3Qjv0_W-vaDz8}-43B<74f}hX;@;HQ0bGG8;28@Mx1xO5Wmsm zS{+9tUilXpVcWrd#tFa^1+Cf!|E%qCvd_iIG-KoNZ(o!{nd1+@bDkt<=QsFgIC~Iq z4!}9$9FB9;ISyyA_cs0|w%Xh_&O++BPrjMB9GTY${1Gq9e;=93EdUHgNi{O(5txIL zY1;)#?f{@mHm?p)I|YEI_WC&67>H$e&oQ931v0Y;T$7~zU5AcHzwbZ>6U$BbXE?VK zFzh86L@QR3+s%38jazat*4S4}7d9AU&9gknuvvr`Ro>LoHa&DB&&{D`XCmcsM>8T-k0#|F}mM}F3i_e1?iM$jfm2KzA%x3JI;{`)`s z@$*WFk_y|{9Vw5SKK72=+uVE_k9P8eFrFbL&)ii+!w?RcyDZp^lqZhUMzcmf|4BEd z%m|9ZuSBG|x=M+2(D36(d2iswkO%Ez8#g26^^#FV`tmA2T6c8ceRbO-vIa#94?rMh!#mo#@5=#IYfO{fa&`MI4#@X zHugp$X^6W8qi@~I(|tIJS-p%5%<9khXE+ZNa304w;yi;h2E}&;9|Gdl=0wMY=kp$^ zylYmTRo0Ddi|j_|lvNr#4A~wCwybRIF3{Y9dQoB6`vL7(Mcd=wvOfc56wwEM#4LRE zCa4KBZeS%*q}UV47BP#`7Uc2B%nA7SfjExXsmPvy-~n%VV3nG9WJ{Rj2(JW$M}V+3iYIzlYYcLnm5iZC zi%769q;AFqhsO$x!;kZE)o~+HpN~N+K!q>yYT!GIZG)Fbx5XDkc1S~sk)pUSoETYR z8_y#}2chI(I4P-i8i1bw%qa7#U5AWRI{+nHl>4M-0NAx31{*0_2Wqni`2>CfP%;>* ziX`nUKt>3>gIlx+rs6i%&9R-(CvmPuY?8`avAvM(kH8pX`~k8fpakZin1M?qJ2;?UMI z*WB0wg)NS?B0GSMm->obkEY&1vMONL7eKfqY!v}m0+DRq3&6tw=3!g}SPW;fD2s0Q zM~MaC8D#bx0ANo5e;A12g21e|a7`MSnFMYJu+20dcofy%2Oy1Zhu?;^2}+0I~pVtfh?%$@73I8`fBJLzhkPAi`_r4q&Qy^~UCq z^lt&w^6KrdHS!oL)f2$?j!PB+m<=G}udy=)T*Tp+j1-+{6{jypUz$)Oy0z6O-5YDS z76O|koD2!^;1$t-#Y$Wf<3WT^&^^tk$0Cw2G9<`@4?;zEw#qXk%0m#HB@Cna5o0sD z5aV-co|&kGB2k&5RZz3BJ#6Dlr08Y{%-)83sGwKaADE3MkiG?^Ck^ufek@`6XxpgW8rAwhoexIlW&&rT(Le2j zi4rNgamq|w53PS4NvQqlFqr4z0Ft<76{< zioR>&B@&y6gJ&>@hyCCP4BI_YPzxZ9ld-9Su)7499gw0I$OQNgTDrux9mvga;7`6s zH%~(5VFC#>@&Pgv5&#ZPn~6P;d6qyw0I@vVI2OrXj%&_AW(k3meII|Cg2w%d;NOzvbHCtk2PC=6HRAy~s z0g`5ErccO5kA->Om8iO$K!$vkw_SiLF}L}|0#F5WWCGJ z^DZ9`+v4Tu@2eOw>kXb{td}FVJ0@hf7ksA&%JByzK0lJU2bw+z!j+PXs=R40wh}7& zSA<@w8jNh)gKgswBtFJs-GEHuCY+uo29L2Ai6sic!zzYF1+?zriR~BPkKAuuaPfj! zyulRPcmRp{x$v}aAmLYRiTCjTqJxkxHO=DhK&|!=0Q=AjOSo`nZ%|u^Q{o|pi!gy60l3EJ~el!R#gH_F(OIR$tR`*Z6&IJI|Zr7 z)o9fI0w`GGr}*c&v3&kxMZ>Cwy(T8&G#?2OgP9l#FFFTFfSZoa0p#>a7=*oqR$=CE z+pt;cuiYd(Gje5#drbGbDIu5ZE4iuS>q)$2O|= zRUJCELOL}6XC3nP7`ffRHs4yMM{3#b@$UCXRz$gVzmYft#2-XT;31vFSNq$>W|%5H zLF|H&$CF1{D2>|Yh=?G@QjL_zxzkAP7LnsQqtgNB1Q9Vs5JX}Lugelgf%YP#!~||+ zjPY8!0JT(0p2!z?#C;AQ_8{Gqni4z?{ib9?#?;dVhKv?xeGfHHL^rjK1CSDQm&KpL z@z%mZ6W5>%Gk}JQo7YAFye)NO)2bpp`3nCJ-)MdqQf_B+VwDcg@weE;hx-|7Pa5HWS+qwT(ukWGj^XsRJM@EI5*fKrDv!HI(1G`bXqW+|V`(mO?pZBXbV{ z?($g=AZNAl^dwHj?KtIuUf~LGd!Yz+4f_FB^KVf9W}IF@Dy%V!Po130A2LA?t04Ag93nx8Fx1yhhv;{e>T{GosVueGT_G%pg3tD@2-jGH3)U z)q!gKgyQsu$j@R6Xgf33znZu5qt)?LhVAp9hC~N;bJOI_DTNK-~6 zl~FY^tYJrbXa3+zjhEPX%1V!$Amr&VO@-~_BG=^ydwB5LXe`o0H!QNxi)6!>Rm;6HN;X(Sh3D1!k z=Syn@B$&S-R-EDYOn3}O%CC#}%)SUm#Dj=<{bv222*Am0{Ee0DY+p62SnG_!%sgrj z4#J|l%2Ifb-Fgzj?}W8xjz$-Ga2MQq3fg)gIEsgu&*sTu?M=mX9S)0I#GGHl_omt(Af^iY10q5i&Zh{X81c?1k=8t6 zy31z4=V$%{j)nq@uF=t~@Kqj_4DqMNZW!td%f+9TA|LXn2)DxWBO)ZfU$H1E$!*Z* z)=(5@Zy;JfjfI@qIIHrYafdV?tB*DNUNs^89hE>*&qstq^AV|w{;BEbS1iz3TA<=Y z8Y#|mvm(yTOLY;ab|iR)!dPPApb zgX9oIGN!^Kk2#;0B@iSfsu1*f;+)px^Dg#X+6MG__g19uhR>@aNd~EWn64IpH93;% zcMD4D3C!tHQiR!UHuFxTBz-MNG!aNd`pT@`0w8)@q(Elv#RM>Gr>R2A2z1h)$ptHU zLC}{`?xAo;5UUAyFvSZ67cW8x`LRw@SY5!Roh;`=`mxS<=G6yP73`R2;F*W~nTA1w zm5LO)XZX{(Al@=J1|A;q1`K{RE{k7Wp1utE29n_9_XhyY1kAwX$0;_tJXWZqUD4`y zV})tX;jOHWXgkelyBz={ZM{5@`Rlo4Iy|8Tmj|q&ZUtc}bEY2~4`rk11$s*>SOLQE zi#PVvb`QU|bXpYzptibmGSxwCb$}tR1|7_(~>10MNA}Cwhu4YcGZ)QAqTZ#yE zTWSppjcPCuUpPb-8g)KrdZEEcIT~DO3?Kpv4H10-1jR4<4Dm|`+k+ik(ZvpGv5OB4ik(Uy4T_zJHH$r~qR35AEq-OG4k8JM zf=D75X6hi42tSC_RJf9gUzMXGE305AN<@eX5v!$gb+=HN*DX|7!eVYE)l+Tz0hw@=@uD+pS-N(xpCZ((+9u!y;3=ba34{QY-+hZY9QG~M7e9oXyRr{I)-2u`_jV+YwS)az+=9Wq<%{vpe-!QtWW9&P5NltD z8zZu{KM-V%Nl2qc1N|EAc@=+&)4rSG?$AM)Z)E5Hh2b7$_f5078TW_Tio4w3`N!`S zjg|h+zxzh^Akg745oq^Kr(Xl$CJ4qo$nEzvq}amzIeF;@INim_<6gRxJ`)AY03>#a zmZfip$X9wLL(|8g#I3_He;U{>rbK$=BWypMc8Y@{6U4p&1a2TYnGfjOaj-@LKZJAd z^zBj*4@Z3nVLPp{0xh{06^S+0uvN8yt0%B73%I$wV0~SwEZ~|+q1$%6g=8y923;rx z8Hy1Ev6>h`?aj86f>?XMLpQ-P2cUa#QFbG)*KlCgHQYmr+`a+WyOWW=qFUL!s6tlqt=%)KZ8_iRb_G5XyD zOes3&-r1+*HsmXj?|C*$cx??!{!~`N>*`s;YqGqC2RV1|OS`;|2Vw78)|ks{Thl_d zSyQF7TUqj0XQVBb*3RmGD-=sxfxNafgFoU_mR1S?C7z{K0-)?=2C896(8}n7LRLmZ z$jSr}v@*YjwlY0Ua^2-VnAX!IVVNegCxKHQJ0ZCz7G-z$b%_S+zEzUhF#y|c;^!3nxMCkNfIYSq)Hwa1zu6+{@044*>lq1c2h513-M20I=J{0PuNj z09d(O4lt~_cswF;-mX4s3On%e?m+#3lj;C&pHBkH+#`ode58Og@jTm`dj?7pxZN#R z9*vSF1%MBW*u++N>O~V4iyaR~-}fXRJ2ILXaU4X3V-k`(Dw@sAoguLNFxQ;|H;zx8 z$-#)mofN?nzfJfxLCtK87m72b!@XjTKptJ_=xuTc)EJPt)}Ld7iAj~mmsueWzm_Cs79cENK{0GL>1Dk zDqgQNs}?|4HLG3`q^M>C=x)t&pYvzeNn~tNw4&q^tX-Pe>>km|%(dqNjf0lzPK%~X z9)m@;u(UZ+ptVvotT{4d%__$lAvyX=nX}OTY(c5qV#PL9ZW(~C%5kM4NIAM^{RiZD zxIc4o$>!dIH(YD!j3s7zw5L`=&O#w26vWzX_Wu@OND(W*qE^Ie09_EEj+W@RNHjws z^6(v5E_N0~a8~zgh-|d0qhAWSIwG{I+kh)z9NbHEw~G#N&-T4MO*QZ72x(c{?}Zs= z7o2WKayfVIjz_KULLy*T=kamNc{u4A$ohsTd%qy+RzQhGLDZnhco>Z<8Gd@qz6)y~ zJh^rQ{`pIzTU6F5z6aT#SYbc2cp@GEz6{BwcYF&E>0v?j8vglL@dppyf-3QMVEKfw zo590_y)Y-U%pGKUKZ-dJPJi+Vws94bJJd|yj_GR_qmzxzOqz396M?~ITJJx(loG~7 zKN3U)2iwrY#t9}gY(#|o2qhbup#-6pJQ?0p;lW?XyIYv44DYP)AVS|=X+_s~Uqj!o zphffUinn3TQnjPM0zgP1Wib()a|IEcbBR!ME{w-_TG9mW*XW{s27Y7EwKhbXgE7(g;2Gy6%rvo%lb7^Mi3tNE*PMS>wE6@*q&)#r`b#o1L`cilZ9KH|pe}_ZA<7lpFX^1NQOQ^D^R*zj zuj*c6mT5r{A*B2=#kcnEHyCruGUjh9F5#xwN>+-(E!;&d!$Hph zM6rAJ76J<*zrleS^T<3x9mgS-hfe7IULvArB@6U@W--O!Q(;8-tfl$%s=F`vXfk`t zu5JZ@(5^21R%ln3%fEGhe3fjG47Qkfd#IXiUSsx?`$KiAO|^B)$Sib^XcHoW_vvYR zR1G~xi!I7MBBO*i&l^Y+yT7QHcx7Asn0q_SE)y{S^hKtQz%c+mLuSKj0NVj*L&h2d z;1vLAWcDIZ2jCE7ZYO|ODkT;o^G^cP{R!+8#HX)e0!yC=7Rh8@uwCw3Kz3b`W_a_mHe`YVXwDEKuv7aE-i<}=T-A`Y69yC-_nMhFKH z;@C@G!N}E6YP*?b=?{UPMqqa{UGh4BSpdArQjwwz@w`%6lOjS$p-W0W+p^M=W=6|r zBO=tOH?jq#%ku$*MxFE2ItF8HiXcaQDS(g^yE^LWcOjw6J#hPx!7)C~DU z!%uUOu~pH4ayaYx^isD+18Y`t;jn@nzGn8&11K64jCVLpAr58Spx~OrbsNb4KRKkg zswRi8nnhY?`;(!dr;=5h(%CvzS327OAf&T0x}9DX9=*{2VBDcNWLk9esyE1bBXcJ@`dpcMp^3o@p4-UVrgC-xU~ctj{K^*x54M=|>3 zK7`5Y^B`gxR9N}3fvDw9!FpTGUMlRDIk^-)(>hTJpsPAjqX<$brUB?)ouJy!ViWt| zY5fq3LA4LD*r<9$KQ0J@dM|5e?0u_dc@zk-088L9!Si|!|OfKlP#^3c5py04aAy@)s{u=K); zFt_xoW1C9V8vt}w59TU@)PrUKAwA$s724Mlgj#y#EO-cKuY~~%7DRCN+MHYjXD^w~ zR7BINdO`JW?*_J3D1v0mn7#^IU5&!^67yqn)p;u}MMw1LRRZYh=+!8KWOG_~vnkQ{ zEH)9Gy?()gTO<3brl$D>lzFxR=&X6_z)kjIgMk|ne&CkV{UYlA9|O8Ch@kGTJ#t&h zekzmh0MJ#XaPa({5TsIM0fbDttGX|@ zuIoYtXlQk>1`yJPwa;Mgt~1CEp5;bz-!*%tx%{dl#V^f)S`YfOG&p&Mmg5bo1Jv%h z0J^H(&59tkyA?o)qi!+ab~dqA0}ipcLiLC&8i#b9#Zu7FgH{Qkds*ayvW89kN+zyp z?5ncOSp<}2HUj9ZWp--f5)GfvCag$jHN1`0mCY^%&{YlZPz0&r&Y|5s{9IsVL3JH8 zyo%Koi?sl{%3{4DNET-U=za}vViUg-4R2vzm4+`Spfr3LfbP|B-Vs{KCVJqjVAKT{ zFC+@x2^vg?9^7aOdAkZ$SGrIQpsTu2rwCFP8US>^F3e>UzY<+&W?z*qv=UId&<>zm zbs;>3zaI!nLLE^msOa&_G8)W*zTlHYtJ}=oSFoI?&oWHz&t7zF?;AZG;{p5rURWM2NfpvRZe-KM9v#1!ANBT`s>iv;W&;Dfg3p z3_R`B-}l_|lt8628_uLP079C&9(FiQ5u_c?>TWyq_8C8cw>ubnj5l+iu}?(19C;qS zZzT6PpWJ9yb4{b_8CjhVAjImr8KpcV)20ZL)ujNs)#aqQXzgGV{USx)qV*^M!N(T| zb0pUo<5#e{aN;=~#ST9Cwr-lP14s4DsQz^q5g`o_MDT%7zlJ;z zntS|`zov1A2CP&~F5-|@P>@P%`EJ{;YHcZK2tjIXC4f+$ySjId=d`}V^V6Ge4^Q-! zId~iV$Ct~k9r5-HD`t(gjcxFQNPLeW57}4$jBG0QIlg)zuVi-Z_?JC6J=|k8B~1 zWE!i(k$AUr38>(_k$`fT^9iV-XamsIp;)R2aws|gbn8$EH_kEWGaQJw)F1$EbZpj% zCko}^3fd3*D5AtE)X&a6_lyBp!}>@9@@jTXIgdI5%6T*Z=vL=}j!lrB0AtLWl-#3@zgAw`Zx3)`} zFz=6)X)1ycyPN?k9po6rnZLp=c}zl*2~$0WM+EIthh9U82tJ0FB|`Zp2Q#psOs-QUu9jBY^H@kq&A;oA{MDs5bUhIjE%sl!NL3@LzXO z53SZg{fTCbLmU*Vtb|qZ;2vPuK~crsw*wKqAjCmk2rABT;26c}w?Ux-fVRtOmMFWd zBhY!fY+!X|mvaGhRcV_QK`L!4fbLaV+GRVN2->BDLTd~hR;V7)E{)^6&SEKOh|I`h zC4lZ_k#@C^3Vh(h~NZ9L}&u*Pz0$(&I#SDMQF|4&)a6fmze>`3x?F|(ggEPz|{zX zt|oIUJBmXVXsq%v+>Jtr!}8XS%du9x1}i;A>KJwJK0AWq^hVHz#Qv*4g2U76gAn zL4;lfCPq#UY&b0d@G+7*8@o>r?S=2+A_?%slw390-1;pZn0N;ciZ7^iV^OVz;@INR z)on$+1}$tQKPXOb3oTpH!z@0c;hY3OE%mYll)_a32-zfvhHX+1L7OBZ zWRtauAQi42KuF;zpS5j8g`ZeYL<=>F-T;PrGefQz1vS#(rbMCW|NWz1Gp9dT@~+QMUdiM z1|THfuC5)yoEEqUqDQok7I;oFUqaw3*%1_{>mcmXlLIcV5I^tQUc25bpYsIm#1H$c^-#+i)ep& zg{E@~8VyFc@;qGd6`Fzwni&xxGxKZYB8!1+K}8l>wxD#V3P4DQ=pI5kB#5}?hRZEuY%>AbzoXLV(7Z2-Eej7t?kDq{zL?o~#vWt`K|=g!+(mem!DRRFrmVyz-5 zP8mS=vPgTI%_e>&_SVF{Dtl`opzLiifOVeOyT{&^u^+3mx6HwQP<{do(7i0;W*&k4 z@esr@(K3k@R`U8_tRT}?Fjny9vA_%Qi3r6CevMqL5W3&&o`DvWT2=rEspWda3e}1r z)v^vix2h$Wb5B@xHw<&3My zA&S#8p|!05^oCA5OM-rWjT<`pK^-AY&SV!Ky&xi_b?X*^5Sf zN_Nr-DBf!UXx{6+k{s`$-Q?LURlGL=2=Tsd79|fUv?zk)eKCOba6W6cBq%_d_kWhL zl`En}-fTx8INOb&o&;w*K?Gej5g}LY*T_j}AZe&Yk9&4NN)-S?Qd$oUsa6DKwgb@J zQu_J5AJ5L_LAIa5#`v`Z_d3tc8rYc|q6KN*wV6u*qAKBodd&p1eYN^UVqfh5w2rOt zN^;T*{WQ-wCm_9209}<{r6Ne_)d1*j>FEg$Gc!IY7R~6513^d_FdP#c5Bb;>tHii1 zibM8G<)agcmi=vmUyN{HhM*QS1UU@ux!peu=`j#j1qi#X(R8{D@~sA-_v7nW zqW0q(2&nz|xdare%>Y8Iu7_7^RRqauJAjbJk>J|)vQ#lP4M0~Jo23Ynu|@zP#w2(QK2zpLli~L{uiahmc|Gpzv6UyHMVa6D zMk9|@zleJlBG`N&`RoAT;o z_Z6hjz28c#Cdn>+E3u9g$LKiC-kh=RZHdCHxjnx(4s@Z#l*`Rv@LXHH%Mfu#Hxv^j)S! zT=BC2q~>-0XFJbD4`#s4kxqI{_6>&WII=L5^tiOUly{wQu;bCjJSX$Mk4T{c5$P|0 zmm?MDX-&m9P@;8$vNO<3E1|VOA z;CuO(5x@)e)BI4(N&@P`?e6&i)Yl*?0Cd6T;3xU^ejfZ0p7#cS?*rT*EIo^2im79h zBLg2L#a!&EJ-^<|gP%HDZ?)E+J?8w-eX6a$Cd@uky~FmTKJ(c?<~-H?*jHV?{LAVS z-Pp*?;DabQc7#*0CSpN;hb#}gk+jaX(%F^%79@wZ$FNbEPXe%0Zf5#l;;-{r!5PP2 z&8PYG+qo3*EGw-)ee1FupS~?Q9c?zV^eD@f9~`w3m}U)-ul=Z z@1_v;@3@ONDoGIH$lT{kmtwR|wEAW42q0o@QOlhdL~M&EhzyZo4JjxYP6N;t8R8vs z{Hn$*kV)@UCdS)@yf)re0?K%o5(s`wgEF82>zxB4y3(D@iJS*$bhiLP{ztD2JZ1IRmA2lHd>;u5k1@F8~jVsJG8Jqu1F(8*aa zZ0zeh6NagD?`$}m+yrMs3N7^IU_q?q%fU^gATA{{jf0DWu1!9^-s2{LJ%so1b@|qJ z3$97m7Rgs(7W4X(W2ub#);Cvwp|8U9Cj#I47TsRP>S{(<37{*=WVna=GXl-t`-V)v z$R?O6EUxUCHM9VT2nc}wZW#qIA|d{6 zr5Y;r5g|&JUPMboW?lHbT!@i#G+8PUk6B3Z(FGYQ5)ZV;~BIG0@TzL~!m|i}Y4EPBP88 z7h~8*dBa|Te5lD1^ohf+o0K3r*yLI~!0MXJs!wh4y7<_5IJypgX-hoG8lvm$3SYr! zb)@p1?}x<-^P)~>AzcX$BJwYfJDDYc8a*=jwlZVeYVgZBPcPS`(H&Ep=owWIG8d#b zM+i5K7c7VsyZp=;4@z7%3zlmt24PbnFJpDMDTFRmeBZEs?0dxSc_sWM`&%Wpf`|M48msEeXZY7-D z#xb(jAj5;>7T+zSKY&PB?m1+)3zFC^lj-M=C`lwPk7RUwD{bta)$uK1KfcxDZ6h9! z?~xmC!lChIyX!RG&LyjiH+3;I-hx=mcxOo=INqJ6u)6UUC9ERJ;8?H4qE^3Pt0e^) zYdvP1eB!me`*C4akK*{0BE7Cs&xUA07g5ktbAl!u5;X5ftdpQ;vqwS0>a>`YVKtFL z_X@g&B)cT&#iSsDHu}BsJIw!p(^JdzkQ#gXMQG`?vGisU-=V>NTwp58R*Y=A{kDBj|LDj1(pO5oB~TY1+K)X%M`dBcPMZ$ zCSLs%hhR?*7?d}~eFClFK}2qf>&L}`dntAVhbLuEqXPNRnq}Q?VM&xyO?uln5}ei{ zABs|VJ1rEY^d|yQimaa+SY553=C0Zo@lT!pHkqLp;}UxX7vr4$qQS*D5o=zI8?xwV zMt9POFX>V?uoR5o2f*EHd6!Q%WmUq-nFC(DwP3PZ(taWfenmO z0D1$XlEDAW21X6J33~ocPe*D`bQ&pm8yH71?7+cKQqt-(Tl)hj2y9>s*a(POxFCJQ zAgO8C^Rb8TTFEEx$4wM@kC2fvV&?++DKNO@k}_kr0y6$AkYTe3U#Y*Tr)>;F2xVD@ z&2k_0&F=(daEWc4fpinL@|Pl|FX(><9WV|$_w+?^@Ag5~idE0Fja^ZO_Zp2uR=#5I z#wMz4=@50%`=GM}Zb+oBGOV|4+iRo^rF~AZjTRu%t^G%hW^KdR0xA7)+RzuDtm^zt zPzRv=6@@y{Fv@#jbyPOO_A-N+c^cfmg10M`KLE3sfHy9ce*q!vj!dslf$6=etf!3f z@sQ3));koLg{)Wp7u@MXW`i_Tyutxg!M8PeRVSmW{U@Ao=cFNK8$XF;V{?!tSqQZJ zG%zt4FLEl|;XvDnJH~svQaXj0BP_G(RNLrnoP_h;pP0tQ_|KyrCK`DNz?J}Px@2ru z;6xNiPD1w7)6nkYfbFMoiX9IyWyN1az8Z{JhI7mLw(%NLa$MAOYOc18IY`MHOw(y@ zvyJ6Q$#3z?DUdQALJR+V%QiN78^{eK$(g`)TyGl5k&%+*?I7pe0N_TmB>5xO3t0fs zL(HPQF91{lux@u!rn8xJ!R$5T!AQ~}T;sUx67GK+u`NfQ8yq;S&qUK1R3>()r2mJz!|85N$tgI6O$#N%eKUzpGg zUuZNF3a#KvUyX>c_cfh@4}ypz^RWFn%Hv3Cl;-s+j0O<#8IJ5T>e1liDxuLJA~YJU z5N5L4AC091l!C6L%$0(cHU~zdnt&ROdI0}#G$_{pb2O-yq0t~BG#ZT%W^((8E4I-> zK#fK_Wv)h}gMhLP=XZh8$O8D^8VwpZg{EzTh>&dvB4`_e2#y93KeG)wvCwD`p+-Y~ z2x3gZ47n|4krOzR?C;GaRgiGxe~;qiW1zMS`Aj|>%*DQ&j*}9$ zBQ+&K$c|3Iw>zQ`2SZ`G=+gkA&%;rt;H)45&(##B(KruYf*LYMNGDdZ6Z`ejG#Pt` zXc7^kDTp9VzXoX*kQW~8ZD;wxWq0`E;*ckgh*<9R0YrR}ds!H~qnvFR2CK&x6(j?o z^?9VIa9bZir)<3+8BpM`CJxyu_#on@h6fO-yTwVPn0jesk1fnP@{@9-a;%f8EsDk5ZwY%1|x<>09L!{6i)DaMcHtA z)bpjx{XircQ?#*qaITc<>pxev`7@R*DesI-{aM6OsA@XQtEmJ)!Q zPcj7RAOII%#BMmZV53%rKKuAhNY^=UgqYhqKIG@j<)T-rQ)o^gLgs|Ri-R&6=n!(w ze$qA$!%`)AsqHO2YJqLSfV{{-sk95em9Q7g1E1W??xCp&q7i<&;E({_FaU1GA8cWWB64bK~ zkHty~xAZlF>z8O*Jd-@B!Z2o|6o8Yw20#;lz89EI9#@Ag1a2sk#o=PsQd9ae0Kq9; z-01o(4)c{|P`~=#=xDxaXUw6I(+;Za_h@ zDqeK|Si@)r-Q>u)Q*bqBF&rFqK`5gU#HaD0T2aKW1{FmRo}zf#2wgK4prK9PLqjh( z1tkA#qT>{vfea5K%9opHTC}(s;1;+>u6y4}_JQuVvV$LBW285zwiB2hD^3;y zSOFk<2Ntdkp;;9Gt3Kj(A_~)c8#FWPq)3V0+aSW*+ep3%-&)HCejh0* z>OCGq10a4>1Uqnk&#yw}Y1Q*joaE6%Fsq?b@>BHuY_LBcK+$M(K;F5qq&5KM&u=Vl zXc_W-UxixJ4H@$RC^wWP;JcwJySqCjggWkC7i-`H~}7%Vd6Itcx92^c>qU#=u2;VZ_b zZ5pu)p5hz&LdnpJZQ~H6 z=q@NpV8eL9r2r1Xrty*UY~vQB=)VA1x8mCcNYOVUrt{Y0w$bMa02iU;dSqTFusKTX z#kNs{6rBnnjnHobQuIX2bS`|_HvWnf#TK+P=UMasDS8xumysz!_!GSyzySz-<{?F2 zw@gvkD;e^Cx;ZQOM7 zk*OzOBM7_=(cox~Z9m6!j>qUNLyAs8wW2oLxD+Y62qhmw_;pVK7>$x9Wd2Q{6u=7@ ziQcyZ7!05d@*W7QiXNXdowHuDjqMu&Y?$!oM0%S14?G_gosvlY9-6IsZ&R`Df&F{uw}b`)3L?=${FP{Iei}{+WoJe1vr7{m2YjXhi(^+zb zZS=nq`FEl1m%-lNMzXF3;K0^)MzZ1nT9EmPz$2!aIqe$TSd3(SYi1@tWEO0}4oEI2AfN-Z?$3FW5esZcadbE!>?%#Nz=VP@u& zCco|(2=X341$!}1&*9YPC7fnp#x&3J?wd`YjX~T6Ck*0yDEpFL(ujYK?4U7t2*48G z`8}|aSbSU5+jtjT?4(}+=AzSa6Ox%rRAxLX7_m>zu#GA!{twXTKvN+1J5|)r9pn6g)mr~=7f~qV*%HKZXw81dwaPsq`p2Il;72ZZ67pnOu zMv}wF@c(#8UfWis{guFL7izS889&&H85kSzdtpD;;2XS-~`9;wb z{(+Svlqj5;$i0SCw4>>D8=JPqv9OV^kcu8O3t!}~5O8oGr|2QvdpySvw`g}o51T1h z?XZ$IHdNLAst>CDRUcIQs~)KLR|#@|wG)9nYGNAYHo$y{sR-M}a;LWqfZm^93P5}5 zj&74C+C3QUI#;0G$4u|mO$7jb>!t<(oweNQttX&v-OMJSru-%VobvUAPL28n-|1cJ zl%o}5AebontLbWmfLaF?!UvT?_@Gh<57Y`lFtp*$)oEzMT@b+ycOr5d?gbnv9>b7| zo-k8-i;@VAnBIvYBDcrDfzo>n1oR#QfZQGf0lmj?B>=TWSplGX_89Wmui#8i#G3XP z{N+U--v55nH{WM-=DP{dMbDXe+Ma3FMeSx!J$z!%&;K{=xf+rydeOJ%Isn?98vtl~ zo(rIRyrXZ=&20B2-=5ppuDTVwjO{9WHm(Ao?75VHvgb+w|D*Q&@-M}nwc>K&U$n#= z7&h=Foi^|qj+`>^X#|vk&jO$gype!1@c9IkfwuwpZy30?RBn|QEj2CeXo(2SygsNL ztq&?k>w((Q5)93}|A${iboS=+e9o?K4{UvT(V2nhY%!1{fI)PYHRDSF?e0NFj76>$ z{|iFUQ~3m$m3|5TUIx~Pv7%o#i9HFFIq#!vP&>kqktTu?n*p_KV%*IT1wL-*wFu*? zA_Xs3<4PPiAoUy>=~+&ii&asN$KnNUwq?YXmkRDI$tf%L9nAYh_!KH44W0&qt9|WV)Fu92r2QTlm#G z@8LLfrst?gT0$oG>VS)_1fX4PEr6hlWrx;tCqzbi^tej9dd+Ab|1M z2U|T7S3481GxGpa-*>QdocS;Sq`voIAvgvL{Siog&jBzTI&m{n-z8Yw*(T7Lm@4PP zytauLUMLP=yADvlg}PX8;gQG}^9y{*Ks$}{mx>F_0Nn5Jh*j{fF}%uhN20mP%e zvha$28%La?g+R;&1Mw!)Es9`Rn+aUQAE@H#Ro+5r1)}_Ar;vA0cyL^J7o~uAQF!oX zOXyAthd6X6h3iqdlOi`omV%(ZDdON2NP1eTBA}+FIs$51ngu|1mekX8j355r({m7l zcHin*#srX|P>TqEQ>B1+Z+LKscn7C|cW`*fnBgu?0q^2y1n%S%@=lIM;BF4{`D&rW zZSnF~9KBK^y#7z3koLL+#`eZ{VVOJ%r>l|5X;6>eYa4?X0=UF9?Z_e&_rd7~r1C}- z-}fMP4Ic6U!|C||o{~ahWzQdP8N<^*FfI}<|NqGQ4)C~&tL?d4?%vg|R;yLDY}sajp=%QLQBf6A0 z-}lU&*}K9da{2iG=lk#T%wZIEz&2z?zuEdkC#=Dm#Or;z}g_w%NqL2U()4N+zV zKZY!g%7!RmUPNXb)k=|>k0=LsP#F(G5Dx{XAu2xXM&T(bA@nc=9MxL!5O5~0pv4c8 zB^}2ZNC~o!L1M$c4N`;-3YASou29&pUnoIdh7j~ot-PluA-8}leu-i5Q)m%u2!7{m zn)e_;JvnhQB=wTtR*t14IEJ3u))#Fw2{?wH_ZujF6WMV#ChsJGW&obkNu3YCM=A}@ z#^k&}iQ*D=o15g&oih0g4%mi&81ld{QgnBF_|YQ{b`?2^#xWKzcl2xUv7UjAA^!d6~tbO2XP!1{KRFWOfKx9a*4 zsY?PleiYPi0Yq(O4poGT@^*nnbufo^3TTt$(8NDeeCBVm+@p|f0du{LU<}xRPg0;HBnX*%Mnh+d5%6LQ3GIC zAL;?@Ft3Tg4D)6am|JhzS8)b% zzaAjo#R*)daaJ5QGe^ngMLv&`N-| zVJHI=X&*Z1VU^m4E`|_nABJ3+f3kh(Wst%4VaQF6X&?F-f*xLp5*&#Z^+qVb`&5E& zoYXPZR1F;DW8?g-vzDF1v(Xs&xU;66!;>I$_`*xKM#qKoZFH8Ab(IGCd|NGmRh$NZ zpyGrP$VyJ(^Nz&Y@JzcJ85P2%<;5IGPJyZT zJKmyqV&$Xcd4Ol3I4b(iud&v_m;BKW@Z(mWE-zR=gZ;=IQQ|5V1LYemSOi}6D|eKB z4@2%biylj((p>1OSiI13+r|6?x2l`#0JjB%WthaA*8$+KArN| z$Dryr_OTJ5ZY|NrJY!8`OM?VCvH>nxN!A6imAn|qJFyLb=K3fU+XU!tABAIE13jpb za_KEsJePiRNfivhi&W63hX}M*kEdpF@q1t?^zpCA$n!A#h4kE=6xz;nIMI-!d~%pjbio%*wJ@#sAMP|DMJ&1Ia4Oi1Ri^R+;VeLI}Ra zCBeSMU4$gtmpnZL<|R)bfPKlMur?)xdhN9->4nu_y9EJ)(4@1q; zB4@BUqeT*a`YkR*K(pyRbPbO8w~4 zcfUk?19!eBS)wcEbTkbqsFD+jy#vQx(9Spz(R~D9gGjcrs%&k>wk=beYoy*z#+W1G zNo^KuI>zmr)pekj$F>3Q8{5HJ6}uQ=)*ymNwQ@HB*^5kI_wu?(GJzKWyhAH)S18nS zX3&5}=|RO7fImemTrYxMIkBDar?>9Jc89f+%?tAF9<)T#E0wL|>#c`(v?{s_RIF@I z{D`hSirjb()xA6t>%T0j_R_I1W9I49SYgxN%j83rhxU@3=AJLNQySpd_4xC*54q1E zVr1@(_>-1U#X4afjr9Tut)gFpHTpe%sy9QjLZMg!f4=-o=rz-z&#HvmwWR5dkJh2TuVK|XM@rpICmm`5H;hIePMz4+}(A2bkkyGBXN(` zk2vKoe zR2>FWvOi9uo&?JS1h-+M=A;{<>X$Gj`AL=|U){JH;|F;i#h;(og|I%0w#~scAAdu^ zOQ=yEdKiz|q$*&J#pr-F21|rOn+V!iG*Ci2Gp4+6Zqmmj;+tdSa?#BQ1nbrDU*WJ) z^j0*1F!6D4saoW-oeppxz~p;m<=VAQ8UE=Ybk-grp z5W)=%?tKhg7Q)g;@DG5g@N^1HycC`uxC>kRVB+sWj*W2sLkqJxY&;Dz_7Q}IY#xsM zbSL8{ny+{cQTn~;II<&y*Qozl7aRFW%BZDiGNb?g9V*u0zun%gm z+acZj$j%?dyHv+CS`zj4plB~g6Y-;HNknC^ZpwY&AxTvJHiHvY14@J&6DjpH4Q!hD z*84|+%d2ozV%@wa5q1hmsho>KT?-Zid~JX5F~t2Ce#SfwriXE^PPyyD8i|a&>PPZ) z1?71@C=Xt-+wrDLY5n?2A`)xeygG#aD@N4?c`ktEd4h)+Z#cz+2dB2P%pG8Nf3&j+84!7NPlPk2>v z(0LdL!$ivxju-ob4~_=7k^m;UFS2A;><7J$dqNkW8o!7hWW<#K2SXtzz;XovLpxzU zx?`B=p+>fHeoosLG~8njFfW>C?m0phUiN)U$x z*TW*Ay$P2L8j*cqM1uLStb;Zo`T-=kYH?J(4I?hI9sz(6*&-PG@(4xrOf9zRS0MXV8-My@TLaLKlHMxCEO$NKPRoAe=8?PCk=!|XBlUV(=ZY`+hNT*soF zx)~;VJY!EoC{%aGzF1T-#<0Yy!)nlBnJ(0;fQS8=5`=}qJP7Sg^f3Im$KmHEM<3CS zYcW!|6+iF748t<8itYxRC`j3K*yh0$&j4LTKmH>^`Zs+Jzs%RL}JNiUH7 z&sW2Vom<&euze0wz7Es0_8p*ail4Gw@pC;4u3GXw#(y0`tr~`|Xdc4Rq234^L#-Oa z@fL&ag6O(_J_+0Q2)67E%)t+aUrJS0=XgKh|C~EvM;S!fk?OEshnNhj>M5NIP%#a%V{00X5YM6$nulI#0dmgsKQDKKaPx+$Uza4!O zKV|RYho?5SSE2SqEir75w?0G;45+{EN$c~Lo>AymbE#>T8C4abvW-gEN?)TpLsCT^Cc%nCMG~Dh#~AH{Oe0F`(2U*puIlbpHf<59|d8 z=XtTS0Qv~_NO(}*4nTD~`G$D|-$4x!EZ21k@ZvE3+D%TDpm&cf`~?O$<#>BaXC66S=sb4-M+LjX>-7P3(y*Fw&M-3r-4kQK6B__UCd7Yq{8 z60$;ek>3|G2L4n)NQ14Ad0=2F3Vb2IK~6410L~;Y`3dX;3`|9zLuRG#fc2t6_Yv5u zVK2aLsn}frbp*RGQEkV4;pSaFZ2m4WEHo#IW*qLFq2*g=iXIKO5 zeumAY)z7fmu-go4BhVSU)e3E9lr)sG^WS&I;ev#!pp9)_;9tB+Pc zv(#OI%qk}cWL6EZ&8&I?lUYpw+01IDlg+ICZy%Idy}q+#mbzn5W*LG_Z3-MYnPmxq z%u3@8gUzg30PFn@M4yvcmXOV?dEj9ber6@8Sql*DWq4=eY@jo&kum5DYo^uDuvXZu zc6AU0s^gak13f`D)4J%>lxZJ;6?2V+gT%CiteEBCv0_Rk_3lA<$Z5&SQ{Y_gSJF6Z zm?22X=xXlWi3w(~n%4zGxE`)KnrjGF%!S~{DGW;p6hP`dro0kLN=A# z`%wf7W0$*d+@FQ9u`Y}*#-Iyh8LfU{48U#+BfTiMFs?ut+>vHAxEc&r%mx4}=F?!! z5z`W~Vm=6-+`^c}@JwM;-aV)=3?Wb$w}L09Fgk)E?0C+rr=CQI)^G6Dh0$V!(M(?0FS*rGt*|E_t8`m$aa0HFdARO1 z)&hqv0=eo{hA+M3TcSq>{jl4Sfp;H(9vN(KEruh2;LEFqy$<%_lRcI9FglbbIy^BN zGfha;4B%WH^C-cx`~C62BhE07Vi*ENiBl9y5OG{~{H+Y_QKv$B{tf`E-CYFI)Oep= zhwFP0`a#Hx zH8^ifIOTl_UzTug$cw)hBy1BIhEQbK*o@en>-4a(6?QYW?SS1XM;AeM*w`z4de}JM z&q6!4wFIeTc^umgkl!CRo&|nXDLb|`*bW=#fFT72Gi>Aly!-(OIado=1G^Ej9(F5a z6G2wUX5rI9ZunrJA>jbr60$3}x0Q{MNkOo^JGhiqfB;+Cl;LOuP_DJNqn)ShM zg;Wpb2w4tjW(kW23uy^iA#2I+3wgyLAq}=dUY#qXv?0ldl$rp+osJU0TLMcPbEC$; zH2CI{=!>W(jfl{>za-iMg=?XG*O>bjYJMl|d545kE}MZ~N_D?8*=0MR9s)ocAWcy@ zfNhFu2(op*o{XmMHv!nX-%OzE{*9=(Z$Kutw`7iA6(AHGis_Fu58r`h23bt=Ufu21P)^`qn5vtHoe@$_^I!>n^MHt|&_C3`r_6Loj|U&KAZ11ha)v{z$ekN)cF2 zVbs#m6h;GpEsU82rZ8q}mq1}`gOG9x!xFNE!MfB2pU$4TE_K3g>QXoCwk|EBgQ-gc z^s%2VzVb%{#a9bpi?5Nu6yGeenc{09$QEBa8BOsm0;xhzWd|!hj zr}zxP6otjv;!8dni7N7T6w)lz>SWfX()6o=P9e^#qMgmiOv$RW~ z__jhwImKrQxy9E4pH8DLzIND6@hyVg7GDn?SbQw-KKj^S`%sT(eU!s)ebmqaK2#pZ z=k-9&vN9P~HPQaQC(C(DAIe?MGuU?2mLMx-GESe(ko{%GHrVX|qLUyy%IOw9J<3Tf z(PdnDTAVNKwHgg0Bkj{Cy;8cWK!1z zOeNw_s+qq0NnLBuQ-}2=%F;zXe^S>AyH%Ecg6yQu>lQwl)K$T5^|+P}PxxBV0N^ak zmr32U$8=Lc*=15^2$WwYb(WBAs%A1Y(^Sm{u({GkkZr1VN9czH70M8-LhS>N9ECCj zQ{Wb773v81$x$dnFn%n~DpV%~vkKJ%V0eFlz;YC-pN>YMye9(+RYhPFs#d!M6zT?q zl%r6V;5SuKPU;%q4^`6Tgl;D6oXokL%*`giL@vgOTpK}P64yyzeR}HA4ZCSMmcee7 zVSpgpa-^RkpKdwgj}K}&EFs%+)R3Po2Pb3=0M2_l!kH3~p6kqp-A33(kd3fY_;iHl z4UW(fvJv)>9}&uA_h`Ruqhc~|47QV9OE8mNOYrlFL#loR>GYSmoWXccBM;3CrV4<4 zvMBu}hzoDEq{52Q8-i7OOUNpHEkiI$-vD5hekMUy>E|KzeS=DG2v+HD0!NP08-h_v zi?d39ub)45s$vMnkHuM~pAEsR(zgQ`-o*$kr+@CEqfz=^0NaZ86BwoUo)MRT()S~z z9HqAe+dn79*C_QW7R=U1rZ}gkQ(tYb)O)}Va77*h%YSdGtJdBe>u;MmkN85?xXfhf9kHVx$SJDZuXTPbD}=<3cHXPf4e z&SnwpwzKJ_13DX5Y9s(e(8FZ!xnPw9u*2k90y9i*Ae$K`&m_oJ!`Wms)vyh~R>Mw$ zY&8r$r__PLYG??y8pgqqGfXxFQ%x++R>R@&lhgMYg7ITbfUSnL1g07`XqP}W+yf!yR6|R!)zD?LJ`+Bj(NG8~^K1aqk+i{X3%Zja z+pc#DpKjOh_0w;Mpq7wr*ZautuVGyb{@`k$!FFi;XE3l3{MEoX>taI>j!A*$Y~&0R z!s#H4A)(eM+-eA$pe~+q9h!#ck+7*a%6Qi;cys%r&e!}G63U%|dQe5z&7Fb-2g2{e zFI(T_+_Wq<87$-AC|_LHfgP^$=DLw~|Lx2y*sZ#?5Qw^|#N@d+ne@EAycr(7Q30IZ zKjz6B&~|u8;{qUgUA#WHS@iaGu_Z`8dRrlc$>0%P!zDp+=lB2tpH75dUBMP1Sf}18 zkUp;m!1j540Jegu7XVBJD+jO@tcD<4!RpCqDp(VMO>r|pwt`KEcscV>L$DQW1~_sm zm?4-7U~#sB%`%BLEB1z9{8*f=V670$RE1vARuh;4tkW)m0&GV}IR$75xdqq= zpU!T60nP$21=s?+Ex>jvX%;>`R5>4`0OqnCs#rpHsM1D$OhMh}F)&yJ;7oHyx{m?$GGJ`|^F9Em zeAy3bokY?L-|S=wI42nY@}?{y>VK3f_6EES=m3Yw&@254LO<9UCh4gLFzKm--KM9J zAe)|9!l%hLlYJ^nK;}p`bd#PE8=T#z@`B;GSaZ z=p1_1i8GKb-ogfT2GZ*!V@y~LV|dva9%ITH2wuTL0+aL5+kSHTo$;|nlTo5{9Th4P z&`z+M4;B$PAzv;8q;`Z{#hqBm;A%!_X~-$AUE<1iqtK%$Tou~yUpV%7I)19W(nIh! zd;sqTRq0G)^-7O3)^zDBU*LEE7((TxzXUb!->BmiDl{FsR))x=#rwKFrjEWgriQI2 zqy)%k01Bx#LasK%TmE58&HD^zUs8!PcA+w3=Pk^zRH-*?jVvx-=6b2)eTLCsm@u;t zwQpy#Y#1VY;=Z|>y^*dC3B?qd96-!`7x5$Ksl=23~~rt3(?!fDv3QtzvpEH3}S_2MR6GT_V&g#Ow6 zOc^8_agJ=Gva%hxwwC`2-_OT>rk+fey_^c~8$VZ%1A)2f6|ALwXVbXJTCS5# zXu>8an+Folbf?%7Mw4Y9Tr~B&~Us2@7sb3UhkOeHJ%1s@JceBHwp~p;2(MYi0Hbo z*U&z{IKD9i&3{U-7Z$vhgkpJBkggo0sP8wvIsN(s_78C4Izl~ysBA0A<1#`M>|8<+ zhh{poYll|tkoY}3JmrUx|I+BhquU4Yj4|=M16bN*L|*c%om`w*9CpyU$iEG~L!ROD zSfzhQRlW!mDEe@xbQW0V`zTa;BGA1WsS+|KBc;pG*PM=40B6oi$nBFPJRC2l7oYT@ z=8}Rw6!E`|kP6R$dnZigy^d5ZR>@0IKq(J^&(ScI&u5}+!8@7$7sp5g-VM8L zz?Tt71D@iThYvHk^2N$%8VjKV^!G|--r)!%{deiYl>}G~P`RvF0<44G2G~fThd{rC zr&*dW7Vg9bB|7OZ%a@$KtBV_>OE>vn~~vAh08kBMu6*Q-7s7_32^nS_Z)_)CXxbtNHG3LfDn~0NYlB9KWm0?2y9+V zZ2?nxkR$PRGrnK?@huC+HxP_3{pJeA=PqWx!B6EJC+gk_P{#mxKI8^~MgnOLbVvUZ zgu5F#Ao^Sh@F+m$FKD~+7DIQhNAFsUZgyvw%1a%mcz;-~AlMBq&prw^G;NhQiI_PY zmbnD*lbQFptKNXAdjZzU<53KWq3EhpSK9F*l5*N5A{3yv24!Q;>$rTgKb&i}=5F5f}M>ezJ?01%_4bBBbBc zUBv%K(q1qqZ%+jNpY497!d-@Fw)sd8$SPYL&x~%^aRX=dgM^>ZkN?L#LGaKbj9x=s z_$heL(GOIF5?bE&|?oauzc7=7fmnl z*v9gaCL4Y{<3|W+YvXKdEr);Acftgd2bZGF*Ra75Gin=*5D<)Kf)T>dn{6ADBy!r? zHYSru8J7h#!3%hhdEae6Q-36s41`4_8U@ux2$1Vl2IPVf(${VFRw2=L{jP%+aurnU%wYv#|1;gc<73jI64G6uDp&y$U z-HL+ViU5!BVjIC;PCM>ez$B6IQbcV;LC?2gsXQF>k1?3EIL^po{Hc)@1S(XQaCPH82V5Ip7Q+ScxSL7q(1#%X7Vt5W z-cK#SG>Q-V0`GPDFMKB(}nhR*Y0+uS0v_&w3#bf?9UYq_UDQc zc0I!@OK@hW)ae+OKZi_7peajiC}+q>u7XKyluqP9W>#M}^Y1zLQ{@{6x?j!!Sx4M%gz`CD_97Va}ztuClF6A+W5@ zn^r~$(#lvrrS!Ae8rF|=PQjK*2)TYFp1NY|XDIQo7ffw6+WL{S1>+HdZUObVDkg4< z-bv90yIIcfgk9#cyfdJiK<2V?PHGwXz8|gc55Q{#vpo-S=f0}21V6&JsAcew*u;}J z%XRep%IFl|GV@^tNd9fSzfyJr&@iaTK2N(UQ72m(8tHkK*vDKqc1?;7cq#P^P`tS%X(nPVtkCtBz>^w4|5XUTwnb}tFQaxA&JNEQBo5Dpy! z_N(+Ll1=p<2;w%Fl8z`n)uUT1SupBHes#;mq2JwLF1`{TZV@ro0;v*k4oM58&XVgA zz=1qOb)OB2ZYB47x?Yp#Gw|F+aUM*4?~5ut4|%#QI99n~DHbdtNnz$YZGz;NRp6`ZBQcQCxL`K z2OdetrzsAd_z2Huo+`Y1v8!%@Dfz%D+!pg~vEQS`o(SGg{a(0aWX{N;WaN<7q-S9; z0Cqca*b~wJdvdnfB^z?}xn#5P*y8DwZj8UJH)lh}nyezd^~cTuP@4;&ifXx0-7LK*)zDgm#f8iM#2DVezuR( zKk)f)$x*GcTZTL+ZHKmi-Kth2qWDSGTC@tPB@Ne32>p}o(6O7P0In01EzAx_iE{>C zBn*1du>yWn;hAUqIkXU2iLfN^UPd-2@jj`n$C63`cOvPpQW&p-vk~xol3tE3c?UIs zh4Jbb_g>iBVGrY@LGH}}-30iaO8m$>8G&BM3*&n#?ozn+(G_1lu>%aYi(!2E#12bH z@P{SdX?ePFDIgQW{3n9oLqhRcm;Jfak3J+4SpE0sVwoK< zm_7$4etXQx+@J5_)=hx%`A()3mIDaR&T}%?qksJbCVp$e$t*wzYuP>nuxwND(q|4# zygBYE8?kBhmd#I5NSwguGYs9RG@#8ab)gpbHNO2)Yk|74#|t=w|@H3R*WKAm|(e7~0OKRQxNQy#B;kAjn}in) zV7{$)ctFte0c?6+HZD}LQAY%la0Gx&!c7J+Qg>z`2?qh#BrGs4NP<*q&MA(Z?^o&# zisBz#00JI%0PziryclbF_dEEk34qEhn(Zoe7Ai1qZqEGu7FSKY6~Ik9nW?Zm1wwp# zfZqeWNSCJo9=pv|1)Ttu0Apae4TSi?0KWjZk1jU=e06)aC9>U*`?}wf>}N@{e@yy1 zm&8{1#5asb>9-ySsUM_W{*G4ZwCFcTWqEl>#eZGlnPppcH}ShO<#u_Jgq(F-A^gPh zZ%kI!7~~_FO#FaS-85qHLB$`QE;cHi%hzC$6}93_dfvovgwZdsbYUF=^pD7Bnz4D(jdW4_pkkQLn$TQ zne9FcRFGBxTR~nlfE8rj&jWShQ~;@!tkw@3fLbZJ_#lG5+vZ|oQ{*C_(_wzjob;A8 zNW3b^h@nN^(jWnv6kie~Xl;t^rag&nQ=7i_d4#}R{U}KAbM?G=TAMhPkNob6oWk$Oa`}z6uC*fILwd%iXnAf-iV#I?@9Xel52ojhthXn~bU(WPNqBqPJ zo;u^hgi9^sRZx6{;O9%*pnPd4(D^hPe74pd2HJ_)d^yd}moJ3pXUv!Rei9F2#MGC| zf&}KvAA$s(FAIHA6+JOu{^ApclR$mx3KIN$xqeW-+~?;@4LzCGXez*8ZN8-L802SM zTIZ$oJI2q(@Uz~VM#oYQ`+o8y+;vlb^8K(Qv+ zRux<~jjNSgHMMFgHD-AYq4$NKZ`|l6#qn;Cz~Xo%NVp+{cHJAkBe?NM?z1>jK>~}z z2@+1BCo4+^9^)?z?u?dZDsp9c3Be9UmM#655QU1r3Qrpb370^Y>LB5K%A!)w3@YXU zzsPc$lDkkg{n;XW(=W2U{x28VvFM@rOn{LhJ2yyRk)0YO=pwt-Cvhp8HORe|gkk7* zQCzW$0jdb3sASAgN4VT#GVxDjP%I`BzYv1)3qi;Kq96Y-dO|U|-5@kF4ir)Bet=m7 ze(}6KsCW)8M4sarP2Z*#4i71{>px5_OgI+_3tu??U#(F)_~U``l$8zK)F6S`!!OhD z5e~^7_jr(6m;o%BLjl?eSTxfC77=8NriXC3MPuUT+LRQHiCYN4xP_qOJ_9lIF-R6m z8-S_+V6mJBP)^_%%R7UL0g^91{SlX9^Xld|n{&6lJY3D45 z_Uv+KWuN5wrGgz~Xw%}E_eRFlv{8_uC#9zp>w%#I4Bx=SD+}UN_5}ftv>YP~(t4eM zFT6|p{h$%dK?ouz817G=0R|JyY(JPP(Bn23rsR%5F!v1(W(*j<4g~XrAB;4_Il=7m zX;zw|szK5)m`lN6q)F`u0-hfS^L`+hV+IHFXLwovvurSX`N13vdTydxz$HaHEiMza z2f^_IXtMfJo5|V#6R*vz_@<%%C7!f4Q4J=3?zd5UWo%{m!*XaJ45HERj$h>ZCGDo= z&=UW$d{Qclz;{fR=5b=l=Q^19-kJ1jnqAsXU1mee8(_!`vj*Gl*%ZnQvz`D=k<2ig z2v%W+sb7HfAXQHXQp+hNpKh4dm|E!fQ_4AIt4S&6lpQ9eoKtpXQ)=dvG7{qO z$;>Gel$XONGp7`S9?hzv*hoj=NQ;{Er7dfh)4pDYY|3;!Fv%p!tQZ)AT`{l(vtnQg zdc&BMX+46;88q$-f)p}V4P?%D0tjp?rHkX7&l1?paL#85**V`lBOO!CIiDpk)tvKL zf=M-^P(Q$&mrb>2CUvhfev@)C=A_&ZY|1Ucq}&n$DJLx_ul(3&#lH_^I0-rL{7BI6{Qft3QpE?f_-gol#>v0>k3J~E%itZ8 z*ha8Fe&$6=cgLR`hf$@|VO^VtKq7^Q!Fn}Jvdt;%PPzDiFYKo|g~u1W>SmbafK%99 z>Z*k>$)!%=@G@8J0h7GYDej--sq{6H8+?0xi6zK}CAq$YB(4Id&GjXgpsz2H%UBG} zT*hLsT*ji;tl978za3MLM(`%OLsHg9A#bjf-AoE|QIoQA*lo&c2z1I4#q$`jQX9Y| zZyAw@1#tRH&-?c^;wX_$!6d+`F!%_Oy>$4o0jl4WwI9`t!c=jyaj>UW0arW$q z<27Frf0?b^BJV1eHy&n1W^1?Fo9^$5lDruot4xgdg&|?X%Oj~bgAAWDApJ;kn-Nd) zwoxwiqm?N%1=&F$$(21IUF5sBRBPEA2!QuNCFK5Q00xS?pyVJp11Giz!7V`!g3EdJ zWem-~6Ka4FnUCV6M*!%|s3@?vz08QesGIBwQyrl@d}FfZ5Sh2fGeMcfxm|6aFJac!FYV z;K(HiP4ryn6w9@#M)qLhBrWDENQOb*4JDc0%mDmMZ-w1vdIv#vr)3xU{GFD|#Ltil zKxe=JJ#6b|0EM7VN(Qj-)1%;uD}F?t8Uk}M1?*OyCW5RIGz;I5WDq52BY!{%q+9U6 z7Db7q7YODPrz`#)TDt071p+?H1RnY%BK-}>SsRrn&O zQa<)&2sw3_9J=`8@^LZa=~Aas>TeyyPhREM-zEU$>QFY^#yB*XP0!ajqup(=K-)pk zj%|ay8L0~(Z+>L5`_?Q>W(mxNnf+ul7iLmq=`zgaA%^f1eTLkf>y1SS=JJp#09$Ca z1X5^nw?6}$&KS()A%?J!&uFUC&*W|TMxm=UvjRWv+_pgTCc2D(mK=yb5BrTFeITj@D`4><{cLT-&@S}L*QV+npMnfDk z=Rb=d-p7zccP~vZLn%bF>r{bwhvV+{9oh&g(n2R4+Zvz^prEP*)k4%{4*1_faQapu zGOkj?(8~}^!_d#D%ox@iZyE-d-vp`xWTW8z6QB+tr$OMtP)>tDLa@RL&TSCF^kZ%o zgk6yk^dmUiAT%*j^DUs+06|{v6tE3KI~`4fun5352t5R*LFm&iC5(Hh4T3ELUg{*5 zInnb9x5sLYK(?0y*le#MkoH)zy`GFF+h+p&?AhMJNKLkP0Q_XOchk{i`!WEV?E?fR z+tU-oWks@GDpD0Pnm3Y4wc$2`6HsmVx+U4;#1Gv?w}c0=H2#KrwkEg3hKGume95Uu znXbv#OckS-YRHo8#rEXFD~n94;1u@5ZW`{;dsm}oJi1n!C~y_Xp0$s9g~Y;9HVKZ9m69NPJ|3%MSu2cATdv)%XL4w|M}|dIdM3wIfIw@D1TitJg4BhbRLEu2(e9 z4iNn7RtrlqF|(i)q4TRSyCPTpl?kSH5mShj3Ay8jc0aX!Ody*%$;|3(Y7g^e-xy(W zWuh^FxiYbJI~?%PT~;P)+X*#6Rwk~zK0v_AgxrdQ7`QS~*^V!a(vFphqh@P9HXO1t zaigDT8Q5@T;t+q~frKHl2`OB}!<7jsT&B<@w}n6oH;?MlPCl$m zNEW`1kXw<3dPyyJnm@$#3EocA%`mY(!Ry7AF*;68c)i#Ffu4q4d@WLii%q~6ZGpW8 zc8sGECw>bV@UZNMFIdMOK9CX5DS1rBiiHOy# zg)BxIc0Ua{LV2p`f@v`2se|3h(@3D@;q5@Pgm0Kv6?Wh~FskGoik6_)LO8T)BmejQ zjPYx*c<&Bc*C2yk*8o6IF_d|cUg)4_EOf|iPihjDF9HX3spG+ex`G1-b&36hx-vs6 zhkv^+QUd@<A1@A&>59 zZ$sYBLALlS@JY6;o#ar`uy)hxH>}HGw=K;8f$m0hKnoC1x-Vu{=H)KJj`Su_q!o zD;(?+>*$j!986Lpf!{UGqTNqZ3+y&c?F4?;Xga=0NLH}pBWA~E_XNlcldB!3W0Mv; z*s%%0@7TQGeun_?u!T!ojwfzuIoTx|e0>pKY~ z>%BAlo^Vg*5Z5V=4-jO0d~`dU@NkqQ(~=qOgqpzdEBj@O^|ZwJVHV1?#P}g0=tr=g zme5Z(1e5VG`TGEZyewH662FOc3aMb|A`PHbG#0f_+yTXtF-RezlVT>l5r(dtjIK33ieFbjYqx=xOyidH#eH z(`r3MJuaP{qRLtYS^|8F%2DcZGz0#cg}YljvWb-vs}%Zh1prqm?5csJonKdvaW39S zUM@+{V>1Dk55!}u?-7v{?@<=Zt_R!+VAcbq5|07P1*pVku3U%FLe;tm3Ug(5eSlg3 z&Xw&rl`<3@S(2~>79I#A@K+9_&WE8Mi~cq+tX0zAW`s=;ymmTGy{)68(c4A< ztGBZVjNZ0rmw?{3gJSh|5rNTLoA+!sR&E+Cqk4pCv%3$#X17{DC%el5ZFbiJ{OsA? z$VfSjW;4+Y@RQlyMn{v~od7nwy9rEoFVil8>>dEcW_KEAo=tX-f+nanV7@}-@z>s@ zLY<3BJ;T2a5lh;k@I*XatqD?^G4*t(rsL|J4`9A zr?>rL!)3-05pK+N2o zX!mgmVdeL6#dzedg|T4coE;h!G8SwijIn&%={h$P(W!(kEAH}IO{x5GloV)@FOX+; zbsa&0xI>etaeC;=9hy9e(?_7wzcQzAB!%i9!4!5Og*^W9bDw$HiD~5aMRVq*)K9cM zXCed^zB%(E1bu+PoO!9FCvIOfXI_NB?ThBjix6_pyznB3oE`fjOYqE##1uU9@}Fec zaz})RM`9Y{nHMRDa#Ika>HT>W#G%*6)Fm+SYcfA~dF%}lq&$xFlT$+im2iI$YA7m| za94nO0$mQRJ~JClDTlLz1eU|eK|=P_L=(dZo|=&OSq3@rqYNbe=3xA-+4%1XhR(dd zF-YKfqpN}hIXNMD-@!0g%_Z;o`e*_2{S}?}|D(0Ni!oF2-|!{l^gvp@=Ys?){$oLc zuJs@IBn~Mh!+FCrA0aTqdBwCP$i7`kaBoh6ABD2@BeA3B{~XGefIK<7w09?gd5~e% z!(){#3PL|crLqkmvEEw%TG^)f%u*S7G-omhRdh$XW1|3S39?GoKp0dqiI+;26EBsF z@y;Z>iFY=Ej<+coFOTKy0YV$yc`RpJfKGy}a&;5hKIBd0HBYPk&(vs_2f&swLUx?y z@Ye+7DUYz%A*&dAR3DRkDWxbXjkkKMc z13~a4+J6#exhK(PG6ZuHZ8m}AtvxU=!k`#MvD@fwGn>n2!;#smsS3-~u#+(a4;dWp zXNJo|2HkXJJIO-^%Lu4K|DcTj1klxXWeyog>Z%xqP2I+rJ@I7S|BNdAsBCjHob}Zl zX&c8JV4``Xt(Gz}(L74mKp^!-j?v8|WL@Pky4eI&G9IIABgod(PQqYaHHB>B6g6U9 zWt`n)H*qc_&~ftk+yJ3DK9}aL6z2F`H9@wX))Cswy#T7ilR2wNb!={OmYkzL`xy1% zeGiS4fjPi zJ%m5BkHG&1=mU7!R=l!^;j2Soc)>^UH}Jxnw&D}8yE;?fkL}Db7@IgHe}Dy{@uLI0 zs|Y!l8T%#Hztjuy^=ique_N3jxOnpk(qUg)DP+=zSbhMh<{Lkh zk74mIPg)8ul%nNZd|ClUq&Vd}D}}y$T4f5qch#0K;vW0KN>Qn$P@&y0*_0_@s0p?) zC*cRO6yJO*wx#1O@uXTu-xz^`ygGBCesw%)j{U^RXk`AR-+GDluZ24vPOK-jtl>=v z;4vkRmlz%-EJ~#6d`xd+uA$DQ%-iVg7{>3Cx%k{F>eV+)v1q7>99k29QW94^E z^c`)lK(q4ijHyX)myPb%SKk!_QY9ySGO7-wBslj5i9t?^I-_<5Ee6`TpfT)8!<|uk z`Lso#eE>6QU0f-+%depHkgfG8NW%3|6mn8(1&+0oG*Mx1Z<$iy;a*Ce0{| z_~C625;-TGmY+V&)l$_!jY4O#^337SAMsN%;-jdlj+B!6{S{1D>4qOh)jd&(st}H1 zEgwtA@4z&6S)rpUKvyLL_^r}j*S^wvEq1L}u@;Y|qj;U2F<#&Q*v2{|>-EH}SFx6l zrK5O#*?PV8lc=iEu|7|JEwJ#XODV8etH#oCkk>nr=kR(kLKyXD3T&BF$+q8!M09)m zQgM6n`ayAz{SuTPkO!({lIt?p$bH-(Zj(P_`z-gT;6_G~d%+-XlO3A6l)iS%n&8W!^dLsk<(MMy|BX^(!KC)9R4< zNyxkn-e9b}%*`tzbL;Am`Bum~F}f-;cdUraU8^8-{`pg5s$g^Kgp)r5|6;$|$^Xr? zmBr;$6WT{Pna-_Zs(x#+JNYlcBH(T()D?yYwp^LlcZ#Vib_UBtd_Cr)rkJ|v zARk1Ii>XIo=z{UacVN0?7eB16cf}F}%+xw3|NcE=YSX=7hfwqJKW=Yf%1oaQL0}+= zlYdDg8s&Yohw~4HrTU6;mUB1N)jz{(I-3 zCpcHzw?g%hDsqvNAG$cEehmX2v@8x%6Ia&+)BTxNmV=fhiwy6pTnefck=sxA5#aPCp?84{y`67!2=c9 z!@-a_QrdvOlfII!ihnEzRf2uRraModOnmj(>`o~zQlz+ubw@TcBwZ7W_o{`qc=y)) zqzFH;6mQ9xFg7o1_52e`$q)Yk%}zuykVK-7#DMTU zn9TZ4X1Wu@djr@vas77ghG}4XGK|kOU^97UOV`PqRDfm*uk8u2Q|eSNrgIbdG&UJi zb72@%Iv;H#41>y?U5vNu*fAqnox|rH-8t5Ik z>N2uhOtrvddI5%^$vg)}TqYh6Q@6s1%lt#}kr%Xq;xhc`n7RgrF8Sx2geLoB0EB$! zY526+uVKFnfvtBsc6P#`6rIdlu8))JSYDT_!s*mC;yLs0qt3s%bfhy=Ug?aNAnzxf3bt-L)cG!Ui0j<)K#y- zFr4bY`gZW_j(w+Z!jN8CTDPSw%Yk7S1Vw<4JQA2C}+x555eT`?_>&4hZn)*mqTk8qcRr{2iV5R zKlNzXkAeLyCx1Nt&!nBVHH0otBhYL4b0dB-3-R*>O!^^Ig5z);q!T7R5m!APya5_< zm~?)g6XGF}%(_!t^(Pp-*LE^DjlkCHN_-~~KxL-mh{zQ%=><^jcVSrrl_b4;%n8kf zB_vhm7LvAvnU0&8-^9L`trPGLfYHE)C%WoHnDmwqT9_mSO}WF7NCgU>h+rrVfJkq@eS?Qj5y6*-~{}P5y1gJkxTKW#CC(?&kx+VDX z_`TwBr5l1O*74bJLLY-zvLTp8L`uJe-Cz5NfFgl;r3qtAmX^Uv5hCf*k%n4aS`F(V zjG`Q$n1H=lUzYxg7TGa_fs%)`+gbP{5t}>$5nc+a2WrF{OUDNQ@$rlwL@xR`HN@4! ztPii$`bdwZqxNx)LhtGg+u;UW>ZX@H@u63K1L-(Wu-t|Zy*7a5ER9qNooe(d=Ov)= z)2?*)Nl%guzDl+R4db58zgk{yPllu9t5;fUtZ`M+3VXFzIvsz0PBs~9vh+A(O_!bo ztG{=~hF@H2OS8Q6bi+HMbdIrBWiD(%UjwN&5TmzQ~zzeYK-wv=3zUS{s@VJwi zIL}r0z|@q(<=E@7Ry`l!2!KRKAb_U;YygvP3&x*ja~oGLoYrh@CnaN1Xf<1BZ_g77nZ+4ltK$`th6eEU@M{vcg>f9Se0o4Nx2q3KH7s_IG}bma;o z_I0^y8#UL3hpghA6dU|Q6T5pA#LoPH<;@e$#vtN7EVhn}cuO$+ka5fBA$P+LoYdiPA`&iks{xt>L?(IsuIi%C^aiY&aI`Yc zkEpF68jA)yY2(gFD}@LeF3@nEx7nsxcU>dB({vz?jarV;(RK z?FnAxaYlCULQEHwOjh)atipH0Bx?CHvWEuE$VOymWR=-)#{7;`AE%@ff0%O2#h)J> zS7~3oUM4By4n|}r;cRAjq#F&dF(Iu^0Ab90$EDY8u&P_FrJRbza12?-8~_p~mW5cq zRgO#pG9O^y$%boSW%5AJ$#k8MOgIXl7GvLutv;9+(mN?K$hgNI(2LOFwp8$gQ{l@z zed-U3Gb;3u&+}mRpgy)#tMDUEQjX!be*uvnc9JTSx=h~=68@{BZ>!!0ZQp*z|BR5` z3QgzDkFi@78pRvvg76+Z$s znU4@&Lh`)b{9x8bXbjgq8GaT)&N#z~wQ#N3nEUPEx>atpcEEj|D@dQnPe;KdX z!jn14#i0qHTOHUCAbb$sgEI#CB+sqTl*QH1SG;XrdJU;yhY9b3Hvr~vISHA4oVYz* z9tNQxc)FYfbGm#q>}r2VHSu9Aa?gpW@T5r2yf{1=?e!1`nN7?c@DHsAZU*N-%d1uj_vSiw95sxHzVk!i1|5Uf&`Xh*re#=tQOc zBnUM#yk1_hEml!g-brLWX-tAC*3583!nLCCOe|^ck9C3TV8WNCoX`tc6Ue-TAFe2b zU(d&iLiJo6F*+9LNVJ3V4R{>j(i^Z<4<=j_*A3R`P@ZLwm7#=R%Xeqoi`%^LjsgLB z-V}6Me54*~Oq_s`M?EzSSO3LMcwhwj=Q@ox1E{Y9g!LxZKR?mg-kG$;V z7$lf-Po0Fo`7pEA-(-Z?@#CHfK^2x~!`DF@&W1LW1JulfHXI9=8iHpt?s-T-J?)jy zhBE+~=w%5yy}eN8%>+jQ@K|6gK}D#@TL>3EQvY_sHDyL0g>Z5bO}S^z5pvKL9)n(R z2%d5?e@rMDKR6Imcw8u!8|-*=jVm1Nc(fNe!A=MzY_P*AZ8f^b6$v(9dn&d)u2kHK zp+ZX#j>(~XOW?pNymkmh7T+(ai;rCr^IdCL2aBZ2*RXB^qhWn41*2gehJseZssOBp z)dCm|Yk+-qYgqg&Ut3w`H6w6S5LB)W`ZE)eg>OhD-A&)ctb<_PxMx+F+~F_W<$h!q zo%Ws!T-6Q}UV>)&Ay_g`;zye4P|Ckh?P=s!_Z{1SToql5LSOP zC^a!S^jqO(u!Dm6&EU1nXkcju%TNTp1V%~w$r(yblxEQTHmIZkStSLqN(%exR#K~z z2s`|&(Mf_8(8^H*kZb;6DwD3R*!)x@%`ew}QprUWXgm+C@+Q-1_JqlWLs)&4Bz)S_^w`9W) z7kGd2+xg8w4=*n8TwX=fz{J#IC|-sAD12;N^5eUuyt-Y4MUBB2 zbUMDX?^*!YxR(|gRqLa{DzYN*v9LBP;nX^cqhtuVD z3@?P>7+x|eIAWh@gf^{{)g~D%)ucyRZ4yFIn@Gr+5t3kL1`_rJ5RO3DebC|XUW3Bk zd!@sc=A#&4--fVDA4l_XQd($n&_)6a?KDkeRr(`nd@B=<7G^%fOYn8@?mK)wHtF=d z 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Û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Ⓢf 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 diff --git a/pkg/execution/testdata/simple_pipeline.json b/pkg/execution/testdata/simple_pipeline.json deleted file mode 100644 index 3dccd39a2..000000000 --- a/pkg/execution/testdata/simple_pipeline.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "steps": [ - { - "kind": "NOOP" - } - ] -} \ No newline at end of file diff --git a/pkg/execution/transformation.go b/pkg/execution/transformation.go deleted file mode 100644 index d90cf7316..000000000 --- a/pkg/execution/transformation.go +++ /dev/null @@ -1,22 +0,0 @@ -package execution - -import ( - "bytes" - - "github.com/jensneuse/pipeline/pkg/pipe" -) - -type Transformation interface { - Transform(input []byte) ([]byte, error) -} - -type PipelineTransformation struct { - pipeline pipe.Pipeline - buf bytes.Buffer -} - -func (p *PipelineTransformation) Transform(input []byte) ([]byte, error) { - p.buf.Reset() - err := p.pipeline.Run(bytes.NewReader(input), &p.buf) - return p.buf.Bytes(), err -} diff --git a/pkg/execution/transformation_test.go b/pkg/execution/transformation_test.go deleted file mode 100644 index ee3e9f3d8..000000000 --- a/pkg/execution/transformation_test.go +++ /dev/null @@ -1,256 +0,0 @@ -package execution - -import ( - "bytes" - "context" - "encoding/json" - "testing" - - "github.com/jensneuse/pipeline/pkg/pipe" - "github.com/jensneuse/pipeline/pkg/step" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" -) - -func TestExecution_With_Transformation(t *testing.T) { - - plan := &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - BufferName: "foo", - Source: &DataSourceInvocation{ - DataSource: &FakeDataSource{ - data: []byte(`{"foo":"bar"}`), - }, - }, - }, - Fields: []Field{ - { - Name: []byte("foo"), - HasResolvedData: true, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - PathSelector: datasource.PathSelector{ - Path: "foo", - }, - Transformation: &PipelineTransformation{ - pipeline: pipe.Pipeline{ - Steps: []pipe.Step{ - func() pipe.Step { - s, _ := step.NewJSON("{{ upper . }}") // simple example using the sprig function upper - return s - }(), - }, - }, - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - } - - out := &bytes.Buffer{} - ex := NewExecutor(nil) - ctx := Context{ - Context: context.Background(), - } - - err := ex.Execute(ctx, plan, out) - if err != nil { - t.Fatal(err) - } - - expected := map[string]interface{}{ - "data": map[string]interface{}{ - "foo": "BAR", - }, - } - - wantResult, err := json.MarshalIndent(expected, "", " ") - if err != nil { - t.Fatal(err) - } - - want := string(wantResult) - got := prettyJSON(out) - - if want != got { - t.Fatalf("want: %s\ngot: %s\n", want, got) - return - } -} - -func TestPlanner_WithTransformation(t *testing.T) { - t.Run("pipeline transformation string dataSourceConfig", run(transformationSchema, ` - query TransformationQuery { - foo - } - `, func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "foo", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "StaticDataSource", - Config: toJSON(datasource.StaticDataSourceConfig{ - Data: "{\"bar\":\"baz\"}", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("StaticDataSource", datasource.StaticDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("{\"bar\":\"baz\"}"), - }, - }, - BufferName: "foo", - }, - Fields: []Field{ - { - Name: []byte("foo"), - HasResolvedData: true, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - Transformation: &PipelineTransformation{ - pipeline: pipe.Pipeline{ - Steps: []pipe.Step{ - step.NoOpStep{}, - }, - }, - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - })) - t.Run("pipeline transformation file dataSourceConfig", run(transformationSchema, ` - query TransformationQuery { - bar - } - `, - func(base *datasource.BasePlanner) { - base.Config = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "bar", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "StaticDataSource", - Config: toJSON(datasource.StaticDataSourceConfig{ - Data: "{\"bar\":\"baz\"}", - }), - }, - }, - }, - } - panicOnErr(base.RegisterDataSourcePlannerFactory("StaticDataSource", datasource.StaticDataSourcePlannerFactoryFactory{})) - }, - &Object{ - operationType: ast.OperationTypeQuery, - Fields: []Field{ - { - Name: []byte("data"), - Value: &Object{ - Fetch: &SingleFetch{ - Source: &DataSourceInvocation{ - DataSource: &datasource.StaticDataSource{ - Data: []byte("{\"bar\":\"baz\"}"), - }, - }, - BufferName: "bar", - }, - Fields: []Field{ - { - Name: []byte("bar"), - HasResolvedData: true, - Value: &Value{ - DataResolvingConfig: DataResolvingConfig{ - Transformation: &PipelineTransformation{ - pipeline: pipe.Pipeline{ - Steps: []pipe.Step{ - step.NoOpStep{}, - }, - }, - }, - }, - ValueType: StringValueType, - }, - }, - }, - }, - }, - }, - })) -} - -const transformationSchema = ` -schema { - query: Query -} - -directive @transformation( - mode: TRANSFORMATION_MODE = PIPELINE - pipelineConfigFile: String - pipelineConfigString: String -) on FIELD_DEFINITION - -enum TRANSFORMATION_MODE { - PIPELINE -} - -type Query { - foo: String! - @StaticDataSource( - data: "{\"bar\":\"baz\"}" - ) - @transformation( - mode: PIPELINE - pipelineConfigString: """ - { - "steps": [ - { - "kind": "NOOP" - } - ] - } - """ - ) - bar: String! - @StaticDataSource( - data: "{\"bar\":\"baz\"}" - ) - @transformation( - mode: PIPELINE - pipelineConfigFile: "./testdata/simple_pipeline.json" - ) -}` diff --git a/pkg/fastbuffer/fastbuffer.go b/pkg/fastbuffer/fastbuffer.go deleted file mode 100644 index 13675d9c4..000000000 --- a/pkg/fastbuffer/fastbuffer.go +++ /dev/null @@ -1,61 +0,0 @@ -package fastbuffer - -import ( - "reflect" - "unsafe" -) - -func New() *FastBuffer { - return &FastBuffer{ - b: make([]byte, 0, 1024), - } -} - -type FastBuffer struct { - b []byte -} - -func (f *FastBuffer) Write(p []byte) (n int, err error) { - f.b = append(f.b, p...) - return len(p), nil -} - -func (f *FastBuffer) Reset() { - f.b = f.b[:0] -} - -func (f *FastBuffer) WriteBytes(b []byte) { - f.b = append(f.b, b...) -} - -func (f *FastBuffer) WriteString(s string) { - f.b = append(f.b, s...) -} - -func (f *FastBuffer) Bytes() []byte { - return f.b -} - -func (f *FastBuffer) Len() int { - return len(f.b) -} - -// Grow increases the buffer capacity to be able to hold at least n more bytes -func (f *FastBuffer) Grow(n int) { - required := cap(f.b) - len(f.b) + n - if required > 0 { - b := make([]byte, len(f.b), len(f.b)+n) - copy(b, f.b) - f.b = b - } -} - -func (f *FastBuffer) UnsafeString() string { - sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&f.b)) - stringHeader := reflect.StringHeader{Data: sliceHeader.Data, Len: sliceHeader.Len} - return *(*string)(unsafe.Pointer(&stringHeader)) // nolint: govet -} - -func (f *FastBuffer) String() string { - return string(f.b) -} diff --git a/pkg/fastbuffer/fastbuffer_test.go b/pkg/fastbuffer/fastbuffer_test.go deleted file mode 100644 index 8f1411e79..000000000 --- a/pkg/fastbuffer/fastbuffer_test.go +++ /dev/null @@ -1,65 +0,0 @@ -package fastbuffer - -import ( - "bytes" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFastBuffer(t *testing.T) { - buf := New() - buf.WriteBytes([]byte("Hello")) - assert.Equal(t, "Hello", string(buf.Bytes())) - buf.WriteBytes([]byte(", World!")) - assert.Equal(t, "Hello, World!", string(buf.Bytes())) - buf.Reset() - assert.Equal(t, "", string(buf.Bytes())) - buf.WriteBytes([]byte("Hello, World!")) - assert.Equal(t, "Hello, World!", string(buf.Bytes())) - buf.Reset() - buf.WriteBytes([]byte("Goodbye!")) - assert.Equal(t, "Goodbye!", string(buf.Bytes())) - - buf.b = make([]byte, 0) - foobar := []byte("FooBar") - buf.WriteBytes(foobar) - foobar[0] = 'B' - assert.Equal(t, "FooBar", string(buf.Bytes())) -} - -func BenchmarkFastBuffer(b *testing.B) { - data := []byte("Hello, World!") - b.Run("bytes.Buffer", func(b *testing.B) { - - buf := bytes.NewBuffer(make([]byte, 0, 1024)) - - b.ResetTimer() - b.ReportAllocs() - b.SetBytes(int64(len(data))) - - for i := 0; i < b.N; i++ { - buf.Reset() - buf.Write(data) - if !bytes.Equal(data, buf.Bytes()) { - b.Error("!=") - } - } - }) - b.Run("fastBuffer", func(b *testing.B) { - - buf := New() - - b.ResetTimer() - b.ReportAllocs() - b.SetBytes(int64(len(data))) - - for i := 0; i < b.N; i++ { - buf.Reset() - buf.WriteBytes(data) - if !bytes.Equal(data, buf.Bytes()) { - b.Error("!=") - } - } - }) -} diff --git a/pkg/federation/fixtures/federated_schema.golden b/pkg/federation/fixtures/federated_schema.golden deleted file mode 100644 index 8ff95d237..000000000 --- a/pkg/federation/fixtures/federated_schema.golden +++ /dev/null @@ -1,255 +0,0 @@ -scalar String - -scalar Int - -scalar ID - -schema { - query: Query -} - -type Query { - me: User - topProducts(first: Int = 5): [Product] - __schema: __Schema! - __type(name: String!): __Type - __typename: String! - _service: _Service! - _entities(representations: [_Any!]!): [_Entity]! -} - -type Product { - upc: String! - name: String! - price: Int! - reviews: [Review] - __typename: String! -} - -type Review { - body: String! - author: User! - product: Product! - __typename: String! -} - -type User { - id: ID! - username: String! - reviews: [Review] - __typename: String! -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean - -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! - __typename: String! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} - -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String - __typename: String! -} - -""" -Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String - __typename: String! -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! - __typename: String! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type - __typename: String! -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -} - -scalar _Any -scalar _FieldSet - -union _Entity = Product | User - -type _Service { - sdl: String -} - -directive @external on FIELD_DEFINITION -directive @requires(fields: _FieldSet!) on FIELD_DEFINITION -directive @provides(fields: _FieldSet!) on FIELD_DEFINITION -directive @key(fields: _FieldSet!) on OBJECT | INTERFACE -directive @extends on OBJECT | INTERFACE diff --git a/pkg/federation/schema.go b/pkg/federation/schema.go deleted file mode 100644 index 874ac58c2..000000000 --- a/pkg/federation/schema.go +++ /dev/null @@ -1,188 +0,0 @@ -package federation - -import ( - "fmt" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/federation/sdlmerge" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func BuildBaseSchemaDocument(serviceSDLs ...string) (string, error) { - return sdlmerge.MergeSDLs(serviceSDLs...) -} - -func BuildFederationSchema(baseSchema, serviceSDL string) (string, error) { - builder := schemaBuilder{} - return builder.buildFederationSchema(baseSchema, serviceSDL) -} - -// schemaBuilder makes GraphQL schemas compliant with the Apollo Federation Specification -type schemaBuilder struct { -} - -// BuildFederationSchema takes a baseSchema plus the service sdl and turns it into a fully compliant federation schema -func (s *schemaBuilder) buildFederationSchema(baseSchema, serviceSDL string) (string, error) { - unionTypes := s.entityUnionTypes(serviceSDL) - if len(unionTypes) == 0 { - return baseSchema, nil - } - allUnionTypes := strings.Join(unionTypes, " | ") - federationExtension := fmt.Sprintf(federationTemplate, allUnionTypes) - - baseSchema = s.extendQueryTypeWithFederationFields(baseSchema) - - federatedSchema := baseSchema + federationExtension - return federatedSchema, nil -} - -func (s *schemaBuilder) extendQueryTypeWithFederationFields(schema string) string { - doc := ast.NewDocument() - doc.Input.ResetInputString(schema) - parser := astparser.NewParser() - report := &operationreport.Report{} - parser.Parse(doc, report) - if report.HasErrors() { - return schema - } - - if err := asttransform.MergeDefinitionWithBaseSchema(doc); err != nil { - return schema - } - - queryTypeName := doc.Index.QueryTypeName.String() - if queryTypeName == "" { - queryTypeName = "Query" - } - for i := range doc.ObjectTypeDefinitions { - name := doc.ObjectTypeDefinitionNameString(i) - if name == queryTypeName { - s.extendQueryType(doc, i) - out, err := astprinter.PrintStringIndent(doc, nil, " ") - if err != nil { - return schema - } - return out - } - } - return schema -} - -func (s *schemaBuilder) extendQueryType(doc *ast.Document, ref int) { - serviceType := doc.AddNonNullNamedType([]byte("_Service")) - - serviceFieldDefRef := doc.ImportFieldDefinition( - "_service", - "", - serviceType, - nil, - nil, - ) - - doc.ObjectTypeDefinitions[ref].HasFieldDefinitions = true - doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs = append(doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs, serviceFieldDefRef) - - anyType := doc.AddNonNullNamedType([]byte("_Any")) - entityType := doc.AddNamedType([]byte("_Entity")) - listOfAnyType := doc.AddListType(anyType) - nonNullListOfAnyType := doc.AddNonNullType(listOfAnyType) - listOfEntityType := doc.AddListType(entityType) - nonNullListOfEntityType := doc.AddNonNullType(listOfEntityType) - - representationsArg := doc.ImportInputValueDefinition( - "representations", - "", - nonNullListOfAnyType, - ast.DefaultValue{}) - - entitiesFDRef := doc.ImportFieldDefinition( - "_entities", - "", - nonNullListOfEntityType, - []int{representationsArg}, - nil) - - doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs = append(doc.ObjectTypeDefinitions[ref].FieldsDefinition.Refs, entitiesFDRef) -} - -// _entities(representations: [_Any!]!): [_Entity]! -// _service: _Service! - -func (s *schemaBuilder) entityUnionTypes(serviceSDL string) []string { - doc := ast.NewDocument() - doc.Input.ResetInputString(serviceSDL) - parser := astparser.NewParser() - report := &operationreport.Report{} - parser.Parse(doc, report) - if report.HasErrors() { - return nil - } - - walker := astvisitor.NewWalker(4) - visitor := &schemaBuilderVisitor{} - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterObjectTypeExtensionVisitor(visitor) - walker.Walk(doc, nil, report) - if report.HasErrors() { - return nil - } - return visitor.entityUnionTypes -} - -type schemaBuilderVisitor struct { - definition *ast.Document - entityUnionTypes []string -} - -func (s *schemaBuilderVisitor) addEntity(entity string) { - for i := range s.entityUnionTypes { - if s.entityUnionTypes[i] == entity { - return - } - } - s.entityUnionTypes = append(s.entityUnionTypes, entity) -} - -func (s *schemaBuilderVisitor) EnterDocument(operation, _ *ast.Document) { - s.definition = operation -} - -func (s *schemaBuilderVisitor) EnterObjectTypeExtension(ref int) { - for _, i := range s.definition.ObjectTypeExtensions[ref].Directives.Refs { - if s.definition.DirectiveNameString(i) == "key" { - s.addEntity(s.definition.ObjectTypeExtensionNameString(ref)) - } - } -} - -func (s *schemaBuilderVisitor) EnterObjectTypeDefinition(ref int) { - for _, i := range s.definition.ObjectTypeDefinitions[ref].Directives.Refs { - if s.definition.DirectiveNameString(i) == "key" { - s.addEntity(s.definition.ObjectTypeDefinitionNameString(ref)) - } - } -} - -const federationTemplate = ` - -scalar _Any -scalar _FieldSet - -union _Entity = %s - -type _Service { - sdl: String -} - -directive @external on FIELD_DEFINITION -directive @requires(fields: _FieldSet!) on FIELD_DEFINITION -directive @provides(fields: _FieldSet!) on FIELD_DEFINITION -directive @key(fields: _FieldSet!) on OBJECT | INTERFACE -directive @extends on OBJECT | INTERFACE -` diff --git a/pkg/federation/schema_test.go b/pkg/federation/schema_test.go deleted file mode 100644 index ac51e1bbe..000000000 --- a/pkg/federation/schema_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package federation - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestSchemaBuilder_BuildFederationSchema(t *testing.T) { - actual, err := BuildFederationSchema(baseSchema, serviceSDL) - assert.NoError(t, err) - goldie.Assert(t, "federated_schema", []byte(actual)) -} - -const serviceSDL = `extend type Query {topProducts(first: Int = 5): [Product]}type Product @key(fields: "upc") {upc: String!name: String! price: Int!} extend type Query {me: User} type User @key(fields: "id"){ id: ID! username: String!} type Review { body: String! author: User! @provides(fields: "username") product: Product! } extend type User @key(fields: "id") { id: ID! @external reviews: [Review] } extend type Product @key(fields: "upc") { upc: String! @external reviews: [Review] }` - -const baseSchema = ` -scalar String -scalar Int -scalar ID - -schema { - query: Query -} - -type Query { - me: User - topProducts(first: Int = 5): [Product] -} - -type Product { - upc: String! - name: String! - price: Int! - reviews: [Review] -} - -type Review { - body: String! - author: User! - product: Product! -} - -type User { - id: ID! - username: String! - reviews: [Review] -} -` diff --git a/pkg/federation/sdlmerge/collect_entities.go b/pkg/federation/sdlmerge/collect_entities.go deleted file mode 100644 index 2b07f8434..000000000 --- a/pkg/federation/sdlmerge/collect_entities.go +++ /dev/null @@ -1,62 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type collectEntitiesVisitor struct { - *astvisitor.Walker - document *ast.Document - collectedEntities entitySet -} - -func newCollectEntitiesVisitor(collectedEntities entitySet) *collectEntitiesVisitor { - return &collectEntitiesVisitor{ - collectedEntities: collectedEntities, - } -} - -func (c *collectEntitiesVisitor) Register(walker *astvisitor.Walker) { - c.Walker = walker - walker.RegisterEnterDocumentVisitor(c) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(c) - walker.RegisterEnterObjectTypeDefinitionVisitor(c) -} - -func (c *collectEntitiesVisitor) EnterDocument(operation, _ *ast.Document) { - c.document = operation -} - -func (c *collectEntitiesVisitor) EnterInterfaceTypeDefinition(ref int) { - interfaceType := c.document.InterfaceTypeDefinitions[ref] - name := c.document.InterfaceTypeDefinitionNameString(ref) - if err := c.resolvePotentialEntity(name, interfaceType.Directives.Refs); err != nil { - c.StopWithExternalErr(*err) - } -} - -func (c *collectEntitiesVisitor) EnterObjectTypeDefinition(ref int) { - objectType := c.document.ObjectTypeDefinitions[ref] - name := c.document.ObjectTypeDefinitionNameString(ref) - if err := c.resolvePotentialEntity(name, objectType.Directives.Refs); err != nil { - c.StopWithExternalErr(*err) - } -} - -func (c *collectEntitiesVisitor) resolvePotentialEntity(name string, directiveRefs []int) *operationreport.ExternalError { - if _, exists := c.collectedEntities[name]; exists { - err := operationreport.ErrEntitiesMustNotBeDuplicated(name) - return &err - } - for _, directiveRef := range directiveRefs { - if c.document.DirectiveNameString(directiveRef) != plan.FederationKeyDirectiveName { - continue - } - c.collectedEntities[name] = struct{}{} - return nil - } - return nil -} diff --git a/pkg/federation/sdlmerge/collect_entities_test.go b/pkg/federation/sdlmerge/collect_entities_test.go deleted file mode 100644 index 8c3d59ece..000000000 --- a/pkg/federation/sdlmerge/collect_entities_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package sdlmerge - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestCollectEntities(t *testing.T) { - t.Run("Valid entities are collected", func(t *testing.T) { - collectEntities(t, newCollectEntitiesVisitor(newTestNormalizer(false)), ` - type Dog @key(fields: "name") @key(fields: "id") { - id: ID! - name: String! - } - - type Cat @key(fields: "species") { - id: ID! - species: String! - } - `, entitySet{ - "Dog": {}, - "Cat": {}, - }) - }) - - t.Run("Valid entities are collected", func(t *testing.T) { - collectEntitiesAndExpectError(t, newCollectEntitiesVisitor(newTestNormalizer(false)), ` - type Dog @key(fields: "name") @key(fields: "id") { - id: ID! - name: String! - } - - type Dog @key(fields: "name") @key(fields: "id") { - id: ID! - name: String! - } - - type Cat @key(fields: "species") { - id: ID! - species: String! - } - `, duplicateEntityErrorMessage("Dog")) - }) -} - -var collectEntities = func(t *testing.T, visitor *collectEntitiesVisitor, operation string, expectedEntities entitySet) { - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - visitor.Register(&walker) - - walker.Walk(&operationDocument, nil, &report) - - if report.HasErrors() { - t.Fatal(report.Error()) - } - - got := visitor.collectedEntities - - assert.Equal(t, expectedEntities, got) -} - -var collectEntitiesAndExpectError = func(t *testing.T, visitor *collectEntitiesVisitor, operation string, expectedError string) { - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - visitor.Register(&walker) - - walker.Walk(&operationDocument, nil, &report) - - var got string - if report.HasErrors() { - if report.InternalErrors == nil { - got = report.ExternalErrors[0].Message - } else { - got = report.InternalErrors[0].Error() - } - } - - assert.Equal(t, expectedError, got) -} diff --git a/pkg/federation/sdlmerge/enum_type_extending.go b/pkg/federation/sdlmerge/enum_type_extending.go deleted file mode 100644 index 57a586c79..000000000 --- a/pkg/federation/sdlmerge/enum_type_extending.go +++ /dev/null @@ -1,50 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type extendEnumTypeDefinitionVisitor struct { - *astvisitor.Walker - document *ast.Document -} - -func newExtendEnumTypeDefinition() *extendEnumTypeDefinitionVisitor { - return &extendEnumTypeDefinitionVisitor{} -} - -func (e *extendEnumTypeDefinitionVisitor) Register(walker *astvisitor.Walker) { - e.Walker = walker - walker.RegisterEnterDocumentVisitor(e) - walker.RegisterEnterEnumTypeExtensionVisitor(e) -} - -func (e *extendEnumTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.document = operation -} - -func (e *extendEnumTypeDefinitionVisitor) EnterEnumTypeExtension(ref int) { - nodes, exists := e.document.Index.NodesByNameBytes(e.document.EnumTypeExtensionNameBytes(ref)) - if !exists { - return - } - - hasExtended := false - for i := range nodes { - if nodes[i].Kind != ast.NodeKindEnumTypeDefinition { - continue - } - if hasExtended { - e.StopWithExternalErr(operationreport.ErrSharedTypesMustNotBeExtended(e.document.EnumTypeExtensionNameString(ref))) - return - } - e.document.ExtendEnumTypeDefinitionByEnumTypeExtension(nodes[i].Ref, ref) - hasExtended = true - } - - if !hasExtended { - e.StopWithExternalErr(operationreport.ErrExtensionOrphansMustResolveInSupergraph(e.document.EnumTypeExtensionNameBytes(ref))) - } -} diff --git a/pkg/federation/sdlmerge/enum_type_extending_test.go b/pkg/federation/sdlmerge/enum_type_extending_test.go deleted file mode 100644 index 01e290153..000000000 --- a/pkg/federation/sdlmerge/enum_type_extending_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package sdlmerge - -import "testing" - -func TestExtendEnumObjectType(t *testing.T) { - t.Run("extend simple enum type by field", func(t *testing.T) { - run(t, newExtendEnumTypeDefinition(), ` - enum Starters { - BULBASAUR - CHARMANDER - SQUIRTLE - } - - extend enum Starters { - CHIKORITA - } - `, ` - enum Starters { - BULBASAUR - CHARMANDER - SQUIRTLE - CHIKORITA - } - - extend enum Starters { - CHIKORITA - } - `) - }) - - t.Run("extend simple enum type by directive", func(t *testing.T) { - run(t, newExtendEnumTypeDefinition(), ` - enum Starters { - BULBASAUR - CHARMANDER - SQUIRTLE - } - - extend enum Starters @deprecated(reason: "some reason") - `, ` - enum Starters @deprecated(reason: "some reason") { - BULBASAUR - CHARMANDER - SQUIRTLE - } - - extend enum Starters @deprecated(reason: "some reason") - `) - }) - - t.Run("extend enum type by complex extends", func(t *testing.T) { - run(t, newExtendEnumTypeDefinition(), ` - enum Starters { - BULBASAUR - CHARMANDER - SQUIRTLE - } - - extend enum Starters @deprecated(reason: "some reason") @skip(if: false) { - CHIKORITA - CYNDAQUIL - } - `, ` - enum Starters @deprecated(reason: "some reason") @skip(if: false) { - BULBASAUR - CHARMANDER - SQUIRTLE - CHIKORITA - CYNDAQUIL - } - - extend enum Starters @deprecated(reason: "some reason") @skip(if: false) { - CHIKORITA - CYNDAQUIL - } - `) - }) - - t.Run("Extending an enum that is a shared type returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendEnumTypeDefinition(), ` - enum Starters { - BULBASAUR - CHARMANDER - SQUIRTLE - } - - enum Starters { - BULBASAUR - CHARMANDER - SQUIRTLE - } - - extend enum Starters @deprecated(reason: "some reason") @skip(if: false) { - CHIKORITA - CYNDAQUIL - } - `, sharedTypeExtensionErrorMessage("Starters")) - }) - - t.Run("Unresolved enum extension orphan returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendEnumTypeDefinition(), ` - extend enum Badges { - BOULDER - } - `, unresolvedExtensionOrphansErrorMessage("Badges")) - }) -} diff --git a/pkg/federation/sdlmerge/input_type_extending.go b/pkg/federation/sdlmerge/input_type_extending.go deleted file mode 100644 index 2292cad80..000000000 --- a/pkg/federation/sdlmerge/input_type_extending.go +++ /dev/null @@ -1,50 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func newExtendInputObjectTypeDefinition() *extendInputObjectTypeDefinitionVisitor { - return &extendInputObjectTypeDefinitionVisitor{} -} - -type extendInputObjectTypeDefinitionVisitor struct { - *astvisitor.Walker - document *ast.Document -} - -func (e *extendInputObjectTypeDefinitionVisitor) Register(walker *astvisitor.Walker) { - e.Walker = walker - walker.RegisterEnterDocumentVisitor(e) - walker.RegisterEnterInputObjectTypeExtensionVisitor(e) -} - -func (e *extendInputObjectTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.document = operation -} - -func (e *extendInputObjectTypeDefinitionVisitor) EnterInputObjectTypeExtension(ref int) { - nodes, exists := e.document.Index.NodesByNameBytes(e.document.InputObjectTypeExtensionNameBytes(ref)) - if !exists { - return - } - - hasExtended := false - for i := range nodes { - if nodes[i].Kind != ast.NodeKindInputObjectTypeDefinition { - continue - } - if hasExtended { - e.StopWithExternalErr(operationreport.ErrSharedTypesMustNotBeExtended(e.document.InputObjectTypeExtensionNameString(ref))) - return - } - e.document.ExtendInputObjectTypeDefinitionByInputObjectTypeExtension(nodes[i].Ref, ref) - hasExtended = true - } - - if !hasExtended { - e.StopWithExternalErr(operationreport.ErrExtensionOrphansMustResolveInSupergraph(e.document.InputObjectTypeExtensionNameBytes(ref))) - } -} diff --git a/pkg/federation/sdlmerge/input_type_extending_test.go b/pkg/federation/sdlmerge/input_type_extending_test.go deleted file mode 100644 index 4cfe91628..000000000 --- a/pkg/federation/sdlmerge/input_type_extending_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package sdlmerge - -import "testing" - -func TestExtendInputObjectType(t *testing.T) { - t.Run("extend simple input type by field", func(t *testing.T) { - run(t, newExtendInputObjectTypeDefinition(), ` - input Mammal { - name: String - } - extend input Mammal { - furType: String - } - `, ` - input Mammal { - name: String - furType: String - } - extend input Mammal { - furType: String - } - `) - }) - - t.Run("extend simple input type by directive", func(t *testing.T) { - run(t, newExtendInputObjectTypeDefinition(), ` - input Mammal { - name: String - } - extend input Mammal @deprecated(reason: "some reason") - `, ` - input Mammal @deprecated(reason: "some reason") { - name: String - } - extend input Mammal @deprecated(reason: "some reason") - `) - }) - - t.Run("extend input type by complex extends", func(t *testing.T) { - run(t, newExtendInputObjectTypeDefinition(), ` - input Mammal { - name: String - } - extend input Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, ` - input Mammal @deprecated(reason: "some reason") @skip(if: false) { - name: String - furType: String - age: Int - } - extend input Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `) - }) - - t.Run("Extending an input that is a shared type returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInputObjectTypeDefinition(), ` - input Mammal { - name: String - } - input Mammal { - name: String - } - extend input Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, sharedTypeExtensionErrorMessage("Mammal")) - }) - - t.Run("Unresolved input extension orphan returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInputObjectTypeDefinition(), ` - extend input Badges { - name: String! - } - `, unresolvedExtensionOrphansErrorMessage("Badges")) - }) -} diff --git a/pkg/federation/sdlmerge/interface_type_extending.go b/pkg/federation/sdlmerge/interface_type_extending.go deleted file mode 100644 index 0379d2ce9..000000000 --- a/pkg/federation/sdlmerge/interface_type_extending.go +++ /dev/null @@ -1,63 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func newExtendInterfaceTypeDefinition(collectedEntities entitySet) *extendInterfaceTypeDefinitionVisitor { - return &extendInterfaceTypeDefinitionVisitor{ - collectedEntities: collectedEntities, - } -} - -type extendInterfaceTypeDefinitionVisitor struct { - *astvisitor.Walker - document *ast.Document - collectedEntities entitySet -} - -func (e *extendInterfaceTypeDefinitionVisitor) Register(walker *astvisitor.Walker) { - e.Walker = walker - walker.RegisterEnterDocumentVisitor(e) - walker.RegisterEnterInterfaceTypeExtensionVisitor(e) -} - -func (e *extendInterfaceTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.document = operation -} - -func (e *extendInterfaceTypeDefinitionVisitor) EnterInterfaceTypeExtension(ref int) { - nameBytes := e.document.InterfaceTypeExtensionNameBytes(ref) - nodes, exists := e.document.Index.NodesByNameBytes(nameBytes) - if !exists { - return - } - - var nodeToExtend *ast.Node - isEntity := false - for i := range nodes { - if nodes[i].Kind != ast.NodeKindInterfaceTypeDefinition { - continue - } - if nodeToExtend != nil { - e.StopWithExternalErr(*multipleExtensionError(isEntity, nameBytes)) - return - } - var err *operationreport.ExternalError - extension := e.document.InterfaceTypeExtensions[ref] - if isEntity, err = e.collectedEntities.isExtensionForEntity(nameBytes, extension.Directives.Refs, e.document); err != nil { - e.StopWithExternalErr(*err) - return - } - nodeToExtend = &nodes[i] - } - - if nodeToExtend == nil { - e.StopWithExternalErr(operationreport.ErrExtensionOrphansMustResolveInSupergraph(e.document.InterfaceTypeExtensionNameBytes(ref))) - return - } - - e.document.ExtendInterfaceTypeDefinitionByInterfaceTypeExtension(nodeToExtend.Ref, ref) -} diff --git a/pkg/federation/sdlmerge/interface_type_extending_test.go b/pkg/federation/sdlmerge/interface_type_extending_test.go deleted file mode 100644 index 70080267a..000000000 --- a/pkg/federation/sdlmerge/interface_type_extending_test.go +++ /dev/null @@ -1,172 +0,0 @@ -package sdlmerge - -import "testing" - -func TestExtendInterfaceType(t *testing.T) { - t.Run("extend simple interface type by field", func(t *testing.T) { - run(t, newExtendInterfaceTypeDefinition(newTestNormalizer(false)), ` - interface Mammal { - name: String - } - - extend interface Mammal { - furType: String - } - `, ` - interface Mammal { - name: String - furType: String - } - - extend interface Mammal { - furType: String - } - `) - }) - - t.Run("extend simple interface type by directive", func(t *testing.T) { - run(t, newExtendInterfaceTypeDefinition(newTestNormalizer(false)), ` - interface Mammal { - name: String - } - - extend interface Mammal @deprecated(reason: "some reason") - `, ` - interface Mammal @deprecated(reason: "some reason") { - name: String - } - - extend interface Mammal @deprecated(reason: "some reason") - `) - }) - - t.Run("extend interface type by complex extends", func(t *testing.T) { - run(t, newExtendInterfaceTypeDefinition(newTestNormalizer(false)), ` - interface Mammal { - name: String - } - - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, ` - interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - name: String - furType: String - age: Int - } - - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `) - }) - - t.Run("Extending an interface that is a shared type returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInterfaceTypeDefinition(newTestNormalizer(false)), ` - interface Mammal { - name: String - } - - interface Mammal { - name: String - } - - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, sharedTypeExtensionErrorMessage("Mammal")) - }) - - t.Run("Unresolved interface extension orphan returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInterfaceTypeDefinition(newTestNormalizer(false)), ` - extend interface Mammal { - name: String! - } - `, unresolvedExtensionOrphansErrorMessage("Mammal")) - }) - - t.Run("Entity is extended successfully", func(t *testing.T) { - run(t, newExtendInterfaceTypeDefinition(newTestNormalizer(true)), ` - interface Mammal @key(fields: "name") { - name: String! - } - - extend interface Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, ` - interface Mammal @key(fields: "name") @key(fields: "name") { - - name: String! - name: String! @external - age: Int! - } - - extend interface Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `) - }) - - t.Run("No key directive on entity extension returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInterfaceTypeDefinition(newTestNormalizer(true)), ` - interface Mammal @key(fields: "name") { - name: String! - } - - extend interface Mammal { - name: String! @external - age: Int! - } - `, noKeyDirectiveErrorMessage("Mammal")) - }) - - t.Run("Non-key directive when extending an entity returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInterfaceTypeDefinition(newTestNormalizer(true)), ` - interface Mammal @key(fields: "name") { - name: String! - } - - extend interface Mammal @deprecated { - name: String! @external - age: Int! - } - `, noKeyDirectiveErrorMessage("Mammal")) - }) - - t.Run("Extending multiple entities returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInterfaceTypeDefinition(newTestNormalizer(true)), ` - interface Mammal @key(fields: "name") { - name: String! - } - - interface Mammal @key(fields: "name") { - name: String! - } - - extend interface Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, duplicateEntityErrorMessage("Mammal")) - }) - - t.Run("A non-entity that is extended by an extension with a key directive returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendInterfaceTypeDefinition(newTestNormalizer(false)), ` - interface Mammal { - name: String! - } - - extend interface Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, nonEntityExtensionErrorMessage("Mammal")) - }) -} diff --git a/pkg/federation/sdlmerge/merge_duplicated_fields.go b/pkg/federation/sdlmerge/merge_duplicated_fields.go deleted file mode 100644 index d98111614..000000000 --- a/pkg/federation/sdlmerge/merge_duplicated_fields.go +++ /dev/null @@ -1,62 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type mergeDuplicatedFieldsVisitor struct { - *astvisitor.Walker - document *ast.Document -} - -func newMergeDuplicatedFieldsVisitor() *mergeDuplicatedFieldsVisitor { - return &mergeDuplicatedFieldsVisitor{ - nil, - nil, - } -} - -func (m *mergeDuplicatedFieldsVisitor) Register(walker *astvisitor.Walker) { - m.Walker = walker - walker.RegisterEnterDocumentVisitor(m) - walker.RegisterLeaveObjectTypeDefinitionVisitor(m) -} - -func (m *mergeDuplicatedFieldsVisitor) EnterDocument(document, _ *ast.Document) { - m.document = document -} - -func (m *mergeDuplicatedFieldsVisitor) LeaveObjectTypeDefinition(ref int) { - var refsForDeletion []int - fieldByTypeRefSet := make(map[string]int) - for _, fieldRef := range m.document.ObjectTypeDefinitions[ref].FieldsDefinition.Refs { - fieldName := m.document.FieldDefinitionNameString(fieldRef) - newTypeRef := m.document.FieldDefinitions[fieldRef].Type - if oldTypeRef, ok := fieldByTypeRefSet[fieldName]; ok { - if m.document.TypesAreEqualDeep(oldTypeRef, newTypeRef) { - refsForDeletion = append(refsForDeletion, fieldRef) - continue - } - oldFieldTypeNameBytes, err := m.document.PrintTypeBytes(oldTypeRef, nil) - if err != nil { - m.Walker.StopWithInternalErr(err) - return - } - newFieldTypeNameBytes, err := m.document.PrintTypeBytes(newTypeRef, nil) - if err != nil { - m.Walker.StopWithInternalErr(err) - return - } - m.Walker.StopWithExternalErr(operationreport.ErrDuplicateFieldsMustBeIdentical( - fieldName, m.document.ObjectTypeDefinitionNameString(ref), string(oldFieldTypeNameBytes), string(newFieldTypeNameBytes), - )) - return - } - - fieldByTypeRefSet[fieldName] = newTypeRef - } - - m.document.RemoveFieldDefinitionsFromObjectTypeDefinition(refsForDeletion, ref) -} diff --git a/pkg/federation/sdlmerge/object_type_extending.go b/pkg/federation/sdlmerge/object_type_extending.go deleted file mode 100644 index aada85a70..000000000 --- a/pkg/federation/sdlmerge/object_type_extending.go +++ /dev/null @@ -1,66 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func newExtendObjectTypeDefinition(collectedEntities entitySet) *extendObjectTypeDefinitionVisitor { - return &extendObjectTypeDefinitionVisitor{ - collectedEntities: collectedEntities, - } -} - -type extendObjectTypeDefinitionVisitor struct { - *astvisitor.Walker - document *ast.Document - collectedEntities entitySet -} - -func (e *extendObjectTypeDefinitionVisitor) Register(walker *astvisitor.Walker) { - e.Walker = walker - walker.RegisterEnterDocumentVisitor(e) - walker.RegisterEnterObjectTypeExtensionVisitor(e) -} - -func (e *extendObjectTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.document = operation -} - -func (e *extendObjectTypeDefinitionVisitor) EnterObjectTypeExtension(ref int) { - nameBytes := e.document.ObjectTypeExtensionNameBytes(ref) - nodes, exists := e.document.Index.NodesByNameBytes(nameBytes) - if !exists { - return - } - - var nodeToExtend *ast.Node - isEntity := false - for i := range nodes { - if nodes[i].Kind != ast.NodeKindObjectTypeDefinition { - continue - } - if nodeToExtend != nil { - e.StopWithExternalErr(*multipleExtensionError(isEntity, nameBytes)) - return - } - var err *operationreport.ExternalError - extension := e.document.ObjectTypeExtensions[ref] - if isEntity, err = e.collectedEntities.isExtensionForEntity(nameBytes, extension.Directives.Refs, e.document); err != nil { - e.StopWithExternalErr(*err) - return - } - nodeToExtend = &nodes[i] - if ast.IsRootType(nameBytes) { - break - } - } - - if nodeToExtend == nil { - e.StopWithExternalErr(operationreport.ErrExtensionOrphansMustResolveInSupergraph(nameBytes)) - return - } - - e.document.ExtendObjectTypeDefinitionByObjectTypeExtension(nodeToExtend.Ref, ref) -} diff --git a/pkg/federation/sdlmerge/object_type_extending_test.go b/pkg/federation/sdlmerge/object_type_extending_test.go deleted file mode 100644 index 60ff32632..000000000 --- a/pkg/federation/sdlmerge/object_type_extending_test.go +++ /dev/null @@ -1,238 +0,0 @@ -package sdlmerge - -import "testing" - -func TestExtendObjectType(t *testing.T) { - t.Run("extend object type by field", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Dog { - name: String - } - - extend type Dog { - favoriteToy: String - } - `, ` - type Dog { - name: String - favoriteToy: String - } - - extend type Dog { - favoriteToy: String - } - `) - }) - - t.Run("extend object type by directive", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Cat { - name: String - } - - extend type Cat @deprecated(reason: "not as cool as dogs") - `, ` - type Cat @deprecated(reason: "not as cool as dogs") { - name: String - } - - extend type Cat @deprecated(reason: "not as cool as dogs") - `) - }) - - t.Run("extend object type by multiple field", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Dog { - name: String - } - - extend type Dog { - favoriteToy: String - breed: String - } - `, ` - type Dog { - name: String - favoriteToy: String - breed: String - } - - extend type Dog { - favoriteToy: String - breed: String - } - `) - }) - - t.Run("extend object type by multiple directives", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Cat { - name: String - } - - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) - `, ` - type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - name: String - } - - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) - `) - }) - - t.Run("extend object type by complex extends", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Cat { - name: String - } - - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - age: Int - breed: String - } - `, ` - type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - name: String - age: Int - breed: String - } - - extend type Cat @deprecated(reason: "not as cool as dogs") @skip(if: false) { - age: Int - breed: String - } - `) - }) - - t.Run("Extending an object that is a shared type returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Mammal { - name: String - } - - type Mammal { - name: String - } - - extend type Mammal @deprecated(reason: "not as cool as dogs") @skip(if: false) { - age: Int - breed: String - } - `, sharedTypeExtensionErrorMessage("Mammal")) - }) - - t.Run("Unresolved object extension orphan returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - extend type Mammal { - name: String! - } - `, unresolvedExtensionOrphansErrorMessage("Mammal")) - }) - - t.Run("Entity is extended successfully", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(true)), ` - type Mammal @key(fields: "name") { - name: String! - } - - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, ` - type Mammal @key(fields: "name") @key(fields: "name") { - - name: String! - name: String! @external - age: Int! - } - - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `) - }) - - t.Run("No key directive on entity extension returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendObjectTypeDefinition(newTestNormalizer(true)), ` - type Mammal @key(fields: "name") { - name: String! - } - - extend type Mammal { - name: String! @external - age: Int! - } - `, noKeyDirectiveErrorMessage("Mammal")) - }) - - t.Run("Non-key directive when extending an entity returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendObjectTypeDefinition(newTestNormalizer(true)), ` - type Mammal @key(fields: "name") { - name: String! - } - - extend type Mammal @deprecated { - name: String! @external - age: Int! - } - `, noKeyDirectiveErrorMessage("Mammal")) - }) - - t.Run("Extending multiple entities returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendObjectTypeDefinition(newTestNormalizer(true)), ` - type Mammal @key(fields: "name") { - name: String! - } - - type Mammal @key(fields: "name") { - name: String! - } - - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, duplicateEntityErrorMessage("Mammal")) - }) - - t.Run("A non-entity that is extended by an extension with a key directive returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendObjectTypeDefinition(newTestNormalizer(false)), ` - type Mammal { - name: String! - } - - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, nonEntityExtensionErrorMessage("Mammal")) - }) - - t.Run("", func(t *testing.T) { - run(t, newExtendObjectTypeDefinition(newTestNormalizer(true)), ` - type Mammal @key(fields: "name") { - name: String! - age: Int! - } - - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, ` - type Mammal @key(fields: "name") @key(fields: "name") { - name: String! - age: Int! - name: String! @external - age: Int! - } - - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `) - }) -} diff --git a/pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types.go b/pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types.go deleted file mode 100644 index cc618efd7..000000000 --- a/pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types.go +++ /dev/null @@ -1,107 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type removeDuplicateFieldedSharedTypesVisitor struct { - *astvisitor.Walker - document *ast.Document - sharedTypeSet map[string]fieldedSharedType - rootNodesToRemove []ast.Node - lastInputRef int - lastInterfaceRef int - lastObjectRef int -} - -func newRemoveDuplicateFieldedSharedTypesVisitor() *removeDuplicateFieldedSharedTypesVisitor { - return &removeDuplicateFieldedSharedTypesVisitor{ - nil, - nil, - make(map[string]fieldedSharedType), - nil, - ast.InvalidRef, - ast.InvalidRef, - ast.InvalidRef, - } -} - -func (r *removeDuplicateFieldedSharedTypesVisitor) Register(walker *astvisitor.Walker) { - r.Walker = walker - walker.RegisterEnterDocumentVisitor(r) - walker.RegisterEnterInputObjectTypeDefinitionVisitor(r) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(r) - walker.RegisterEnterObjectTypeDefinitionVisitor(r) - walker.RegisterLeaveDocumentVisitor(r) -} - -func (r *removeDuplicateFieldedSharedTypesVisitor) EnterDocument(operation, _ *ast.Document) { - r.document = operation -} - -func (r *removeDuplicateFieldedSharedTypesVisitor) EnterInputObjectTypeDefinition(ref int) { - if ref <= r.lastInputRef { - return - } - name := r.document.InputObjectTypeDefinitionNameString(ref) - refs := r.document.InputObjectTypeDefinitions[ref].InputFieldsDefinition.Refs - input, exists := r.sharedTypeSet[name] - if exists { - if !input.areFieldsIdentical(refs) { - r.StopWithExternalErr(operationreport.ErrSharedTypesMustBeIdenticalToFederate(name)) - return - } - r.rootNodesToRemove = append(r.rootNodesToRemove, ast.Node{Kind: ast.NodeKindInputObjectTypeDefinition, Ref: ref}) - } else { - r.sharedTypeSet[name] = newFieldedSharedType(r.document, ast.NodeKindInputValueDefinition, refs) - } - r.lastInputRef = ref -} - -func (r *removeDuplicateFieldedSharedTypesVisitor) EnterInterfaceTypeDefinition(ref int) { - if ref <= r.lastInterfaceRef { - return - } - name := r.document.InterfaceTypeDefinitionNameString(ref) - interfaceType := r.document.InterfaceTypeDefinitions[ref] - refs := interfaceType.FieldsDefinition.Refs - iFace, exists := r.sharedTypeSet[name] - if exists { - if !iFace.areFieldsIdentical(refs) { - r.StopWithExternalErr(operationreport.ErrSharedTypesMustBeIdenticalToFederate(name)) - return - } - r.rootNodesToRemove = append(r.rootNodesToRemove, ast.Node{Kind: ast.NodeKindInterfaceTypeDefinition, Ref: ref}) - } else { - r.sharedTypeSet[name] = newFieldedSharedType(r.document, ast.NodeKindFieldDefinition, refs) - } - r.lastInterfaceRef = ref -} - -func (r *removeDuplicateFieldedSharedTypesVisitor) EnterObjectTypeDefinition(ref int) { - if ref <= r.lastObjectRef { - return - } - name := r.document.ObjectTypeDefinitionNameString(ref) - objectType := r.document.ObjectTypeDefinitions[ref] - refs := objectType.FieldsDefinition.Refs - object, exists := r.sharedTypeSet[name] - if exists { - if !object.areFieldsIdentical(refs) { - r.StopWithExternalErr(operationreport.ErrSharedTypesMustBeIdenticalToFederate(name)) - return - } - r.rootNodesToRemove = append(r.rootNodesToRemove, ast.Node{Kind: ast.NodeKindObjectTypeDefinition, Ref: ref}) - } else { - r.sharedTypeSet[name] = newFieldedSharedType(r.document, ast.NodeKindFieldDefinition, refs) - } - r.lastObjectRef = ref -} - -func (r *removeDuplicateFieldedSharedTypesVisitor) LeaveDocument(_, _ *ast.Document) { - if r.rootNodesToRemove != nil { - r.document.DeleteRootNodes(r.rootNodesToRemove) - } -} diff --git a/pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types_test.go b/pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types_test.go deleted file mode 100644 index ec67045af..000000000 --- a/pkg/federation/sdlmerge/remove_duplicate_fielded_shared_types_test.go +++ /dev/null @@ -1,529 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestRemoveDuplicateFieldedValueTypes(t *testing.T) { - t.Run("Same name empty inputs are merged into a single input", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Trainer { - } - - input Trainer { - } - `, ` - input Trainer { - } - `) - }) - - t.Run("Identical same name inputs are merged into a single input", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: Int! - } - `, ` - input Trainer { - name: String! - age: Int! - } - `) - }) - - t.Run("Identical same name inputs are merged into a single input regardless of field order", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Trainer { - age: Int! - name: String! - } - - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: Int! - } - `, ` - input Trainer { - age: Int! - name: String! - } - `) - }) - - t.Run("Groups of identical same name inputs are respectively merged into single inputs", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: Int! - } - - input Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - `, ` - input Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - - input Trainer { - name: String! - age: Int! - } - `) - }) - - t.Run("Same name inputs with different nullability of fields return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String - age: Int! - } - - input Trainer { - name: String! - age: Int - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name inputs with different fields return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Trainer { - name: String - age: Int - } - - input Trainer { - name: String - age: Int - } - - input Trainer { - name: String - age: Int - badges: Int - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name inputs with a slight difference in nested field values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Pokemon { - type: [[[[Type!]]!]!]! - } - - input Pokemon { - type: [[[[Type!]]]!]! - } - - input Pokemon { - type: [[[[Type!]]!]!]! - } - `, NonIdenticalSharedTypeErrorMessage("Pokemon")) - }) - - t.Run("Same name inputs with different non-nullable field values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: Int! - } - - input Trainer { - name: String! - age: String! - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name empty interfaces are merged into a single interface", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Trainer { - } - - interface Trainer { - } - `, ` - interface Trainer { - } - `) - }) - - t.Run("Identical same name interfaces are merged into a single interface", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: Int! - } - `, ` - interface Trainer { - name: String! - age: Int! - } - `) - }) - - t.Run("Identical same name interfaces are merged into a single input regardless of field order", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Trainer { - age: Int! - name: String! - } - - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: Int! - } - `, ` - interface Trainer { - age: Int! - name: String! - } - `) - }) - - t.Run("Groups of identical same name interfaces are respectively merged into single interfaces", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: Int! - } - - interface Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - `, ` - interface Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - - interface Trainer { - name: String! - age: Int! - } - `) - }) - - t.Run("Same name interfaces with different nullability of fields return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String - age: Int! - } - - interface Trainer { - name: String! - age: Int - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name interfaces with different fields return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Trainer { - name: String - age: Int - } - - interface Trainer { - name: String - age: Int - } - - interface Trainer { - name: String - age: Int - badges: Int - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name interfaces with a slight difference in nested field values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Pokemon { - type: [[[[Type!]]!]!]! - } - - interface Pokemon { - type: [[[[Type!]]]!]! - } - - interface Pokemon { - type: [[[[Type!]]!]!]! - } - `, NonIdenticalSharedTypeErrorMessage("Pokemon")) - }) - - t.Run("Same name interfaces with different non-nullable field values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: Int! - } - - interface Trainer { - name: String! - age: String! - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name empty objects are merged into a single object", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Trainer { - } - - type Trainer { - } - `, ` - type Trainer { - } - `) - }) - - t.Run("Identical same name objects are merged into a single object", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: Int! - } - `, ` - type Trainer { - name: String! - age: Int! - } - `) - }) - - t.Run("Identical same name objects are merged into a single input regardless of field order", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Trainer { - age: Int! - name: String! - } - - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: Int! - } - `, ` - type Trainer { - age: Int! - name: String! - } - `) - }) - - t.Run("Groups of identical same name objects are respectively merged into single objects", func(t *testing.T) { - run(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: Int! - } - - type Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - `, ` - type Pokemon { - type: [Type!]! - isEvolved: Boolean! - } - - type Trainer { - name: String! - age: Int! - } - `) - }) - - t.Run("Same name objects with different nullability of fields return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String - age: Int! - } - - type Trainer { - name: String! - age: Int - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name objects with different fields return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Trainer { - name: String - age: Int - } - - type Trainer { - name: String - age: Int - } - - type Trainer { - name: String - age: Int - badges: Int - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) - - t.Run("Same name objects with a slight difference in nested field values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Pokemon { - type: [[[[Type!]]!]!]! - } - - type Pokemon { - type: [[[[Type!]]]!]! - } - - type Pokemon { - type: [[[[Type!]]!]!]! - } - `, NonIdenticalSharedTypeErrorMessage("Pokemon")) - }) - - t.Run("Same name objects with different non-nullable field values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldedSharedTypesVisitor(), ` - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: Int! - } - - type Trainer { - name: String! - age: String! - } - `, NonIdenticalSharedTypeErrorMessage("Trainer")) - }) -} diff --git a/pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types.go b/pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types.go deleted file mode 100644 index 7fcf8c7a7..000000000 --- a/pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types.go +++ /dev/null @@ -1,98 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type removeDuplicateFieldlessSharedTypesVisitor struct { - *astvisitor.Walker - document *ast.Document - sharedTypeSet map[string]fieldlessSharedType - rootNodesToRemove []ast.Node - lastEnumRef int - lastUnionRef int - lastScalarRef int -} - -func newRemoveDuplicateFieldlessSharedTypesVisitor() *removeDuplicateFieldlessSharedTypesVisitor { - return &removeDuplicateFieldlessSharedTypesVisitor{ - nil, - nil, - make(map[string]fieldlessSharedType), - nil, - ast.InvalidRef, - ast.InvalidRef, - ast.InvalidRef, - } -} - -func (r *removeDuplicateFieldlessSharedTypesVisitor) Register(walker *astvisitor.Walker) { - r.Walker = walker - walker.RegisterEnterDocumentVisitor(r) - walker.RegisterEnterEnumTypeDefinitionVisitor(r) - walker.RegisterEnterScalarTypeDefinitionVisitor(r) - walker.RegisterEnterUnionTypeDefinitionVisitor(r) - walker.RegisterLeaveDocumentVisitor(r) -} - -func (r *removeDuplicateFieldlessSharedTypesVisitor) EnterDocument(operation, _ *ast.Document) { - r.document = operation -} - -func (r *removeDuplicateFieldlessSharedTypesVisitor) EnterEnumTypeDefinition(ref int) { - if ref <= r.lastEnumRef { - return - } - name := r.document.EnumTypeDefinitionNameString(ref) - enum, exists := r.sharedTypeSet[name] - if exists { - if !enum.areValuesIdentical(r.document.EnumTypeDefinitions[ref].EnumValuesDefinition.Refs) { - r.StopWithExternalErr(operationreport.ErrSharedTypesMustBeIdenticalToFederate(name)) - return - } - r.rootNodesToRemove = append(r.rootNodesToRemove, ast.Node{Kind: ast.NodeKindEnumTypeDefinition, Ref: ref}) - } else { - r.sharedTypeSet[name] = newEnumSharedType(r.document, ref) - } - r.lastEnumRef = ref -} - -func (r *removeDuplicateFieldlessSharedTypesVisitor) EnterScalarTypeDefinition(ref int) { - if ref <= r.lastScalarRef { - return - } - name := r.document.ScalarTypeDefinitionNameString(ref) - _, exists := r.sharedTypeSet[name] - if exists { - r.rootNodesToRemove = append(r.rootNodesToRemove, ast.Node{Kind: ast.NodeKindScalarTypeDefinition, Ref: ref}) - } else { - r.sharedTypeSet[name] = scalarSharedType{} - } - r.lastScalarRef = ref -} - -func (r *removeDuplicateFieldlessSharedTypesVisitor) EnterUnionTypeDefinition(ref int) { - if ref <= r.lastUnionRef { - return - } - name := r.document.UnionTypeDefinitionNameString(ref) - union, exists := r.sharedTypeSet[name] - if exists { - if !union.areValuesIdentical(r.document.UnionTypeDefinitions[ref].UnionMemberTypes.Refs) { - r.StopWithExternalErr(operationreport.ErrSharedTypesMustBeIdenticalToFederate(name)) - return - } - r.rootNodesToRemove = append(r.rootNodesToRemove, ast.Node{Kind: ast.NodeKindUnionTypeDefinition, Ref: ref}) - } else { - r.sharedTypeSet[name] = newUnionSharedType(r.document, ref) - } - r.lastUnionRef = ref -} - -func (r *removeDuplicateFieldlessSharedTypesVisitor) LeaveDocument(_, _ *ast.Document) { - if r.rootNodesToRemove != nil { - r.document.DeleteRootNodes(r.rootNodesToRemove) - } -} diff --git a/pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types_test.go b/pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types_test.go deleted file mode 100644 index acefe2e25..000000000 --- a/pkg/federation/sdlmerge/remove_duplicate_fieldless_shared_types_test.go +++ /dev/null @@ -1,373 +0,0 @@ -package sdlmerge - -import ( - "fmt" - "testing" -) - -func TestRemoveDuplicateFieldlessSharedTypes(t *testing.T) { - t.Run("Input and output are identical when no duplications", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - `, ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - `) - }) - - t.Run("Identical same name enums are merged", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - `, ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - `) - }) - - t.Run("Identical same name enums are merged into a single input regardless of value order", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - - enum Pokemon { - SQUIRTLE, - CHARMANDER, - BULBASAUR, - } - `, ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - `) - }) - - t.Run("Same name enums with different values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - } - - enum Pokemon { - BULBASAUR, - CHARMANDER, - SQUIRTLE, - MEW, - } - `, NonIdenticalSharedTypeErrorMessage(pokemon)) - }) - - t.Run("Empty and populated same name enums return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - } - - enum Pokemon { - CHARMANDER, - SQUIRTLE, - } - `, NonIdenticalSharedTypeErrorMessage(pokemon)) - }) - - t.Run("Empty enums are merged into a single empty enum", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - } - - enum Pokemon { - } - `, ` - enum Pokemon { - } - `) - }) - - t.Run("Same name enums with no overlapping values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - } - - enum Pokemon { - SQUIRTLE, - MEW, - } - `, NonIdenticalSharedTypeErrorMessage(pokemon)) - }) - - t.Run("Same name enums with varying overlapping values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Pokemon { - BULBASAUR, - CHARMANDER, - } - - enum Pokemon { - CHARMANDER, - MEW, - } - - enum Pokemon { - BULBASAUR, - MEW, - } - - enum Pokemon { - BULBASAUR, - SQUIRTLE, - } - `, NonIdenticalSharedTypeErrorMessage(pokemon)) - }) - - t.Run("Different groups of same name enums return an error immediately upon invalidation", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - enum Cities { - CERULEAN, - SAFFRON, - } - - enum Types { - GRASS, - FIRE, - ROCK, - } - - enum Badges { - } - - enum Types { - FIRE, - WATER, - } - - enum Badges { - BOULDER, - VOLCANO, - EARTH, - } - - enum Cities { - VIRIDIAN, - SAFFRON, - CELADON, - } - - enum Types { - ROCK, - GRASS, - FIRE, - WATER, - } - - enum Badges { - MARSH, - SOUL, - VOLCANO, - THUNDER, - RAINBOW, - CASCADE, - } - - enum Badges { - VOLCANO, - RAINBOW, - BOULDER, - SOUL, - } - - enum Types { - WATER, - FIRE, - } - - enum Badges { - } - - enum Badges { - EARTH, - THUNDER, - } - - enum Cities { - } - - enum Cities { - CERULEAN, - CELADON, - } - `, NonIdenticalSharedTypeErrorMessage(types)) - }) - - t.Run("Input and output are identical when no scalar duplications", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - scalar DateTime - `, ` - scalar DateTime - `) - }) - - t.Run("Same name scalars are removed to leave only one", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - scalar DateTime - - scalar DateTime - - scalar DateTime - `, ` - scalar DateTime - `) - }) - - t.Run("Any more than one of a same name scalar are removed", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - scalar DateTime - - scalar BigInt - - scalar BigInt - - scalar CustomScalar - - scalar DateTime - - scalar UniqueScalar - - scalar BigInt - - scalar CustomScalar - - scalar CustomScalar - - scalar DateTime - - scalar CustomScalar - - scalar DateTime - `, ` - scalar DateTime - - scalar BigInt - - scalar CustomScalar - - scalar UniqueScalar - `) - }) - - t.Run("Input and output are identical when no duplications", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Types = Grass | Fire | Water - `, ` - union Types = Grass | Fire | Water - `) - }) - - t.Run("Identical same name unions are merged", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Types = Grass | Fire | Water - - union Types = Grass | Fire | Water - `, ` - union Types = Grass | Fire | Water - `) - }) - - t.Run("Identical same name unions are merged into a single input regardless of value order", func(t *testing.T) { - run(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Types = Grass | Fire | Water - - union Types = Water | Grass | Fire - `, ` - union Types = Grass | Fire | Water - `) - }) - - t.Run("Same name unions with different values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Types = Grass | Fire | Water - - union Types = Grass | Fire | Water | Rock - `, NonIdenticalSharedTypeErrorMessage(types)) - }) - - t.Run("Same name unions with no overlapping values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Types = Grass | Fire - - union Types = Water | Rock - `, NonIdenticalSharedTypeErrorMessage(types)) - }) - - t.Run("Same name unions with varying overlapping values return an error", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Types = Grass | Fire - - union Types = Fire | Water - - union Types = Rock | Grass - - union Types = Water | Fire - `, NonIdenticalSharedTypeErrorMessage(types)) - }) - - t.Run("Different groups of same name unions return an error immediately upon invalidation", func(t *testing.T) { - runAndExpectError(t, newRemoveDuplicateFieldlessSharedTypesVisitor(), ` - union Cities = Cerulean | Saffron - - union Types = Grass | Fire | Rock - - union Badges = Boulder | Volcano | Earth - - union Cities = Viridian | Saffron | Celadon - - union Types = Rock | Grass | Fire | Water - - union Badges = Marsh | Soul | Volcano | Thunder | Rainbow | Cascade - - union Badges = Volcano | Rainbow | Boulder | Soul - - union Types = Water | Fire - - union Badges = Earth | Thunder - - union Cities = Cerulean | Celadon - `, NonIdenticalSharedTypeErrorMessage(cities)) - }) -} - -const ( - cities = "Cities" - pokemon = "Pokemon" - types = "Types" -) - -func NonIdenticalSharedTypeErrorMessage(typeName string) string { - return fmt.Sprintf("the shared type named '%s' must be identical in any subgraphs to federate", typeName) -} diff --git a/pkg/federation/sdlmerge/remove_empty_object_type_definition.go b/pkg/federation/sdlmerge/remove_empty_object_type_definition.go deleted file mode 100644 index cc32f7fdb..000000000 --- a/pkg/federation/sdlmerge/remove_empty_object_type_definition.go +++ /dev/null @@ -1,32 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func newRemoveEmptyObjectTypeDefinition() *removeEmptyObjectTypeDefinition { - return &removeEmptyObjectTypeDefinition{} -} - -type removeEmptyObjectTypeDefinition struct{} - -func (r *removeEmptyObjectTypeDefinition) Register(walker *astvisitor.Walker) { - walker.RegisterLeaveDocumentVisitor(r) -} - -func (r *removeEmptyObjectTypeDefinition) LeaveDocument(operation, _ *ast.Document) { - for ref := range operation.ObjectTypeDefinitions { - if operation.ObjectTypeDefinitions[ref].HasFieldDefinitions { - continue - } - - name := operation.ObjectTypeDefinitionNameString(ref) - node, ok := operation.Index.FirstNodeByNameStr(name) - if !ok { - return - } - - operation.RemoveRootNode(node) - } -} diff --git a/pkg/federation/sdlmerge/remove_empty_object_type_definition_test.go b/pkg/federation/sdlmerge/remove_empty_object_type_definition_test.go deleted file mode 100644 index f280df353..000000000 --- a/pkg/federation/sdlmerge/remove_empty_object_type_definition_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestRemoveEmptyObjectTypeDefinitionDirective(t *testing.T) { - t.Run("remove object definition without fields", func(t *testing.T) { - run(t, newRemoveEmptyObjectTypeDefinition(), ` - type Query { - } - type Cat { - name: String! - } - `, ` - type Cat { - name: String! - } - `) - }) -} diff --git a/pkg/federation/sdlmerge/remove_field_definition_by_directive.go b/pkg/federation/sdlmerge/remove_field_definition_by_directive.go deleted file mode 100644 index 8d707746e..000000000 --- a/pkg/federation/sdlmerge/remove_field_definition_by_directive.go +++ /dev/null @@ -1,46 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func newRemoveFieldDefinitions(directives ...string) *removeFieldDefinitionByDirective { - directivesSet := make(map[string]struct{}, len(directives)) - for _, directive := range directives { - directivesSet[directive] = struct{}{} - } - - return &removeFieldDefinitionByDirective{ - directives: directivesSet, - } -} - -type removeFieldDefinitionByDirective struct { - operation *ast.Document - directives map[string]struct{} -} - -func (r *removeFieldDefinitionByDirective) Register(walker *astvisitor.Walker) { - walker.RegisterEnterDocumentVisitor(r) - walker.RegisterLeaveObjectTypeDefinitionVisitor(r) -} - -func (r *removeFieldDefinitionByDirective) EnterDocument(operation, _ *ast.Document) { - r.operation = operation -} - -func (r *removeFieldDefinitionByDirective) LeaveObjectTypeDefinition(ref int) { - var refsForDeletion []int - // select fields for deletion - for _, fieldRef := range r.operation.ObjectTypeDefinitions[ref].FieldsDefinition.Refs { - for _, directiveRef := range r.operation.FieldDefinitions[fieldRef].Directives.Refs { - directiveName := r.operation.DirectiveNameString(directiveRef) - if _, ok := r.directives[directiveName]; ok { - refsForDeletion = append(refsForDeletion, fieldRef) - } - } - } - // delete fields - r.operation.RemoveFieldDefinitionsFromObjectTypeDefinition(refsForDeletion, ref) -} diff --git a/pkg/federation/sdlmerge/remove_field_definition_by_directive_test.go b/pkg/federation/sdlmerge/remove_field_definition_by_directive_test.go deleted file mode 100644 index 534771b0b..000000000 --- a/pkg/federation/sdlmerge/remove_field_definition_by_directive_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestRemoveFieldDirective(t *testing.T) { - t.Run("remove field with specified directive", func(t *testing.T) { - run( - t, newRemoveFieldDefinitions("forDelete"), - ` - type Dog { - name: String @notForDelete - favoriteToy: String @forDelete - barkVolume: Int - isHousetrained(atOtherHomes: Boolean): Boolean! @forDelete - doesKnowCommand(dogCommand: DogCommand!): Boolean! - } - `, - ` - type Dog { - name: String @notForDelete - barkVolume: Int - doesKnowCommand(dogCommand: DogCommand!): Boolean! - } - `) - }) -} diff --git a/pkg/federation/sdlmerge/remove_field_definition_directive.go b/pkg/federation/sdlmerge/remove_field_definition_directive.go deleted file mode 100644 index fb74dcbfa..000000000 --- a/pkg/federation/sdlmerge/remove_field_definition_directive.go +++ /dev/null @@ -1,44 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func newRemoveFieldDefinitionDirective(directives ...string) *removeFieldDefinitionDirective { - directivesSet := make(map[string]struct{}, len(directives)) - for _, directive := range directives { - directivesSet[directive] = struct{}{} - } - - return &removeFieldDefinitionDirective{ - directives: directivesSet, - } -} - -type removeFieldDefinitionDirective struct { - operation *ast.Document - directives map[string]struct{} -} - -func (r *removeFieldDefinitionDirective) Register(walker *astvisitor.Walker) { - walker.RegisterEnterDocumentVisitor(r) - walker.RegisterEnterFieldDefinitionVisitor(r) -} - -func (r *removeFieldDefinitionDirective) EnterDocument(operation, _ *ast.Document) { - r.operation = operation -} - -func (r *removeFieldDefinitionDirective) EnterFieldDefinition(ref int) { - var refsForDeletion []int - // select directives for deletion - for _, directiveRef := range r.operation.FieldDefinitions[ref].Directives.Refs { - directiveName := r.operation.DirectiveNameString(directiveRef) - if _, ok := r.directives[directiveName]; ok { - refsForDeletion = append(refsForDeletion, directiveRef) - } - } - // delete directives - r.operation.RemoveDirectivesFromNode(ast.Node{Kind: ast.NodeKindFieldDefinition, Ref: ref}, refsForDeletion) -} diff --git a/pkg/federation/sdlmerge/remove_field_definition_directive_test.go b/pkg/federation/sdlmerge/remove_field_definition_directive_test.go deleted file mode 100644 index 72600e97b..000000000 --- a/pkg/federation/sdlmerge/remove_field_definition_directive_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestRemoveFieldDefinitionDirective(t *testing.T) { - t.Run("remove specified directive from field definition", func(t *testing.T) { - run( - t, - newRemoveFieldDefinitionDirective("requires", "provides"), - ` - type Dog { - name: String! - age: Int! - code: String @requires(fields: "name age") - owner: Owner @provides(fields: "name") - } - `, - ` - type Dog { - name: String! - age: Int! - code: String - owner: Owner - }`, - ) - }) -} diff --git a/pkg/federation/sdlmerge/remove_interface_definition_directive.go b/pkg/federation/sdlmerge/remove_interface_definition_directive.go deleted file mode 100644 index 0bc741d03..000000000 --- a/pkg/federation/sdlmerge/remove_interface_definition_directive.go +++ /dev/null @@ -1,45 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func newRemoveInterfaceDefinitionDirective(directives ...string) *removeInterfaceDefinitionDirective { - directivesSet := make(map[string]struct{}, len(directives)) - for _, directive := range directives { - directivesSet[directive] = struct{}{} - } - - return &removeInterfaceDefinitionDirective{ - directives: directivesSet, - } -} - -type removeInterfaceDefinitionDirective struct { - *astvisitor.Walker - operation *ast.Document - directives map[string]struct{} -} - -func (r *removeInterfaceDefinitionDirective) Register(walker *astvisitor.Walker) { - walker.RegisterEnterDocumentVisitor(r) - walker.RegisterEnterInterfaceTypeDefinitionVisitor(r) -} - -func (r *removeInterfaceDefinitionDirective) EnterDocument(operation, _ *ast.Document) { - r.operation = operation -} - -func (r *removeInterfaceDefinitionDirective) EnterInterfaceTypeDefinition(ref int) { - var refsForDeletion []int - // select fields for deletion - for _, directiveRef := range r.operation.InterfaceTypeDefinitions[ref].Directives.Refs { - directiveName := r.operation.DirectiveNameString(directiveRef) - if _, ok := r.directives[directiveName]; ok { - refsForDeletion = append(refsForDeletion, directiveRef) - } - } - // delete directives - r.operation.RemoveDirectivesFromNode(ast.Node{Kind: ast.NodeKindInterfaceTypeDefinition, Ref: ref}, refsForDeletion) -} diff --git a/pkg/federation/sdlmerge/remove_interface_definition_directive_test.go b/pkg/federation/sdlmerge/remove_interface_definition_directive_test.go deleted file mode 100644 index 52abbc0e9..000000000 --- a/pkg/federation/sdlmerge/remove_interface_definition_directive_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestRemoveInterfaceDefinitionDirective(t *testing.T) { - t.Run("remove specified directive from interface", func(t *testing.T) { - run( - t, newRemoveInterfaceDefinitionDirective("key"), - ` - interface Mammal @key(fields: "name") { - name: String - } - `, - ` - interface Mammal { - name: String - } - `) - }) - t.Run("remove multiple specified directive from interface", func(t *testing.T) { - run( - t, newRemoveInterfaceDefinitionDirective("key"), - ` - interface Mammal @key(fields: "name") @key(fields: "favoriteToy") { - name: String - } - `, - ` - interface Mammal { - name: String - } - `) - }) - t.Run("remove specified directive from interface with different directives", func(t *testing.T) { - run( - t, newRemoveInterfaceDefinitionDirective("key"), - ` - interface Mammal @key(fields: "name") @notForDeletion(fields: "favoriteToy") { - name: String - } - `, - ` - interface Mammal @notForDeletion(fields: "favoriteToy") { - name: String - } - `) - }) -} diff --git a/pkg/federation/sdlmerge/remove_object_type_definition_directive.go b/pkg/federation/sdlmerge/remove_object_type_definition_directive.go deleted file mode 100644 index 676fe1c44..000000000 --- a/pkg/federation/sdlmerge/remove_object_type_definition_directive.go +++ /dev/null @@ -1,44 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func newRemoveObjectTypeDefinitionDirective(directives ...string) *removeObjectTypeDefinitionDirective { - directivesSet := make(map[string]struct{}, len(directives)) - for _, directive := range directives { - directivesSet[directive] = struct{}{} - } - - return &removeObjectTypeDefinitionDirective{ - directives: directivesSet, - } -} - -type removeObjectTypeDefinitionDirective struct { - operation *ast.Document - directives map[string]struct{} -} - -func (r *removeObjectTypeDefinitionDirective) Register(walker *astvisitor.Walker) { - walker.RegisterEnterDocumentVisitor(r) - walker.RegisterEnterObjectTypeDefinitionVisitor(r) -} - -func (r *removeObjectTypeDefinitionDirective) EnterDocument(operation, _ *ast.Document) { - r.operation = operation -} - -func (r *removeObjectTypeDefinitionDirective) EnterObjectTypeDefinition(ref int) { - var refsForDeletion []int - // select fields for deletion - for _, directiveRef := range r.operation.ObjectTypeDefinitions[ref].Directives.Refs { - directiveName := r.operation.DirectiveNameString(directiveRef) - if _, ok := r.directives[directiveName]; ok { - refsForDeletion = append(refsForDeletion, directiveRef) - } - } - // delete directives - r.operation.RemoveDirectivesFromNode(ast.Node{Kind: ast.NodeKindObjectTypeDefinition, Ref: ref}, refsForDeletion) -} diff --git a/pkg/federation/sdlmerge/remove_object_type_definition_directive_test.go b/pkg/federation/sdlmerge/remove_object_type_definition_directive_test.go deleted file mode 100644 index c579d623d..000000000 --- a/pkg/federation/sdlmerge/remove_object_type_definition_directive_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestRemoveObjectTypeDefinitionDirective(t *testing.T) { - t.Run("remove specified directive from object definition", func(t *testing.T) { - run( - t, newRemoveObjectTypeDefinitionDirective("key"), - ` - type Dog @key(fields: "name") { - name: String - favoriteToy: String - barkVolume: Int - } - `, - ` - type Dog { - name: String - favoriteToy: String - barkVolume: Int - } - `) - }) - t.Run("remove multiple specified directive from object definition", func(t *testing.T) { - run( - t, newRemoveObjectTypeDefinitionDirective("key"), - ` - type Dog @key(fields: "name") @key(fields: "favoriteToy") { - name: String - favoriteToy: String - barkVolume: Int - } - `, - ` - type Dog { - name: String - favoriteToy: String - barkVolume: Int - } - `) - }) - t.Run("remove specified directive from object definition with different directives", func(t *testing.T) { - run( - t, newRemoveObjectTypeDefinitionDirective("key"), - ` - type Dog @key(fields: "name") @notForDeletion(fields: "favoriteToy") { - name: String - favoriteToy: String - barkVolume: Int - } - `, - ` - type Dog @notForDeletion(fields: "favoriteToy") { - name: String - favoriteToy: String - barkVolume: Int - } - `) - }) -} diff --git a/pkg/federation/sdlmerge/remove_type_extensions.go b/pkg/federation/sdlmerge/remove_type_extensions.go deleted file mode 100644 index d4a6b5dcf..000000000 --- a/pkg/federation/sdlmerge/remove_type_extensions.go +++ /dev/null @@ -1,21 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" -) - -func newRemoveMergedTypeExtensions() *removeMergedTypeExtensionsVisitor { - return &removeMergedTypeExtensionsVisitor{} -} - -type removeMergedTypeExtensionsVisitor struct { -} - -func (r *removeMergedTypeExtensionsVisitor) Register(walker *astvisitor.Walker) { - walker.RegisterLeaveDocumentVisitor(r) -} - -func (r *removeMergedTypeExtensionsVisitor) LeaveDocument(operation, definition *ast.Document) { - operation.RemoveMergedTypeExtensions() -} diff --git a/pkg/federation/sdlmerge/remove_type_extensions_test.go b/pkg/federation/sdlmerge/remove_type_extensions_test.go deleted file mode 100644 index f6aec0073..000000000 --- a/pkg/federation/sdlmerge/remove_type_extensions_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package sdlmerge - -import "testing" - -func TestRemoveTypeExtensions(t *testing.T) { - t.Run("remove single type extension of fieldDefinition", func(t *testing.T) { - runMany(t, ` - type Dog { - name: String - } - extend type Dog { - favoriteToy: String - } - `, ` - type Dog { - name: String - favoriteToy: String - } - `, - newExtendObjectTypeDefinition(newTestNormalizer(false)), - newRemoveMergedTypeExtensions()) - }) - t.Run("remove single type extension of directive", func(t *testing.T) { - runMany(t, ` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") - `, ` - type Cat @deprecated(reason: "not as cool as dogs") { - name: String - } - `, - newExtendObjectTypeDefinition(newTestNormalizer(false)), - newRemoveMergedTypeExtensions()) - }) - t.Run("remove multiple type extensions at once", func(t *testing.T) { - runMany(t, ` - type Cat { - name: String - } - extend type Cat @deprecated(reason: "not as cool as dogs") - extend type Cat { - age: Int - } - `, ` - type Cat @deprecated(reason: "not as cool as dogs") { - name: String - age: Int - } - `, - newExtendObjectTypeDefinition(newTestNormalizer(false)), - newRemoveMergedTypeExtensions()) - }) - t.Run("remove interface type extensions", func(t *testing.T) { - runMany(t, ` - interface Mammal { - name: String - } - extend interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - furType: String - age: Int - } - `, ` - interface Mammal @deprecated(reason: "some reason") @skip(if: false) { - name: String - furType: String - age: Int - } - `, - newExtendInterfaceTypeDefinition(newTestNormalizer(false)), - newRemoveMergedTypeExtensions()) - }) - t.Run("keep not merged type extension", func(t *testing.T) { - runMany(t, ` - extend type User { - field: String! - } - `, ` - extend type User { - field: String! - } - `, - newExtendInterfaceTypeDefinition(newTestNormalizer(false)), - newRemoveMergedTypeExtensions(), - ) - }) -} diff --git a/pkg/federation/sdlmerge/scalar_type_extending.go b/pkg/federation/sdlmerge/scalar_type_extending.go deleted file mode 100644 index 24669a9ce..000000000 --- a/pkg/federation/sdlmerge/scalar_type_extending.go +++ /dev/null @@ -1,49 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func newExtendScalarTypeDefinition() *extendScalarTypeDefinitionVisitor { - return &extendScalarTypeDefinitionVisitor{} -} - -type extendScalarTypeDefinitionVisitor struct { - *astvisitor.Walker - document *ast.Document -} - -func (e *extendScalarTypeDefinitionVisitor) Register(walker *astvisitor.Walker) { - e.Walker = walker - walker.RegisterEnterDocumentVisitor(e) - walker.RegisterEnterScalarTypeExtensionVisitor(e) -} - -func (e *extendScalarTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.document = operation -} - -func (e *extendScalarTypeDefinitionVisitor) EnterScalarTypeExtension(ref int) { - nodes, exists := e.document.Index.NodesByNameBytes(e.document.ScalarTypeExtensionNameBytes(ref)) - if !exists { - return - } - - hasExtended := false - for i := range nodes { - if nodes[i].Kind != ast.NodeKindScalarTypeDefinition { - continue - } - if hasExtended { - e.StopWithExternalErr(operationreport.ErrSharedTypesMustNotBeExtended(e.document.ScalarTypeExtensionNameString(ref))) - return - } - e.document.ExtendScalarTypeDefinitionByScalarTypeExtension(nodes[i].Ref, ref) - hasExtended = true - } - if !hasExtended { - e.StopWithExternalErr(operationreport.ErrExtensionOrphansMustResolveInSupergraph(e.document.ScalarTypeExtensionNameBytes(ref))) - } -} diff --git a/pkg/federation/sdlmerge/scalar_type_extending_test.go b/pkg/federation/sdlmerge/scalar_type_extending_test.go deleted file mode 100644 index 4dbb82dca..000000000 --- a/pkg/federation/sdlmerge/scalar_type_extending_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package sdlmerge - -import "testing" - -func TestExtendScalarType(t *testing.T) { - t.Run("Scalar types can be extended", func(t *testing.T) { - run(t, newExtendScalarTypeDefinition(), ` - scalar Attack - extend scalar Attack @deprecated(reason: "some reason") @skip(if: false) - `, ` - scalar Attack @deprecated(reason: "some reason") @skip(if: false) - extend scalar Attack @deprecated(reason: "some reason") @skip(if: false) - `) - }) - - t.Run("Extending a scalar that is a shared type returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendScalarTypeDefinition(), ` - scalar Attack - scalar Attack - extend scalar Attack @deprecated(reason: "some reason") @skip(if: false) - `, sharedTypeExtensionErrorMessage("Attack")) - }) - - t.Run("Unresolved scalar extension orphan returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendScalarTypeDefinition(), ` - extend scalar Badges @onScalar - `, unresolvedExtensionOrphansErrorMessage("Badges")) - }) -} diff --git a/pkg/federation/sdlmerge/sdlmerge.go b/pkg/federation/sdlmerge/sdlmerge.go deleted file mode 100644 index 78abf0ac4..000000000 --- a/pkg/federation/sdlmerge/sdlmerge.go +++ /dev/null @@ -1,205 +0,0 @@ -package sdlmerge - -import ( - "fmt" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const ( - rootOperationTypeDefinitions = ` - type Query {} - type Mutation {} - type Subscription {} - ` - - parseDocumentError = "parse graphql document string: %w" -) - -type Visitor interface { - Register(walker *astvisitor.Walker) -} - -func MergeAST(ast *ast.Document) error { - normalizer := normalizer{} - normalizer.setupWalkers() - - return normalizer.normalize(ast) -} - -func MergeSDLs(SDLs ...string) (string, error) { - rawDocs := make([]string, 0, len(SDLs)+1) - rawDocs = append(rawDocs, rootOperationTypeDefinitions) - rawDocs = append(rawDocs, SDLs...) - if validationError := validateSubgraphs(rawDocs[1:]); validationError != nil { - return "", validationError - } - if normalizationError := normalizeSubgraphs(rawDocs[1:]); normalizationError != nil { - return "", normalizationError - } - - doc, report := astparser.ParseGraphqlDocumentString(strings.Join(rawDocs, "\n")) - if report.HasErrors() { - return "", fmt.Errorf("parse graphql document string: %w", report) - } - - astnormalization.NormalizeSubgraphSDL(&doc, &report) - if report.HasErrors() { - return "", fmt.Errorf("merge ast: %w", report) - } - - if err := MergeAST(&doc); err != nil { - return "", fmt.Errorf("merge ast: %w", err) - } - - out, err := astprinter.PrintString(&doc, nil) - if err != nil { - return "", fmt.Errorf("stringify schema: %w", err) - } - - return out, nil -} - -func validateSubgraphs(subgraphs []string) error { - validator := astvalidation.NewDefinitionValidator( - astvalidation.PopulatedTypeBodies(), astvalidation.KnownTypeNames(), - ) - for _, subgraph := range subgraphs { - doc, report := astparser.ParseGraphqlDocumentString(subgraph) - if err := asttransform.MergeDefinitionWithBaseSchema(&doc); err != nil { - return err - } - if report.HasErrors() { - return fmt.Errorf(parseDocumentError, report) - } - validator.Validate(&doc, &report) - if report.HasErrors() { - return fmt.Errorf("validate schema: %w", report) - } - } - return nil -} - -func normalizeSubgraphs(subgraphs []string) error { - subgraphNormalizer := astnormalization.NewSubgraphDefinitionNormalizer() - for i, subgraph := range subgraphs { - doc, report := astparser.ParseGraphqlDocumentString(subgraph) - if report.HasErrors() { - return fmt.Errorf(parseDocumentError, report) - } - subgraphNormalizer.NormalizeDefinition(&doc, &report) - if report.HasErrors() { - return fmt.Errorf("normalize schema: %w", report) - } - out, err := astprinter.PrintString(&doc, nil) - if err != nil { - return fmt.Errorf("stringify schema: %w", err) - } - subgraphs[i] = out - } - return nil -} - -type normalizer struct { - walkers []*astvisitor.Walker -} - -type entitySet map[string]struct{} - -func (m *normalizer) setupWalkers() { - collectedEntities := make(entitySet) - visitorGroups := [][]Visitor{ - { - newCollectEntitiesVisitor(collectedEntities), - }, - { - newExtendEnumTypeDefinition(), - newExtendInputObjectTypeDefinition(), - newExtendInterfaceTypeDefinition(collectedEntities), - newExtendScalarTypeDefinition(), - newExtendUnionTypeDefinition(), - newExtendObjectTypeDefinition(collectedEntities), - newRemoveEmptyObjectTypeDefinition(), - newRemoveMergedTypeExtensions(), - }, - // visitors for cleaning up federated duplicated fields and directives - { - newRemoveFieldDefinitions("external"), - newRemoveDuplicateFieldedSharedTypesVisitor(), - newRemoveDuplicateFieldlessSharedTypesVisitor(), - newMergeDuplicatedFieldsVisitor(), - newRemoveInterfaceDefinitionDirective("key"), - newRemoveObjectTypeDefinitionDirective("key"), - newRemoveFieldDefinitionDirective("provides", "requires"), - }, - } - - for _, visitorGroup := range visitorGroups { - walker := astvisitor.NewWalker(48) - for _, visitor := range visitorGroup { - visitor.Register(&walker) - m.walkers = append(m.walkers, &walker) - } - } -} - -func (m *normalizer) normalize(operation *ast.Document) error { - report := operationreport.Report{} - - for _, walker := range m.walkers { - walker.Walk(operation, nil, &report) - if report.HasErrors() { - return fmt.Errorf("walk: %w", report) - } - } - - return nil -} - -func (e entitySet) isExtensionForEntity(nameBytes []byte, directiveRefs []int, document *ast.Document) (bool, *operationreport.ExternalError) { - name := string(nameBytes) - hasDirectives := len(directiveRefs) > 0 - if _, exists := e[name]; !exists { - if !hasDirectives || !isEntityExtension(directiveRefs, document) { - return false, nil - } - err := operationreport.ErrExtensionWithKeyDirectiveMustExtendEntity(name) - return false, &err - } - if !hasDirectives { - err := operationreport.ErrEntityExtensionMustHaveKeyDirective(name) - return false, &err - } - if isEntityExtension(directiveRefs, document) { - return true, nil - } - err := operationreport.ErrEntityExtensionMustHaveKeyDirective(name) - return false, &err -} - -func isEntityExtension(directiveRefs []int, document *ast.Document) bool { - for _, directiveRef := range directiveRefs { - if document.DirectiveNameString(directiveRef) == plan.FederationKeyDirectiveName { - return true - } - } - return false -} - -func multipleExtensionError(isEntity bool, nameBytes []byte) *operationreport.ExternalError { - if isEntity { - err := operationreport.ErrEntitiesMustNotBeDuplicated(string(nameBytes)) - return &err - } - err := operationreport.ErrSharedTypesMustNotBeExtended(string(nameBytes)) - return &err -} diff --git a/pkg/federation/sdlmerge/sdlmerge_test.go b/pkg/federation/sdlmerge/sdlmerge_test.go deleted file mode 100644 index 39530f697..000000000 --- a/pkg/federation/sdlmerge/sdlmerge_test.go +++ /dev/null @@ -1,838 +0,0 @@ -package sdlmerge - -import ( - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -var testEntitySet = entitySet{"Mammal": {}} - -func newTestNormalizer(withEntity bool) entitySet { - if withEntity { - return testEntitySet - } - return make(entitySet) -} - -type composeVisitor []Visitor - -func (c composeVisitor) Register(walker *astvisitor.Walker) { - for _, visitor := range c { - visitor.Register(walker) - } -} - -var run = func(t *testing.T, visitor Visitor, operation, expectedOutput string) { - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedOutput) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - visitor.Register(&walker) - - walker.Walk(&operationDocument, nil, &report) - - if report.HasErrors() { - t.Fatal(report.Error()) - } - - got := mustString(astprinter.PrintStringIndent(&operationDocument, nil, " ")) - want := mustString(astprinter.PrintStringIndent(&expectedOutputDocument, nil, " ")) - - assert.Equal(t, want, got) -} - -var runAndExpectError = func(t *testing.T, visitor Visitor, operation, expectedError string) { - operationDocument := unsafeparser.ParseGraphqlDocumentString(operation) - report := operationreport.Report{} - walker := astvisitor.NewWalker(48) - - visitor.Register(&walker) - - walker.Walk(&operationDocument, nil, &report) - - var got string - if report.HasErrors() { - if report.InternalErrors == nil { - got = report.ExternalErrors[0].Message - } else { - got = report.InternalErrors[0].Error() - } - } - - assert.Equal(t, expectedError, got) -} - -func runMany(t *testing.T, operation, expectedOutput string, visitors ...Visitor) { - run(t, composeVisitor(visitors), operation, expectedOutput) -} - -func mustString(str string, err error) string { - if err != nil { - panic(err) - } - return str -} - -func TestMergeSDLs(t *testing.T) { - runMergeTest := func(expectedSchema string, sdls ...string) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - got, err := MergeSDLs(sdls...) - if err != nil { - t.Fatal(err) - } - - expectedOutputDocument := unsafeparser.ParseGraphqlDocumentString(expectedSchema) - want := mustString(astprinter.PrintString(&expectedOutputDocument, nil)) - - assert.Equal(t, want, got) - } - } - - runMergeTestAndExpectError := func(expectedError string, sdls ...string) func(t *testing.T) { - return func(t *testing.T) { - _, err := MergeSDLs(sdls...) - actual, _ := operationreport.ExternalErrorMessage(err, testFormatExternalErrorMessage) - assert.Equal(t, expectedError, actual) - } - } - - t.Run("should merge all sdls successfully", runMergeTest( - federatedSchema, - accountSchema, productSchema, reviewSchema, likeSchema, disLikeSchema, paymentSchema, onlinePaymentSchema, classicPaymentSchema, - )) - - t.Run("When merging product and review, the unresolved orphan extension for User will return an error", runMergeTestAndExpectError( - unresolvedExtensionOrphansErrorMessage("User"), - productSchema, reviewSchema, - )) - - t.Run("When merging product and extendsDirectives, the unresolved orphan extension for User will return an error", runMergeTestAndExpectError( - unresolvedExtensionOrphansErrorMessage("User"), - productSchema, extendsDirectivesSchema, - )) - - t.Run("Non-identical duplicate enums should return an error", runMergeTestAndExpectError( - nonIdenticalSharedTypeErrorMessage("Satisfaction"), - productSchema, negativeTestingLikeSchema, - )) - - t.Run("Non-identical duplicate unions should return an error", runMergeTestAndExpectError( - nonIdenticalSharedTypeErrorMessage("AlphaNumeric"), - accountSchema, negativeTestingReviewSchema, - )) - - t.Run("Entity duplicates should return an error", runMergeTestAndExpectError( - duplicateEntityErrorMessage("User"), - accountSchema, negativeTestingAccountSchema, - )) - - t.Run("The first type encountered without a body should return an error", runMergeTestAndExpectError( - emptyTypeBodyErrorMessage("object", "Message"), - accountSchema, negativeTestingProductSchema, - )) - - t.Run("Fields should merge successfully", runMergeTest( - ` - type Mammal { - name: String! - age: Int! - } - `, - ` - type Mammal @key(fields: "name") { - name: String! - age: Int! - } - `, ` - extend type Mammal @key(fields: "name") { - name: String! @external - age: Int! - } - `, - )) - - t.Run("Operation fields should merge successfully", runMergeTest( - ` - type Query { - _service: _Service! - } - - type _Service { - sdl: String - } - `, - ` - type Query { - _service: _Service! - } - - type _Service { - sdl: String - } - `, ` - type Query { - _service: _Service! - } - - type _Service { - sdl: String - } - `, - )) - - t.Run("Non-identical fields should fail to merge #1", runMergeTestAndExpectError( - unmergableDuplicateFieldsErrorMessage("age", "Mammal", "Int", "String"), - ` - type Mammal @key(fields: "name") { - name: String! - age: Int - } - `, ` - extend type Mammal @key(fields: "name") { - name: String! @external - age: String - } - `, - )) - - t.Run("Non-identical fields should fail to merge #2", runMergeTestAndExpectError( - unmergableDuplicateFieldsErrorMessage("age", "Mammal", "Int!", "String!"), - ` - type Mammal @key(fields: "name") { - name: String! - age: Int! - } - `, ` - extend type Mammal @key(fields: "name") { - name: String! @external - age: String! - } - `, - )) - - t.Run("Non-dentical fields should fail to merge #3", runMergeTestAndExpectError( - unmergableDuplicateFieldsErrorMessage("ages", "Mammal", "[Int!]!", "[String!]!"), - ` - type Mammal @key(fields: "name") { - name: String! - ages: [Int!]! - } - `, ` - extend type Mammal @key(fields: "name") { - name: String! @external - ages: [String!]! - } - `, - )) -} - -const ( - accountSchema = ` - extend type Query { - me: User - } - - union AlphaNumeric = Int | String | Float - - scalar DateTime - - scalar CustomScalar - - type User @key(fields: "id") { - id: ID! - username: String! - created: DateTime! - reputation: CustomScalar! - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - ` - - negativeTestingAccountSchema = ` - extend type Query { - me: User - } - - union AlphaNumeric = Int | String | Float - - scalar DateTime - - scalar CustomScalar - - type User { - id: ID! - username: String! - created: DateTime! - reputation: CustomScalar! - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - ` - - productSchema = ` - enum Satisfaction { - UNHAPPY, - HAPPY, - NEUTRAL, - } - - scalar CustomScalar - - extend type Query { - topProducts(first: Int = 5): [Product] - } - - enum Department { - COSMETICS, - ELECTRONICS, - GROCERIES, - } - - interface ProductInfo { - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - - scalar BigInt - - type Product implements ProductInfo @key(fields: "upc") { - upc: String! - name: String! - price: Int! - worth: BigInt! - reputation: CustomScalar! - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - - union AlphaNumeric = Int | String | Float - ` - - negativeTestingProductSchema = ` - enum Satisfaction { - UNHAPPY, - HAPPY, - NEUTRAL, - } - - scalar CustomScalar - - extend type Query { - topProducts(first: Int = 5): [Product] - } - - enum Department { - COSMETICS, - ELECTRONICS, - GROCERIES, - } - - interface ProductInfo { - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - - type Message { - } - - scalar BigInt - - type Product implements ProductInfo @key(fields: "upc") { - upc: String! - name: String! - price: Int! - worth: BigInt! - reputation: CustomScalar! - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - - extend type Message { - content: String! - } - - union AlphaNumeric = Int | String | Float - ` - reviewSchema = ` - scalar DateTime - union AlphaNumeric = Int | String | Float - - input ReviewInput { - body: String! - author: User! @provides(fields: "username") - product: Product! - updated: DateTime! - inputType: AlphaNumeric! - } - - type Review { - id: ID! - created: DateTime! - body: String! - author: User! @provides(fields: "username") - product: Product! - updated: DateTime! - inputType: AlphaNumeric! - } - - type Query { - getReview(id: ID!): Review - } - - type Mutation { - createReview(input: ReviewInput): Review - updateReview(id: ID!, input: ReviewInput): Review - } - - enum Department { - GROCERIES, - COSMETICS, - ELECTRONICS, - } - - extend type User @key(fields: "id") { - id: ID! @external - reviews: [Review] - } - - scalar BigInt - - extend type Product implements ProductInfo @key(fields: "upc") { - upc: String! @external - name: String! @external - reviews: [Review] @requires(fields: "name") - sales: BigInt! - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - - extend type Subscription { - review: Review! - } - - interface ProductInfo { - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - ` - - negativeTestingReviewSchema = ` - scalar DateTime - - input ReviewInput { - body: String! - author: User! @provides(fields: "username") - product: Product! - updated: DateTime! - inputType: AlphaNumeric! - } - - type Review { - id: ID! - created: DateTime! - body: String! - author: User! @provides(fields: "username") - product: Product! - updated: DateTime! - inputType: AlphaNumeric! - } - - type Query { - getReview(id: ID!): Review - } - - type Mutation { - createReview(input: ReviewInput): Review - updateReview(id: ID!, input: ReviewInput): Review - } - - interface ProductInfo { - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - - enum Department { - COSMETICS, - ELECTRONICS, - GROCERIES, - } - - extend type User @key(fields: "id") { - id: ID! @external - reviews: [Review] - } - - type Product implements ProductInfo @key(fields: "upc") { - upc: String! - name: String! - reviews: [Review] @requires(fields: "name") - sales: BigInt! - } - - scalar BigInt - - union AlphaNumeric = BigInt | String - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - - extend type Subscription { - review: Review! - } - ` - - likeSchema = ` - scalar DateTime - - type Like @key(fields: "id") { - id: ID! - productId: ID! - userId: ID! - date: DateTime! - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - - type Query { - likesCount(productID: ID!): Int! - likes(productID: ID!): [Like]! - } - ` - negativeTestingLikeSchema = ` - scalar DateTime - - type Like @key(fields: "id") { - id: ID! - productId: ID! - userId: ID! - date: DateTime! - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - DEVASTATED, - } - - type Query { - likesCount(productID: ID!): Int! - likes(productID: ID!): [Like]! - } - ` - - disLikeSchema = ` - type Like @key(fields: "id") @extends { - id: ID! @external - isDislike: Boolean! - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - - ` - paymentSchema = ` - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - - interface PaymentType { - name: String! - } - ` - onlinePaymentSchema = ` - extend enum Satisfaction { - UNHAPPY - } - - scalar DateTime - - union AlphaNumeric = Int | String - - scalar BigInt - - interface PaymentType @extends { - email: String! - date: DateTime! - amount: BigInt! - } - - extend union AlphaNumeric = Float - - enum Satisfaction { - HAPPY - NEUTRAL - } - ` - classicPaymentSchema = ` - union AlphaNumeric = Int | String | Float - - scalar CustomScalar - - extend interface PaymentType { - number: String! - reputation: CustomScalar! - } - ` - extendsDirectivesSchema = ` - scalar DateTime - - type Comment { - body: String! - author: User! - created: DateTime! - } - - type User @extends @key(fields: "id") { - id: ID! @external - comments: [Comment] - } - - union AlphaNumeric = Int | String | Float - - interface PaymentType @extends { - name: String! - } - ` - federatedSchema = ` - type Query { - me: User - topProducts(first: Int = 5): [Product] - getReview(id: ID!): Review - likesCount(productID: ID!): Int! - likes(productID: ID!): [Like]! - } - - type Mutation { - createReview(input: ReviewInput): Review - updateReview(id: ID!, input: ReviewInput): Review - } - - type Subscription { - review: Review! - } - - union AlphaNumeric = Int | String | Float - - scalar DateTime - - scalar CustomScalar - - type User { - id: ID! - username: String! - created: DateTime! - reputation: CustomScalar! - reviews: [Review] - } - - enum Satisfaction { - HAPPY, - NEUTRAL, - UNHAPPY, - } - - enum Department { - COSMETICS, - ELECTRONICS, - GROCERIES, - } - - interface ProductInfo { - departments: [Department!]! - averageSatisfaction: Satisfaction! - } - - scalar BigInt - - type Product implements ProductInfo { - upc: String! - name: String! - price: Int! - worth: BigInt! - reputation: CustomScalar! - departments: [Department!]! - averageSatisfaction: Satisfaction! - reviews: [Review] - sales: BigInt! - } - - input ReviewInput { - body: String! - author: User! @provides(fields: "username") - product: Product! - updated: DateTime! - inputType: AlphaNumeric! - } - - type Review { - id: ID! - created: DateTime! - body: String! - author: User! - product: Product! - updated: DateTime! - inputType: AlphaNumeric! - } - - type Like { - id: ID! - productId: ID! - userId: ID! - date: DateTime! - isDislike: Boolean! - } - - interface PaymentType { - name: String! - email: String! - date: DateTime! - amount: BigInt! - number: String! - reputation: CustomScalar! - } - ` -) - -var testFormatExternalErrorMessage = func(report *operationreport.Report) string { - if len(report.ExternalErrors) > 0 { - return report.ExternalErrors[0].Message - } - return "" -} - -func nonIdenticalSharedTypeErrorMessage(typeName string) string { - return fmt.Sprintf("the shared type named '%s' must be identical in any subgraphs to federate", typeName) -} - -func sharedTypeExtensionErrorMessage(typeName string) string { - return fmt.Sprintf("the type named '%s' cannot be extended because it is a shared type", typeName) -} - -func emptyTypeBodyErrorMessage(definitionType, typeName string) string { - return fmt.Sprintf("the %s named '%s' is invalid due to an empty body", definitionType, typeName) -} - -func unresolvedExtensionOrphansErrorMessage(typeName string) string { - return fmt.Sprintf("the extension orphan named '%s' was never resolved in the supergraph", typeName) -} - -func noKeyDirectiveErrorMessage(typeName string) string { - return fmt.Sprintf("an extension of the entity named '%s' does not have a key directive", typeName) -} - -func nonEntityExtensionErrorMessage(typeName string) string { - return fmt.Sprintf("the extension named '%s' has a key directive but there is no entity of the same name", typeName) -} - -func duplicateEntityErrorMessage(typeName string) string { - return fmt.Sprintf("the entity named '%s' is defined in the subgraph(s) more than once", typeName) -} - -func unmergableDuplicateFieldsErrorMessage(fieldName, parentName, typeOne, typeTwo string) string { - return fmt.Sprintf("field '%s' on type '%s' is defined in multiple subgraphs "+ - "but the fields cannot be merged because the types of the fields are non-identical:\n"+ - "first subgraph: type '%s'\n second subgraph: type '%s'", fieldName, parentName, typeOne, typeTwo) -} - -func Test_validateSubgraphs(t *testing.T) { - basePath := filepath.Join(".", "testdata", "validate-subgraph") - - testcase := []struct { - name string - schemaFileName string - wantErr bool - errMsg string - }{ - { - name: "well-defined subgraph schema", - schemaFileName: "well-defined.graphqls", - wantErr: false, - }, - { - name: "well-defined subgraph schema (non-null field type)", - schemaFileName: "well-defined-non-null.graphqls", - wantErr: false, - }, - { - name: "a subgraph lacking the definition of 'User' type", - schemaFileName: "lack-definition.graphqls", - wantErr: true, - errMsg: `external: Unknown type "User"`, - }, - { - name: "a subgraph lacking the extend definition of 'Product' type", - schemaFileName: "lack-extend-definition.graphqls", - wantErr: true, - errMsg: `external: Unknown type "Product"`, - }, - { - name: "a subgraph lacking the definition of 'User' type (field type non-null)", - schemaFileName: "lack-definition-non-null.graphqls", - wantErr: true, - errMsg: `external: Unknown type "User"`, - }, - { - name: "a subgraph lacking the extend definition of 'Product' type (field type non-null)", - schemaFileName: "lack-extend-definition-non-null.graphqls", - wantErr: true, - errMsg: `external: Unknown type "Product"`, - }, - } - for _, tt := range testcase { - t.Run(tt.name, func(t *testing.T) { - caseSchemaPath := filepath.Join(basePath, tt.schemaFileName) - - b, err := os.ReadFile(caseSchemaPath) - require.NoError(t, err) - - subgraph := string(b) - err = validateSubgraphs([]string{subgraph}) - - if tt.wantErr { - assert.Error(t, err, subgraph) - assert.Contains(t, err.Error(), tt.errMsg) - return - } - - assert.NoError(t, err, subgraph) - }) - } -} diff --git a/pkg/federation/sdlmerge/shared_types.go b/pkg/federation/sdlmerge/shared_types.go deleted file mode 100644 index 83cde0390..000000000 --- a/pkg/federation/sdlmerge/shared_types.go +++ /dev/null @@ -1,168 +0,0 @@ -package sdlmerge - -import "github.com/wundergraph/graphql-go-tools/pkg/ast" - -type fieldlessSharedType interface { - areValuesIdentical(valueRefsToCompare []int) bool - valueRefs() []int - valueName(ref int) string -} - -func createValueSet(f fieldlessSharedType) map[string]bool { - valueSet := make(map[string]bool) - for _, valueRef := range f.valueRefs() { - valueSet[f.valueName(valueRef)] = true - } - return valueSet -} - -type fieldedSharedType struct { - document *ast.Document - fieldKind ast.NodeKind - fieldRefs []int - fieldSet map[string]int -} - -func newFieldedSharedType(document *ast.Document, fieldKind ast.NodeKind, fieldRefs []int) fieldedSharedType { - f := fieldedSharedType{ - document, - fieldKind, - fieldRefs, - nil, - } - f.createFieldSet() - return f -} - -func (f fieldedSharedType) areFieldsIdentical(fieldRefsToCompare []int) bool { - if len(f.fieldRefs) != len(fieldRefsToCompare) { - return false - } - for _, fieldRef := range fieldRefsToCompare { - actualFieldName := f.fieldName(fieldRef) - expectedTypeRef, exists := f.fieldSet[actualFieldName] - if !exists { - return false - } - actualTypeRef := f.fieldTypeRef(fieldRef) - if !f.document.TypesAreCompatibleDeep(expectedTypeRef, actualTypeRef) { - return false - } - } - return true -} - -func (f *fieldedSharedType) createFieldSet() { - fieldSet := make(map[string]int) - for _, fieldRef := range f.fieldRefs { - fieldSet[f.fieldName(fieldRef)] = f.fieldTypeRef(fieldRef) - } - f.fieldSet = fieldSet -} - -func (f fieldedSharedType) fieldName(ref int) string { - switch f.fieldKind { - case ast.NodeKindInputValueDefinition: - return f.document.InputValueDefinitionNameString(ref) - default: - return f.document.FieldDefinitionNameString(ref) - } -} - -func (f fieldedSharedType) fieldTypeRef(ref int) int { - switch f.fieldKind { - case ast.NodeKindInputValueDefinition: - return f.document.InputValueDefinitions[ref].Type - default: - return f.document.FieldDefinitions[ref].Type - } -} - -type enumSharedType struct { - *ast.EnumTypeDefinition - document *ast.Document - valueSet map[string]bool -} - -func newEnumSharedType(document *ast.Document, ref int) enumSharedType { - e := enumSharedType{ - &document.EnumTypeDefinitions[ref], - document, - nil, - } - e.valueSet = createValueSet(e) - return e -} - -func (e enumSharedType) areValuesIdentical(valueRefsToCompare []int) bool { - if len(e.valueRefs()) != len(valueRefsToCompare) { - return false - } - for _, valueRefToCompare := range valueRefsToCompare { - name := e.valueName(valueRefToCompare) - if !e.valueSet[name] { - return false - } - } - return true -} - -func (e enumSharedType) valueRefs() []int { - return e.EnumValuesDefinition.Refs -} - -func (e enumSharedType) valueName(ref int) string { - return e.document.EnumValueDefinitionNameString(ref) -} - -type unionSharedType struct { - *ast.UnionTypeDefinition - document *ast.Document - valueSet map[string]bool -} - -func newUnionSharedType(document *ast.Document, ref int) unionSharedType { - u := unionSharedType{ - &document.UnionTypeDefinitions[ref], - document, - nil, - } - u.valueSet = createValueSet(u) - return u -} - -func (u unionSharedType) areValuesIdentical(valueRefsToCompare []int) bool { - if len(u.valueRefs()) != len(valueRefsToCompare) { - return false - } - for _, refToCompare := range valueRefsToCompare { - name := u.valueName(refToCompare) - if !u.valueSet[name] { - return false - } - } - return true -} - -func (u unionSharedType) valueRefs() []int { - return u.UnionMemberTypes.Refs -} - -func (u unionSharedType) valueName(ref int) string { - return u.document.TypeNameString(ref) -} - -type scalarSharedType struct { -} - -func (_ scalarSharedType) areValuesIdentical(_ []int) bool { - return true -} - -func (_ scalarSharedType) valueRefs() []int { - return nil -} - -func (_ scalarSharedType) valueName(_ int) string { - return "" -} diff --git a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition-non-null.graphqls b/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition-non-null.graphqls deleted file mode 100644 index 639b44d35..000000000 --- a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition-non-null.graphqls +++ /dev/null @@ -1,16 +0,0 @@ -type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! -} - -#type User @key(fields: "id") { -# id: ID! @external -# username: String! @external -# reviews: [Review] -#} - -extend type Product @key(fields: "upc") { - upc: String! @external - reviews: [Review] -} diff --git a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition.graphqls b/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition.graphqls deleted file mode 100644 index 976558c5a..000000000 --- a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-definition.graphqls +++ /dev/null @@ -1,16 +0,0 @@ -type Review { - body: String! - author: User @provides(fields: "username") - product: Product -} - -#type User @key(fields: "id") { -# id: ID! @external -# username: String! @external -# reviews: [Review] -#} - -extend type Product @key(fields: "upc") { - upc: String! @external - reviews: [Review] -} diff --git a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition-non-null.graphqls b/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition-non-null.graphqls deleted file mode 100644 index ff57c4ca5..000000000 --- a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition-non-null.graphqls +++ /dev/null @@ -1,16 +0,0 @@ -type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! -} - -type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] -} - -#extend type Product @key(fields: "upc") { -# @external -# reviews: [Review] } -#} diff --git a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition.graphqls b/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition.graphqls deleted file mode 100644 index 99c5b03a7..000000000 --- a/pkg/federation/sdlmerge/testdata/validate-subgraph/lack-extend-definition.graphqls +++ /dev/null @@ -1,17 +0,0 @@ -type Review { - body: String! - author: User @provides(fields: "username") - product: Product -} - -type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] -} - -#extend type Product @key(fields: "upc") { -# upc: String! @external -# reviews: [Review] -#} - diff --git a/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined-non-null.graphqls b/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined-non-null.graphqls deleted file mode 100644 index 5c303e8fe..000000000 --- a/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined-non-null.graphqls +++ /dev/null @@ -1,16 +0,0 @@ -type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! -} - -type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] -} - -extend type Product @key(fields: "upc") { - upc: String! @external - reviews: [Review] -} diff --git a/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined.graphqls b/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined.graphqls deleted file mode 100644 index 788dbc0c1..000000000 --- a/pkg/federation/sdlmerge/testdata/validate-subgraph/well-defined.graphqls +++ /dev/null @@ -1,16 +0,0 @@ -type Review { - body: String! - author: User @provides(fields: "username") - product: Product -} - -type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] -} - -extend type Product @key(fields: "upc") { - upc: String! @external - reviews: [Review] -} diff --git a/pkg/federation/sdlmerge/union_type_extending.go b/pkg/federation/sdlmerge/union_type_extending.go deleted file mode 100644 index 49624daaf..000000000 --- a/pkg/federation/sdlmerge/union_type_extending.go +++ /dev/null @@ -1,50 +0,0 @@ -package sdlmerge - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func newExtendUnionTypeDefinition() *extendUnionTypeDefinitionVisitor { - return &extendUnionTypeDefinitionVisitor{} -} - -type extendUnionTypeDefinitionVisitor struct { - *astvisitor.Walker - document *ast.Document -} - -func (e *extendUnionTypeDefinitionVisitor) Register(walker *astvisitor.Walker) { - e.Walker = walker - walker.RegisterEnterDocumentVisitor(e) - walker.RegisterEnterUnionTypeExtensionVisitor(e) -} - -func (e *extendUnionTypeDefinitionVisitor) EnterDocument(operation, _ *ast.Document) { - e.document = operation -} - -func (e *extendUnionTypeDefinitionVisitor) EnterUnionTypeExtension(ref int) { - nodes, exists := e.document.Index.NodesByNameBytes(e.document.UnionTypeExtensionNameBytes(ref)) - if !exists { - return - } - - hasExtended := false - for i := range nodes { - if nodes[i].Kind != ast.NodeKindUnionTypeDefinition { - continue - } - if hasExtended { - e.StopWithExternalErr(operationreport.ErrSharedTypesMustNotBeExtended(e.document.UnionTypeExtensionNameString(ref))) - return - } - e.document.ExtendUnionTypeDefinitionByUnionTypeExtension(nodes[i].Ref, ref) - hasExtended = true - } - - if !hasExtended { - e.StopWithExternalErr(operationreport.ErrExtensionOrphansMustResolveInSupergraph(e.document.UnionTypeExtensionNameBytes(ref))) - } -} diff --git a/pkg/federation/sdlmerge/union_type_extending_test.go b/pkg/federation/sdlmerge/union_type_extending_test.go deleted file mode 100644 index 9db731293..000000000 --- a/pkg/federation/sdlmerge/union_type_extending_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package sdlmerge - -import ( - "testing" -) - -func TestExtendUnionType(t *testing.T) { - t.Run("extend union types", func(t *testing.T) { - run(t, newExtendUnionTypeDefinition(), ` - type Dog { - name: String - } - - union Animal = Dog - - type Cat { - name: String - } - - type Bird { - name: String - } - - extend union Animal = Bird | Cat - `, ` - type Dog { - name: String - } - - union Animal = Dog | Bird | Cat - - type Cat { - name: String - } - - type Bird { - name: String - } - - extend union Animal = Bird | Cat - `) - }) - - t.Run("Extending a union that is a shared type returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendUnionTypeDefinition(), ` - type Dog { - name: String - } - - union Animal = Dog - - type Cat { - name: String - } - - type Bird { - name: String - } - - union Animal = Dog - - extend union Animal = Bird | Cat - `, sharedTypeExtensionErrorMessage("Animal")) - }) - - t.Run("Unresolved union extension orphan returns an error", func(t *testing.T) { - runAndExpectError(t, newExtendUnionTypeDefinition(), ` - extend union Badges = Boulder - `, unresolvedExtensionOrphansErrorMessage("Badges")) - }) -} diff --git a/pkg/graphql/complexity.go b/pkg/graphql/complexity.go deleted file mode 100644 index 7b2e275ee..000000000 --- a/pkg/graphql/complexity.go +++ /dev/null @@ -1,75 +0,0 @@ -package graphql - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/middleware/operation_complexity" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -var DefaultComplexityCalculator = defaultComplexityCalculator{} - -type ComplexityCalculator interface { - Calculate(operation, definition *ast.Document) (ComplexityResult, error) -} - -type defaultComplexityCalculator struct { -} - -func (d defaultComplexityCalculator) Calculate(operation, definition *ast.Document) (ComplexityResult, error) { - report := operationreport.Report{} - globalComplexityResult, fieldsComplexityResult := operation_complexity.CalculateOperationComplexity(operation, definition, &report) - - return complexityResult(globalComplexityResult, fieldsComplexityResult, report) -} - -type ComplexityResult struct { - NodeCount int - Complexity int - Depth int - PerRootField []FieldComplexityResult - Errors Errors -} - -type FieldComplexityResult struct { - TypeName string - FieldName string - Alias string - NodeCount int - Complexity int - Depth int -} - -func complexityResult(globalComplexityResult operation_complexity.OperationStats, fieldsComplexityResult []operation_complexity.RootFieldStats, report operationreport.Report) (ComplexityResult, error) { - allFieldComplexityResults := make([]FieldComplexityResult, 0, len(fieldsComplexityResult)) - for _, fieldResult := range fieldsComplexityResult { - allFieldComplexityResults = append(allFieldComplexityResults, FieldComplexityResult{ - TypeName: fieldResult.TypeName, - FieldName: fieldResult.FieldName, - Alias: fieldResult.Alias, - NodeCount: fieldResult.Stats.NodeCount, - Complexity: fieldResult.Stats.Complexity, - Depth: fieldResult.Stats.Depth, - }) - } - - result := ComplexityResult{ - NodeCount: globalComplexityResult.NodeCount, - Complexity: globalComplexityResult.Complexity, - Depth: globalComplexityResult.Depth, - PerRootField: allFieldComplexityResults, - Errors: nil, - } - - if !report.HasErrors() { - return result, nil - } - - result.Errors = RequestErrorsFromOperationReport(report) - - var err error - if len(report.InternalErrors) > 0 { - err = report.InternalErrors[0] - } - - return result, err -} diff --git a/pkg/graphql/config_factory_federation.go b/pkg/graphql/config_factory_federation.go deleted file mode 100644 index 25023b4ff..000000000 --- a/pkg/graphql/config_factory_federation.go +++ /dev/null @@ -1,203 +0,0 @@ -package graphql - -import ( - "fmt" - "net/http" - "time" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/federation" -) - -type federationEngineConfigFactoryOptions struct { - httpClient *http.Client - streamingClient *http.Client - subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory - subscriptionType SubscriptionType - customResolveMap map[string]resolve.CustomResolve - engineOptions []EngineV2ConfigurationOption -} - -type FederationEngineConfigFactoryOption func(options *federationEngineConfigFactoryOptions) - -func WithCustomResolveMap(customResolveMap map[string]resolve.CustomResolve) FederationEngineConfigFactoryOption { - return func(options *federationEngineConfigFactoryOptions) { - options.customResolveMap = customResolveMap - } -} - -func WithFederationHttpClient(client *http.Client) FederationEngineConfigFactoryOption { - return func(options *federationEngineConfigFactoryOptions) { - options.httpClient = client - } -} - -func WithFederationStreamingClient(client *http.Client) FederationEngineConfigFactoryOption { - return func(options *federationEngineConfigFactoryOptions) { - options.streamingClient = client - } -} - -func WithFederationSubscriptionClientFactory(factory graphqlDataSource.GraphQLSubscriptionClientFactory) FederationEngineConfigFactoryOption { - return func(options *federationEngineConfigFactoryOptions) { - options.subscriptionClientFactory = factory - } -} - -func WithFederationSubscriptionType(subscriptionType SubscriptionType) FederationEngineConfigFactoryOption { - return func(options *federationEngineConfigFactoryOptions) { - options.subscriptionType = subscriptionType - } -} - -func WithEngineOptions(engineOptions ...EngineV2ConfigurationOption) FederationEngineConfigFactoryOption { - return func(options *federationEngineConfigFactoryOptions) { - options.engineOptions = engineOptions - } -} - -func NewFederationEngineConfigFactory(dataSourceConfigs []graphqlDataSource.Configuration, batchFactory resolve.DataSourceBatchFactory, opts ...FederationEngineConfigFactoryOption) *FederationEngineConfigFactory { - options := federationEngineConfigFactoryOptions{ - httpClient: &http.Client{ - Timeout: time.Second * 10, - Transport: &http.Transport{ - MaxIdleConnsPerHost: 1024, - TLSHandshakeTimeout: 0 * time.Second, - }, - }, - streamingClient: &http.Client{ - Timeout: 0, - }, - subscriptionClientFactory: &graphqlDataSource.DefaultSubscriptionClientFactory{}, - subscriptionType: SubscriptionTypeUnknown, - } - - for _, optFunc := range opts { - optFunc(&options) - } - - return &FederationEngineConfigFactory{ - httpClient: options.httpClient, - streamingClient: options.streamingClient, - dataSourceConfigs: dataSourceConfigs, - batchFactory: batchFactory, - subscriptionClientFactory: options.subscriptionClientFactory, - subscriptionType: options.subscriptionType, - customResolveMap: options.customResolveMap, - engineOptions: options.engineOptions, - } -} - -// FederationEngineConfigFactory is used to create a v2 engine config for a supergraph with multiple data sources for subgraphs. -type FederationEngineConfigFactory struct { - httpClient *http.Client - streamingClient *http.Client - dataSourceConfigs []graphqlDataSource.Configuration - schema *Schema - batchFactory resolve.DataSourceBatchFactory - subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory - subscriptionType SubscriptionType - customResolveMap map[string]resolve.CustomResolve - engineOptions []EngineV2ConfigurationOption -} - -func (f *FederationEngineConfigFactory) SetMergedSchemaFromString(mergedSchema string) (err error) { - f.schema, err = NewSchemaFromString(mergedSchema) - if err != nil { - return fmt.Errorf("set merged schema in FederationEngineConfigFactory: %s", err.Error()) - } - return nil -} - -func (f *FederationEngineConfigFactory) MergedSchema() (*Schema, error) { - if f.schema != nil { - return f.schema, nil - } - - SDLs := make([]string, len(f.dataSourceConfigs)) - for i := range f.dataSourceConfigs { - SDLs[i] = f.dataSourceConfigs[i].Federation.ServiceSDL - } - - rawBaseSchema, err := federation.BuildBaseSchemaDocument(SDLs...) - if err != nil { - return nil, fmt.Errorf("build base schema: %w", err) - } - - if f.schema, err = NewSchemaFromString(rawBaseSchema); err != nil { - return nil, fmt.Errorf("parse schema from string: %v", err) - } - - return f.schema, nil -} - -func (f *FederationEngineConfigFactory) EngineV2Configuration() (conf EngineV2Configuration, err error) { - schema, err := f.MergedSchema() - if err != nil { - return conf, fmt.Errorf("get schema: %v", err) - } - - conf = NewEngineV2Configuration(schema, f.engineOptions...) - - fieldConfigs, err := f.engineConfigFieldConfigs(schema) - if err != nil { - return conf, fmt.Errorf("create field configs: %v", err) - } - - dataSources, err := f.engineConfigDataSources() - if err != nil { - return conf, fmt.Errorf("create datasource config: %v", err) - } - - conf.SetFieldConfigurations(fieldConfigs) - conf.SetDataSources(dataSources) - - if f.customResolveMap != nil { - conf.SetCustomResolveMap(f.customResolveMap) - } - - return conf, nil -} - -func (f *FederationEngineConfigFactory) engineConfigFieldConfigs(schema *Schema) (plan.FieldConfigurations, error) { - var planFieldConfigs plan.FieldConfigurations - - for _, dataSourceConfig := range f.dataSourceConfigs { - doc, report := astparser.ParseGraphqlDocumentString(dataSourceConfig.Federation.ServiceSDL) - if report.HasErrors() { - return nil, fmt.Errorf("parse graphql document string: %s", report.Error()) - } - extractor := plan.NewRequiredFieldExtractor(&doc) - planFieldConfigs = append(planFieldConfigs, extractor.GetAllRequiredFields()...) - } - - planFieldConfigs = newGraphQLFieldConfigsV2Generator(schema).Generate(planFieldConfigs...) - return planFieldConfigs, nil -} - -func (f *FederationEngineConfigFactory) engineConfigDataSources() (planDataSources []plan.DataSourceConfiguration, err error) { - for _, dataSourceConfig := range f.dataSourceConfigs { - doc, report := astparser.ParseGraphqlDocumentString(dataSourceConfig.Federation.ServiceSDL) - if report.HasErrors() { - return nil, fmt.Errorf("parse graphql document string: %s", report.Error()) - } - - planDataSource, err := newGraphQLDataSourceV2Generator(&doc).Generate( - dataSourceConfig, - f.batchFactory, - f.httpClient, - WithDataSourceV2GeneratorSubscriptionConfiguration(f.streamingClient, f.subscriptionType), - WithDataSourceV2GeneratorSubscriptionClientFactory(f.subscriptionClientFactory), - ) - if err != nil { - return nil, err - } - - planDataSources = append(planDataSources, planDataSource) - } - - return -} diff --git a/pkg/graphql/config_factory_federation_test.go b/pkg/graphql/config_factory_federation_test.go deleted file mode 100644 index 969f3cdfc..000000000 --- a/pkg/graphql/config_factory_federation_test.go +++ /dev/null @@ -1,298 +0,0 @@ -package graphql - -import ( - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -func TestEngineConfigV2Factory_EngineV2Configuration(t *testing.T) { - runWithoutError := func( - t *testing.T, - httpClient *http.Client, - streamingClient *http.Client, - batchFactory resolve.DataSourceBatchFactory, - dataSourceConfigs []graphqlDataSource.Configuration, - baseSchema string, - expectedConfigFactory func(t *testing.T, baseSchema string) EngineV2Configuration, - ) { - doc, report := astparser.ParseGraphqlDocumentString(baseSchema) - if report.HasErrors() { - require.Fail(t, report.Error()) - } - printedBaseSchema, err := astprinter.PrintString(&doc, nil) - require.NoError(t, err) - - engineConfigV2Factory := NewFederationEngineConfigFactory( - dataSourceConfigs, - batchFactory, - WithFederationHttpClient(httpClient), - WithFederationStreamingClient(streamingClient), - WithFederationSubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - config, err := engineConfigV2Factory.EngineV2Configuration() - assert.NoError(t, err) - assert.Equal(t, expectedConfigFactory(t, printedBaseSchema), config) - } - - httpClient := &http.Client{} - streamingClient := &http.Client{} - batchFactory := graphqlDataSource.NewBatchFactory() - - t.Run("should create engine V2 configuration", func(t *testing.T) { - runWithoutError(t, httpClient, streamingClient, batchFactory, []graphqlDataSource.Configuration{ - { - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://user.service", - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: accountSchema, - }, - }, - { - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://product.service", - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: productSchema, - }, - }, - { - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://review.service", - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: reviewSchema, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - UseSSE: true, - }, - }, - }, baseFederationSchema, func(t *testing.T, baseSchema string) EngineV2Configuration { - schema, err := NewSchemaFromString(baseSchema) - require.NoError(t, err) - - conf := NewEngineV2Configuration(schema) - conf.SetFieldConfigurations(plan.FieldConfigurations{ - { - TypeName: "User", - FieldName: "username", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Product", - FieldName: "name", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product", - FieldName: "price", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Product", - FieldName: "reviews", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Query", - FieldName: "topProducts", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "first", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }) - - conf.SetDataSources([]plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "username"}, - }, - }, - Custom: graphqlDataSource.ConfigJson(graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://user.service", - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: accountSchema, - }, - }), - Factory: &graphqlDataSource.Factory{ - HTTPClient: httpClient, - StreamingClient: streamingClient, - BatchFactory: batchFactory, - SubscriptionClient: mockSubscriptionClient, - }, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"topProducts"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price"}, - }, - }, - Custom: graphqlDataSource.ConfigJson(graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://product.service", - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: productSchema, - }, - }), - Factory: &graphqlDataSource.Factory{ - HTTPClient: httpClient, - StreamingClient: streamingClient, - BatchFactory: batchFactory, - SubscriptionClient: mockSubscriptionClient, - }, - }, - { - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - { - TypeName: "Product", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"body", "author", "product"}, - }, - { - TypeName: "Product", - FieldNames: []string{"reviews", "upc"}, - }, - { - TypeName: "User", - FieldNames: []string{"reviews", "id", "username"}, - }, - }, - Factory: &graphqlDataSource.Factory{ - HTTPClient: httpClient, - StreamingClient: streamingClient, - BatchFactory: batchFactory, - SubscriptionClient: mockSubscriptionClient, - }, - Custom: graphqlDataSource.ConfigJson(graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://review.service", - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: reviewSchema, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - UseSSE: true, - }, - }), - }, - }) - - return conf - }) - }) -} - -const ( - accountSchema = ` - extend type Query { - me: User - } - type User @key(fields: "id"){ - id: ID! - username: String! - }` - productSchema = ` - extend type Query { - topProducts(first: Int = 5): [Product] - } - type Product @key(fields: "upc") { - upc: String! - name: String! - price: Int! - }` - reviewSchema = ` - type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! - } - extend type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] - } - extend type Product @key(fields: "upc") { - upc: String!@external - reviews: [Review] - }` - baseFederationSchema = ` - type Query { - me: User - topProducts(first: Int = 5): [Product] - } - type User { - id: ID! - username: String! - reviews: [Review] - } - type Product { - upc: String! - name: String! - price: Int! - reviews: [Review] - } - type Review { - body: String! - author: User! - product: Product! - } -` -) diff --git a/pkg/graphql/config_factory_proxy.go b/pkg/graphql/config_factory_proxy.go deleted file mode 100644 index 292ca209d..000000000 --- a/pkg/graphql/config_factory_proxy.go +++ /dev/null @@ -1,121 +0,0 @@ -package graphql - -import ( - "net/http" - "time" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -type proxyEngineConfigFactoryOptions struct { - httpClient *http.Client - streamingClient *http.Client - subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory -} - -type ProxyEngineConfigFactoryOption func(options *proxyEngineConfigFactoryOptions) - -func WithProxyHttpClient(client *http.Client) ProxyEngineConfigFactoryOption { - return func(options *proxyEngineConfigFactoryOptions) { - options.httpClient = client - } -} - -func WithProxyStreamingClient(client *http.Client) ProxyEngineConfigFactoryOption { - return func(options *proxyEngineConfigFactoryOptions) { - options.streamingClient = client - } -} - -func WithProxySubscriptionClientFactory(factory graphqlDataSource.GraphQLSubscriptionClientFactory) ProxyEngineConfigFactoryOption { - return func(options *proxyEngineConfigFactoryOptions) { - options.subscriptionClientFactory = factory - } -} - -// ProxyUpstreamConfig holds configuration to configure a single data source to a single upstream. -type ProxyUpstreamConfig struct { - URL string - Method string - StaticHeaders http.Header - SubscriptionType SubscriptionType -} - -// ProxyEngineConfigFactory is used to create a v2 engine config with a single upstream and a single data source for this upstream. -type ProxyEngineConfigFactory struct { - httpClient *http.Client - streamingClient *http.Client - schema *Schema - proxyUpstreamConfig ProxyUpstreamConfig - batchFactory resolve.DataSourceBatchFactory - subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory -} - -func NewProxyEngineConfigFactory(schema *Schema, proxyUpstreamConfig ProxyUpstreamConfig, batchFactory resolve.DataSourceBatchFactory, opts ...ProxyEngineConfigFactoryOption) *ProxyEngineConfigFactory { - options := proxyEngineConfigFactoryOptions{ - httpClient: &http.Client{ - Timeout: time.Second * 10, - Transport: &http.Transport{ - MaxIdleConnsPerHost: 1024, - TLSHandshakeTimeout: 0 * time.Second, - }, - }, - streamingClient: &http.Client{ - Timeout: 0, - }, - subscriptionClientFactory: &graphqlDataSource.DefaultSubscriptionClientFactory{}, - } - - for _, optFunc := range opts { - optFunc(&options) - } - - return &ProxyEngineConfigFactory{ - httpClient: options.httpClient, - streamingClient: options.streamingClient, - schema: schema, - proxyUpstreamConfig: proxyUpstreamConfig, - batchFactory: batchFactory, - subscriptionClientFactory: options.subscriptionClientFactory, - } -} - -func (p *ProxyEngineConfigFactory) EngineV2Configuration() (EngineV2Configuration, error) { - dataSourceConfig := graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: p.proxyUpstreamConfig.URL, - Method: p.proxyUpstreamConfig.Method, - Header: p.proxyUpstreamConfig.StaticHeaders, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - URL: p.proxyUpstreamConfig.URL, - UseSSE: p.proxyUpstreamConfig.SubscriptionType == SubscriptionTypeSSE, - }, - } - - conf := NewEngineV2Configuration(p.schema) - - rawDoc, report := astparser.ParseGraphqlDocumentBytes(p.schema.rawInput) - if report.HasErrors() { - return EngineV2Configuration{}, report - } - - dataSource, err := newGraphQLDataSourceV2Generator(&rawDoc).Generate( - dataSourceConfig, - p.batchFactory, - p.httpClient, - WithDataSourceV2GeneratorSubscriptionConfiguration(p.streamingClient, p.proxyUpstreamConfig.SubscriptionType), - WithDataSourceV2GeneratorSubscriptionClientFactory(p.subscriptionClientFactory), - ) - if err != nil { - return EngineV2Configuration{}, err - } - - conf.AddDataSource(dataSource) - fieldConfigs := newGraphQLFieldConfigsV2Generator(p.schema).Generate() - conf.SetFieldConfigurations(fieldConfigs) - - return conf, nil -} diff --git a/pkg/graphql/config_factory_proxy_test.go b/pkg/graphql/config_factory_proxy_test.go deleted file mode 100644 index f65ef326e..000000000 --- a/pkg/graphql/config_factory_proxy_test.go +++ /dev/null @@ -1,291 +0,0 @@ -package graphql - -import ( - "net/http" - "sort" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" -) - -func TestProxyEngineConfigFactory_EngineV2Configuration(t *testing.T) { - schema, err := NewSchemaFromString(graphqlGeneratorSchema) - require.NoError(t, err) - - client := &http.Client{} - streamingClient := &http.Client{} - batchFactory := graphqlDataSource.NewBatchFactory() - - expectedFieldConfigs := plan.FieldConfigurations{ - { - TypeName: "Mutation", - FieldName: "addUser", - Arguments: plan.ArgumentsConfigurations{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "age", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "language", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "_entities", - Arguments: plan.ArgumentsConfigurations{ - { - Name: "representations", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - } - - t.Run("engine config with unknown subscription type", func(t *testing.T) { - upstreamConfig := ProxyUpstreamConfig{ - URL: "http://localhost:8080", - Method: http.MethodGet, - StaticHeaders: map[string][]string{ - "Authorization": {"123abc"}, - }, - } - - configFactory := NewProxyEngineConfigFactory( - schema, - upstreamConfig, - batchFactory, - WithProxyHttpClient(client), - WithProxyStreamingClient(streamingClient), - WithProxySubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - config, err := configFactory.EngineV2Configuration() - if !assert.NoError(t, err) { - return - } - - expectedDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "_entities"}, - }, - { - TypeName: "Mutation", - FieldNames: []string{"addUser"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"userCount"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "age", "language"}, - }, - { - TypeName: "Language", - FieldNames: []string{"code", "name"}, - }, - }, - Factory: &graphqlDataSource.Factory{ - HTTPClient: client, - StreamingClient: streamingClient, - BatchFactory: batchFactory, - SubscriptionClient: mockSubscriptionClient, - }, - Custom: graphqlDataSource.ConfigJson(graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://localhost:8080", - Method: "GET", - Header: map[string][]string{ - "Authorization": {"123abc"}, - }, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - URL: "http://localhost:8080", - UseSSE: false, - }, - }), - } - - expectedConfig := NewEngineV2Configuration(schema) - expectedConfig.AddDataSource(expectedDataSource) - expectedConfig.SetFieldConfigurations(expectedFieldConfigs) - sortFieldConfigurations(config.FieldConfigurations()) - - assert.Equal(t, expectedConfig, config) - }) - - t.Run("engine config with specific WS subscription type", func(t *testing.T) { - upstreamConfig := ProxyUpstreamConfig{ - URL: "http://localhost:8080", - Method: http.MethodGet, - StaticHeaders: map[string][]string{ - "Authorization": {"123abc"}, - }, - SubscriptionType: SubscriptionTypeGraphQLTransportWS, - } - - configFactory := NewProxyEngineConfigFactory( - schema, - upstreamConfig, - batchFactory, - WithProxyHttpClient(client), - WithProxyStreamingClient(streamingClient), - WithProxySubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - config, err := configFactory.EngineV2Configuration() - if !assert.NoError(t, err) { - return - } - - expectedDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "_entities"}, - }, - { - TypeName: "Mutation", - FieldNames: []string{"addUser"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"userCount"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "age", "language"}, - }, - { - TypeName: "Language", - FieldNames: []string{"code", "name"}, - }, - }, - Factory: &graphqlDataSource.Factory{ - HTTPClient: client, - StreamingClient: streamingClient, - BatchFactory: batchFactory, - SubscriptionClient: mockSubscriptionClient, - }, - Custom: graphqlDataSource.ConfigJson(graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://localhost:8080", - Method: "GET", - Header: map[string][]string{ - "Authorization": {"123abc"}, - }, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - URL: "http://localhost:8080", - UseSSE: false, - }, - }), - } - - expectedConfig := NewEngineV2Configuration(schema) - expectedConfig.AddDataSource(expectedDataSource) - expectedConfig.SetFieldConfigurations(expectedFieldConfigs) - sortFieldConfigurations(config.FieldConfigurations()) - - assert.Equal(t, expectedConfig, config) - }) - - t.Run("engine config with SSE subscription type", func(t *testing.T) { - upstreamConfig := ProxyUpstreamConfig{ - URL: "http://localhost:8080", - Method: http.MethodGet, - StaticHeaders: map[string][]string{ - "Authorization": {"123abc"}, - }, - SubscriptionType: SubscriptionTypeSSE, - } - - configFactory := NewProxyEngineConfigFactory( - schema, - upstreamConfig, - batchFactory, - WithProxyHttpClient(client), - WithProxyStreamingClient(streamingClient), - WithProxySubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - config, err := configFactory.EngineV2Configuration() - if !assert.NoError(t, err) { - return - } - - expectedDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "_entities"}, - }, - { - TypeName: "Mutation", - FieldNames: []string{"addUser"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"userCount"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "age", "language"}, - }, - { - TypeName: "Language", - FieldNames: []string{"code", "name"}, - }, - }, - Factory: &graphqlDataSource.Factory{ - HTTPClient: client, - StreamingClient: streamingClient, - BatchFactory: batchFactory, - SubscriptionClient: mockSubscriptionClient, - }, - Custom: graphqlDataSource.ConfigJson(graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://localhost:8080", - Method: "GET", - Header: map[string][]string{ - "Authorization": {"123abc"}, - }, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - URL: "http://localhost:8080", - UseSSE: true, - }, - }), - } - - expectedConfig := NewEngineV2Configuration(schema) - expectedConfig.AddDataSource(expectedDataSource) - expectedConfig.SetFieldConfigurations(expectedFieldConfigs) - sortFieldConfigurations(config.FieldConfigurations()) - - assert.Equal(t, expectedConfig, config) - }) - -} - -// sortFieldConfigurations makes field configurations deterministic for testing -func sortFieldConfigurations(fieldConfigs []plan.FieldConfiguration) { - sort.Slice(fieldConfigs, func(i, j int) bool { - return fieldConfigs[i].TypeName < fieldConfigs[j].TypeName - }) -} diff --git a/pkg/graphql/engine_config_v2.go b/pkg/graphql/engine_config_v2.go deleted file mode 100644 index e8f964dee..000000000 --- a/pkg/graphql/engine_config_v2.go +++ /dev/null @@ -1,255 +0,0 @@ -package graphql - -import ( - "errors" - "net/http" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -const ( - DefaultFlushIntervalInMilliseconds = 1000 -) - -type EngineV2Configuration struct { - schema *Schema - plannerConfig plan.Configuration - websocketBeforeStartHook WebsocketBeforeStartHook - dataLoaderConfig dataLoaderConfig - options EngineV2ConfigurationOptions -} - -type EngineV2ConfigurationOptions struct { - disableIntrospection bool -} - -type EngineV2ConfigurationOption func(config *EngineV2ConfigurationOptions) - -func WithDisableIntrospection(disable bool) EngineV2ConfigurationOption { - return func(config *EngineV2ConfigurationOptions) { - config.disableIntrospection = disable - } -} - -func NewEngineV2Configuration(schema *Schema, options ...EngineV2ConfigurationOption) EngineV2Configuration { - opts := EngineV2ConfigurationOptions{} - for _, option := range options { - option(&opts) - } - - return EngineV2Configuration{ - schema: schema, - plannerConfig: plan.Configuration{ - DefaultFlushIntervalMillis: DefaultFlushIntervalInMilliseconds, - DataSources: []plan.DataSourceConfiguration{}, - Fields: plan.FieldConfigurations{}, - }, - dataLoaderConfig: dataLoaderConfig{ - EnableSingleFlightLoader: false, - EnableDataLoader: false, - }, - options: opts, - } -} - -type dataLoaderConfig struct { - EnableSingleFlightLoader bool - EnableDataLoader bool -} - -func (e *EngineV2Configuration) SetCustomResolveMap(customResolveMap map[string]resolve.CustomResolve) { - e.plannerConfig.CustomResolveMap = customResolveMap -} - -func (e *EngineV2Configuration) AddDataSource(dataSource plan.DataSourceConfiguration) { - e.plannerConfig.DataSources = append(e.plannerConfig.DataSources, dataSource) -} - -func (e *EngineV2Configuration) SetDataSources(dataSources []plan.DataSourceConfiguration) { - e.plannerConfig.DataSources = dataSources -} - -func (e *EngineV2Configuration) AddFieldConfiguration(fieldConfig plan.FieldConfiguration) { - e.plannerConfig.Fields = append(e.plannerConfig.Fields, fieldConfig) -} - -func (e *EngineV2Configuration) SetFieldConfigurations(fieldConfigs plan.FieldConfigurations) { - e.plannerConfig.Fields = fieldConfigs -} - -func (e *EngineV2Configuration) DataSources() []plan.DataSourceConfiguration { - return e.plannerConfig.DataSources -} - -func (e *EngineV2Configuration) FieldConfigurations() plan.FieldConfigurations { - return e.plannerConfig.Fields -} - -func (e *EngineV2Configuration) EnableDataLoader(enable bool) { - e.dataLoaderConfig.EnableDataLoader = enable -} - -func (e *EngineV2Configuration) EnableSingleFlight(enable bool) { - e.dataLoaderConfig.EnableSingleFlightLoader = enable -} - -// SetWebsocketBeforeStartHook - sets before start hook which will be called before processing any operation sent over websockets -func (e *EngineV2Configuration) SetWebsocketBeforeStartHook(hook WebsocketBeforeStartHook) { - e.websocketBeforeStartHook = hook -} - -type dataSourceV2GeneratorOptions struct { - streamingClient *http.Client - subscriptionType SubscriptionType - subscriptionClientFactory graphqlDataSource.GraphQLSubscriptionClientFactory -} - -type DataSourceV2GeneratorOption func(options *dataSourceV2GeneratorOptions) - -func WithDataSourceV2GeneratorSubscriptionConfiguration(streamingClient *http.Client, subscriptionType SubscriptionType) DataSourceV2GeneratorOption { - return func(options *dataSourceV2GeneratorOptions) { - options.streamingClient = streamingClient - options.subscriptionType = subscriptionType - } -} - -func WithDataSourceV2GeneratorSubscriptionClientFactory(factory graphqlDataSource.GraphQLSubscriptionClientFactory) DataSourceV2GeneratorOption { - return func(options *dataSourceV2GeneratorOptions) { - options.subscriptionClientFactory = factory - } -} - -type graphqlDataSourceV2Generator struct { - document *ast.Document -} - -func newGraphQLDataSourceV2Generator(document *ast.Document) *graphqlDataSourceV2Generator { - return &graphqlDataSourceV2Generator{ - document: document, - } -} - -func (d *graphqlDataSourceV2Generator) Generate(config graphqlDataSource.Configuration, batchFactory resolve.DataSourceBatchFactory, httpClient *http.Client, options ...DataSourceV2GeneratorOption) (plan.DataSourceConfiguration, error) { - var planDataSource plan.DataSourceConfiguration - extractor := plan.NewLocalTypeFieldExtractor(d.document) - planDataSource.RootNodes, planDataSource.ChildNodes = extractor.GetAllNodes() - - definedOptions := &dataSourceV2GeneratorOptions{ - streamingClient: &http.Client{Timeout: 0}, - subscriptionType: SubscriptionTypeUnknown, - subscriptionClientFactory: &graphqlDataSource.DefaultSubscriptionClientFactory{}, - } - - for _, option := range options { - option(definedOptions) - } - - factory := &graphqlDataSource.Factory{ - HTTPClient: httpClient, - StreamingClient: definedOptions.streamingClient, - BatchFactory: batchFactory, - } - - subscriptionClient, err := d.generateSubscriptionClient(httpClient, definedOptions) - if err != nil { - return plan.DataSourceConfiguration{}, err - } - factory.SubscriptionClient = subscriptionClient - - planDataSource.Factory = factory - planDataSource.Custom = graphqlDataSource.ConfigJson(config) - - return planDataSource, nil -} - -func (d *graphqlDataSourceV2Generator) generateSubscriptionClient(httpClient *http.Client, definedOptions *dataSourceV2GeneratorOptions) (*graphqlDataSource.SubscriptionClient, error) { - var graphqlSubscriptionClient graphqlDataSource.GraphQLSubscriptionClient - switch definedOptions.subscriptionType { - case SubscriptionTypeGraphQLTransportWS: - graphqlSubscriptionClient = definedOptions.subscriptionClientFactory.NewSubscriptionClient( - httpClient, - definedOptions.streamingClient, - nil, - graphqlDataSource.WithWSSubProtocol(graphqlDataSource.ProtocolGraphQLTWS), - ) - default: - // for compatibility reasons we fall back to graphql-ws protocol - graphqlSubscriptionClient = definedOptions.subscriptionClientFactory.NewSubscriptionClient( - httpClient, - definedOptions.streamingClient, - nil, - graphqlDataSource.WithWSSubProtocol(graphqlDataSource.ProtocolGraphQLWS), - ) - } - - subscriptionClient, ok := graphqlSubscriptionClient.(*graphqlDataSource.SubscriptionClient) - if !ok { - return nil, errors.New("invalid SubscriptionClient was instantiated") - } - return subscriptionClient, nil -} - -type graphqlFieldConfigurationsV2Generator struct { - schema *Schema -} - -func newGraphQLFieldConfigsV2Generator(schema *Schema) *graphqlFieldConfigurationsV2Generator { - return &graphqlFieldConfigurationsV2Generator{ - schema: schema, - } -} - -func (g *graphqlFieldConfigurationsV2Generator) Generate(predefinedFieldConfigs ...plan.FieldConfiguration) plan.FieldConfigurations { - var planFieldConfigs plan.FieldConfigurations - if len(predefinedFieldConfigs) > 0 { - planFieldConfigs = predefinedFieldConfigs - } - - generatedArgs := g.schema.GetAllFieldArguments(NewSkipReservedNamesFunc()) - generatedArgsAsLookupMap := CreateTypeFieldArgumentsLookupMap(generatedArgs) - g.engineConfigArguments(&planFieldConfigs, generatedArgsAsLookupMap) - - return planFieldConfigs -} - -func (g *graphqlFieldConfigurationsV2Generator) engineConfigArguments(fieldConfs *plan.FieldConfigurations, generatedArgs map[TypeFieldLookupKey]TypeFieldArguments) { - for i := range *fieldConfs { - if len(generatedArgs) == 0 { - return - } - - lookupKey := CreateTypeFieldLookupKey((*fieldConfs)[i].TypeName, (*fieldConfs)[i].FieldName) - currentArgs, exists := generatedArgs[lookupKey] - if !exists { - continue - } - - (*fieldConfs)[i].Arguments = g.createArgumentConfigurationsForArgumentNames(currentArgs.ArgumentNames) - delete(generatedArgs, lookupKey) - } - - for _, genArgs := range generatedArgs { - *fieldConfs = append(*fieldConfs, plan.FieldConfiguration{ - TypeName: genArgs.TypeName, - FieldName: genArgs.FieldName, - Arguments: g.createArgumentConfigurationsForArgumentNames(genArgs.ArgumentNames), - }) - } -} - -func (g *graphqlFieldConfigurationsV2Generator) createArgumentConfigurationsForArgumentNames(argumentNames []string) plan.ArgumentsConfigurations { - argConfs := plan.ArgumentsConfigurations{} - for _, argName := range argumentNames { - argConf := plan.ArgumentConfiguration{ - Name: argName, - SourceType: plan.FieldArgumentSource, - } - - argConfs = append(argConfs, argConf) - } - - return argConfs -} diff --git a/pkg/graphql/engine_config_v2_test.go b/pkg/graphql/engine_config_v2_test.go deleted file mode 100644 index 74a15b0ef..000000000 --- a/pkg/graphql/engine_config_v2_test.go +++ /dev/null @@ -1,329 +0,0 @@ -package graphql - -import ( - "context" - "net/http" - "sort" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" -) - -func TestNewEngineV2Configuration(t *testing.T) { - var engineConfig EngineV2Configuration - - t.Run("should create a new engine v2 config", func(t *testing.T) { - schema, err := NewSchemaFromString(countriesSchema) - require.NoError(t, err) - - engineConfig = NewEngineV2Configuration(schema) - assert.Len(t, engineConfig.plannerConfig.DataSources, 0) - assert.Len(t, engineConfig.plannerConfig.Fields, 0) - }) - - t.Run("should successfully add a data source", func(t *testing.T) { - ds := plan.DataSourceConfiguration{Custom: []byte("1")} - engineConfig.AddDataSource(ds) - - assert.Len(t, engineConfig.plannerConfig.DataSources, 1) - assert.Equal(t, ds, engineConfig.plannerConfig.DataSources[0]) - }) - - t.Run("should successfully set all data sources", func(t *testing.T) { - ds := []plan.DataSourceConfiguration{ - {Custom: []byte("2")}, - {Custom: []byte("3")}, - {Custom: []byte("4")}, - } - engineConfig.SetDataSources(ds) - - assert.Len(t, engineConfig.plannerConfig.DataSources, 3) - assert.Equal(t, ds, engineConfig.plannerConfig.DataSources) - }) - - t.Run("should successfully add a field config", func(t *testing.T) { - fieldConfig := plan.FieldConfiguration{FieldName: "a"} - engineConfig.AddFieldConfiguration(fieldConfig) - - assert.Len(t, engineConfig.plannerConfig.Fields, 1) - assert.Equal(t, fieldConfig, engineConfig.plannerConfig.Fields[0]) - }) - - t.Run("should successfully set all field configs", func(t *testing.T) { - fieldConfigs := plan.FieldConfigurations{ - {FieldName: "b"}, - {FieldName: "c"}, - {FieldName: "d"}, - } - engineConfig.SetFieldConfigurations(fieldConfigs) - - assert.Len(t, engineConfig.plannerConfig.Fields, 3) - assert.Equal(t, fieldConfigs, engineConfig.plannerConfig.Fields) - }) -} - -func TestGraphQLDataSourceV2Generator_Generate(t *testing.T) { - client := &http.Client{} - streamingClient := &http.Client{} - - doc, report := astparser.ParseGraphqlDocumentString(graphqlGeneratorSchema) - require.Falsef(t, report.HasErrors(), "document parser report has errors") - - batchFactory := graphqlDataSource.NewBatchFactory() - expectedRootNodes := []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me", "_entities"}, - }, - { - TypeName: "Mutation", - FieldNames: []string{"addUser"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"userCount"}, - }, - } - expectedChildNodes := []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "age", "language"}, - }, - { - TypeName: "Language", - FieldNames: []string{"code", "name"}, - }, - } - - t.Run("without subscription configuration", func(t *testing.T) { - dataSourceConfig := graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://localhost:8080", - Method: http.MethodGet, - Header: map[string][]string{ - "Authorization": {"123abc"}, - }, - }, - } - - expectedDataSourceFactory := &graphqlDataSource.Factory{ - BatchFactory: batchFactory, - HTTPClient: client, - StreamingClient: streamingClient, - SubscriptionClient: mockSubscriptionClient, - } - - dataSource, err := newGraphQLDataSourceV2Generator(&doc).Generate( - dataSourceConfig, - batchFactory, - client, - WithDataSourceV2GeneratorSubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - require.NoError(t, err) - - assert.Equal(t, expectedRootNodes, dataSource.RootNodes) - assert.Equal(t, expectedChildNodes, dataSource.ChildNodes) - assert.Equal(t, expectedDataSourceFactory, dataSource.Factory) - }) - - t.Run("with subscription configuration (SSE)", func(t *testing.T) { - dataSourceConfig := graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: "http://localhost:8080", - Method: http.MethodGet, - Header: map[string][]string{ - "Authorization": {"123abc"}, - }, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - UseSSE: true, - }, - } - - expectedDataSourceFactory := &graphqlDataSource.Factory{ - BatchFactory: batchFactory, - HTTPClient: client, - StreamingClient: streamingClient, - SubscriptionClient: mockSubscriptionClient, - } - - dataSource, err := newGraphQLDataSourceV2Generator(&doc).Generate( - dataSourceConfig, - batchFactory, - client, - WithDataSourceV2GeneratorSubscriptionConfiguration(streamingClient, SubscriptionTypeSSE), - WithDataSourceV2GeneratorSubscriptionClientFactory(&MockSubscriptionClientFactory{}), - ) - require.NoError(t, err) - - assert.Equal(t, expectedRootNodes, dataSource.RootNodes) - assert.Equal(t, expectedChildNodes, dataSource.ChildNodes) - assert.Equal(t, expectedDataSourceFactory, dataSource.Factory) - }) - -} - -func TestGraphqlFieldConfigurationsV2Generator_Generate(t *testing.T) { - schema, err := NewSchemaFromString(graphqlGeneratorSchema) - require.NoError(t, err) - - t.Run("should generate field configs without predefined field configs", func(t *testing.T) { - fieldConfigurations := newGraphQLFieldConfigsV2Generator(schema).Generate() - sort.Slice(fieldConfigurations, func(i, j int) bool { // make the resulting slice deterministic again - return fieldConfigurations[i].TypeName < fieldConfigurations[j].TypeName - }) - - expectedFieldConfigurations := plan.FieldConfigurations{ - { - TypeName: "Mutation", - FieldName: "addUser", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "age", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "language", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "_entities", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "representations", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - } - - assert.Equal(t, expectedFieldConfigurations, fieldConfigurations) - }) - - t.Run("should generate field configs with predefined field configs", func(t *testing.T) { - predefinedFieldConfigs := plan.FieldConfigurations{ - { - TypeName: "User", - FieldName: "name", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Query", - FieldName: "_entities", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "representations", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - } - - fieldConfigurations := newGraphQLFieldConfigsV2Generator(schema).Generate(predefinedFieldConfigs...) - sort.Slice(fieldConfigurations, func(i, j int) bool { // make the resulting slice deterministic again - return fieldConfigurations[i].TypeName < fieldConfigurations[j].TypeName - }) - - expectedFieldConfigurations := plan.FieldConfigurations{ - { - TypeName: "Mutation", - FieldName: "addUser", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "age", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "language", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "_entities", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "representations", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "User", - FieldName: "name", - RequiresFields: []string{"id"}, - }, - } - - assert.Equal(t, expectedFieldConfigurations, fieldConfigurations) - }) - -} - -func TestEngineV2Configuration_EnableSingleFlight(t *testing.T) { - schema, err := NewSchemaFromString(graphqlGeneratorSchema) - require.NoError(t, err) - - conf := NewEngineV2Configuration(schema) - require.Falsef(t, conf.dataLoaderConfig.EnableSingleFlightLoader, "single flight is not disabled by default") - - conf.EnableSingleFlight(true) - assert.True(t, conf.dataLoaderConfig.EnableSingleFlightLoader) - - conf.EnableSingleFlight(false) - assert.False(t, conf.dataLoaderConfig.EnableSingleFlightLoader) -} - -var mockSubscriptionClient = &graphqlDataSource.SubscriptionClient{} - -type MockSubscriptionClientFactory struct{} - -func (m *MockSubscriptionClientFactory) NewSubscriptionClient(httpClient, streamingClient *http.Client, engineCtx context.Context, options ...graphqlDataSource.Options) graphqlDataSource.GraphQLSubscriptionClient { - return mockSubscriptionClient -} - -var graphqlGeneratorSchema = `scalar _Any - union _Entity = User - - type Query { - me: User! - _entities(representations: [_Any!]!): [_Entity]! - } - - type Mutation { - addUser(name: String!, age: Int!, language: Language!): User! - } - - type Subscription { - userCount: Int! - } - - type User { - id: ID! - name: String! - age: Int! - language: Language! - } - - type Language { - code: String! - name: String! - } -` diff --git a/pkg/graphql/errors.go b/pkg/graphql/errors.go deleted file mode 100644 index 95496dbd6..000000000 --- a/pkg/graphql/errors.go +++ /dev/null @@ -1,207 +0,0 @@ -package graphql - -import ( - "encoding/json" - "fmt" - "io" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphqlerrors" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type Errors interface { - error - WriteResponse(writer io.Writer) (n int, err error) - Count() int - ErrorByIndex(i int) error -} - -type RequestErrors []RequestError - -func RequestErrorsFromError(err error) RequestErrors { - if errors, ok := err.(RequestErrors); ok { - return errors - } - if report, ok := err.(operationreport.Report); ok { - if len(report.ExternalErrors) == 0 { - return RequestErrors{ - { - Message: "Internal Error", - }, - } - } - var errors RequestErrors - for _, externalError := range report.ExternalErrors { - errors = append(errors, RequestError{ - Message: externalError.Message, - Locations: externalError.Locations, - Path: ErrorPath{ - astPath: externalError.Path, - }, - }) - } - return errors - } - return RequestErrors{ - { - Message: err.Error(), - }, - } -} - -func RequestErrorsFromOperationReport(report operationreport.Report) (errors RequestErrors) { - if len(report.ExternalErrors) == 0 { - return nil - } - - for _, externalError := range report.ExternalErrors { - locations := make([]graphqlerrors.Location, 0) - for _, reportLocation := range externalError.Locations { - loc := graphqlerrors.Location{ - Line: reportLocation.Line, - Column: reportLocation.Column, - } - - locations = append(locations, loc) - } - - validationError := RequestError{ - Message: externalError.Message, - Path: ErrorPath{astPath: externalError.Path}, - Locations: locations, - } - - errors = append(errors, validationError) - } - - return errors -} - -func (o RequestErrors) Error() string { - if len(o) > 0 { // avoid panic ... - return o.ErrorByIndex(0).Error() - } - return "no error" // ... so, this should never be returned -} - -func (o RequestErrors) WriteResponse(writer io.Writer) (n int, err error) { - response := Response{ - Errors: o, - } - - responseBytes, err := response.Marshal() - if err != nil { - return 0, err - } - - return writer.Write(responseBytes) -} - -func (o RequestErrors) Count() int { - return len(o) -} - -func (o RequestErrors) ErrorByIndex(i int) error { - if i >= o.Count() { - return nil - } - - return o[i] -} - -type RequestError struct { - Message string `json:"message"` - Locations []graphqlerrors.Location `json:"locations,omitempty"` - Path ErrorPath `json:"path"` -} - -func (o RequestError) MarshalJSON() ([]byte, error) { - if o.Path.Len() == 0 { - return json.Marshal(struct { - Message string `json:"message"` - Locations []graphqlerrors.Location `json:"locations,omitempty"` - }{ - Message: o.Message, - Locations: o.Locations, - }) - } - path, err := o.Path.MarshalJSON() - if err != nil { - return nil, err - } - return json.Marshal(struct { - Message string `json:"message"` - Locations []graphqlerrors.Location `json:"locations,omitempty"` - Path json.RawMessage `json:"path"` - }{ - Message: o.Message, - Locations: o.Locations, - Path: path, - }) -} - -func (o RequestError) Error() string { - return fmt.Sprintf("%s, locations: %+v, path: %s", o.Message, o.Locations, o.Path.String()) -} - -type SchemaValidationErrors []SchemaValidationError - -func schemaValidationErrorsFromOperationReport(report operationreport.Report) (errors SchemaValidationErrors) { - if len(report.ExternalErrors) == 0 { - return nil - } - - for _, externalError := range report.ExternalErrors { - validationError := SchemaValidationError{ - Message: externalError.Message, - } - - errors = append(errors, validationError) - } - - return errors -} - -func (s SchemaValidationErrors) Error() string { - return fmt.Sprintf("schema contains %d error(s)", s.Count()) -} - -func (s SchemaValidationErrors) WriteResponse(writer io.Writer) (n int, err error) { - return writer.Write(nil) -} - -func (s SchemaValidationErrors) Count() int { - return len(s) -} - -func (s SchemaValidationErrors) ErrorByIndex(i int) error { - if i >= s.Count() { - return nil - } - return s[i] -} - -type SchemaValidationError struct { - Message string `json:"message"` -} - -func (s SchemaValidationError) Error() string { - return s.Message -} - -type ErrorPath struct { - astPath ast.Path -} - -func (e *ErrorPath) String() string { - return e.astPath.String() -} - -func (e *ErrorPath) MarshalJSON() ([]byte, error) { - return json.Marshal(e.astPath) -} - -func (e *ErrorPath) Len() int { - return len(e.astPath) -} diff --git a/pkg/graphql/errors_test.go b/pkg/graphql/errors_test.go deleted file mode 100644 index ed1f8b968..000000000 --- a/pkg/graphql/errors_test.go +++ /dev/null @@ -1,155 +0,0 @@ -package graphql - -import ( - "bytes" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphqlerrors" -) - -func TestOperationValidationErrors_Error(t *testing.T) { - validationErrs := RequestErrors{ - RequestError{ - Message: "a single error", - Locations: []graphqlerrors.Location{ - { - Line: 1, - Column: 1, - }, - }, - Path: ErrorPath{ - astPath: []ast.PathItem{ - { - Kind: ast.FieldName, - ArrayIndex: 0, - FieldName: []byte("hello"), - }, - }, - }, - }, - } - - assert.Equal(t, "a single error, locations: [{Line:1 Column:1}], path: [hello]", validationErrs.Error()) -} - -func TestOperationValidationErrors_WriteResponse(t *testing.T) { - validationErrs := RequestErrors{ - RequestError{ - Message: "error in operation", - Locations: []graphqlerrors.Location{ - { - Line: 1, - Column: 1, - }, - }, - Path: ErrorPath{ - astPath: []ast.PathItem{ - { - Kind: ast.FieldName, - ArrayIndex: 0, - FieldName: []byte("hello"), - }, - }, - }, - }, - } - - buf := new(bytes.Buffer) - n, err := validationErrs.WriteResponse(buf) - - expectedResponse := `{"errors":[{"message":"error in operation","locations":[{"line":1,"column":1}],"path":["hello"]}]}` - - assert.NoError(t, err) - assert.Greater(t, n, 0) - assert.Equal(t, expectedResponse, buf.String()) -} - -func TestOperationValidationError_Error(t *testing.T) { - validatonErr := RequestError{ - Message: "error in operation", - Locations: []graphqlerrors.Location{ - { - Line: 1, - Column: 1, - }, - }, - Path: ErrorPath{ - astPath: []ast.PathItem{ - { - Kind: ast.FieldName, - ArrayIndex: 0, - FieldName: []byte("hello"), - }, - }, - }, - } - - assert.Equal(t, "error in operation, locations: [{Line:1 Column:1}], path: [hello]", validatonErr.Error()) -} - -func TestOperationValidationErrors_Count(t *testing.T) { - validationErrs := RequestErrors{ - RequestError{ - Message: "error in operation", - }, - } - - assert.Equal(t, 1, validationErrs.Count()) -} - -func TestOperationValidationErrors_ErrorByIndex(t *testing.T) { - existingValidationError := RequestError{ - Message: "error in operation", - } - - validationErrs := RequestErrors{ - existingValidationError, - } - - assert.Equal(t, existingValidationError, validationErrs.ErrorByIndex(0)) - assert.Nil(t, validationErrs.ErrorByIndex(1)) -} - -func TestSchemaValidationErrors_Error(t *testing.T) { - validationErrs := SchemaValidationErrors{ - SchemaValidationError{ - Message: "there can be only one query type in schema", - }, - } - - assert.Equal(t, "schema contains 1 error(s)", validationErrs.Error()) -} - -func TestSchemaValidationErrors_Count(t *testing.T) { - validationErrs := SchemaValidationErrors{ - SchemaValidationError{ - Message: "there can be only one query type in schema", - }, - } - - assert.Equal(t, 1, validationErrs.Count()) -} - -func TestSchemaValidationErrors_ErrorByIndex(t *testing.T) { - existingValidationError := SchemaValidationError{ - Message: "there can be only one query type in schema", - } - - validationErrs := SchemaValidationErrors{ - existingValidationError, - } - - assert.Equal(t, existingValidationError, validationErrs.ErrorByIndex(0)) - assert.Nil(t, validationErrs.ErrorByIndex(1)) -} - -func TestSchemaValidationError_Error(t *testing.T) { - validationError := SchemaValidationError{ - Message: "there can be only one query type in schema", - } - - assert.Equal(t, "there can be only one query type in schema", validationError.Error()) -} diff --git a/pkg/graphql/execution_engine.go b/pkg/graphql/execution_engine.go deleted file mode 100644 index 03691415a..000000000 --- a/pkg/graphql/execution_engine.go +++ /dev/null @@ -1,172 +0,0 @@ -package graphql - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "sync" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/execution" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type DataSourceHttpJsonOptions struct { - HttpClient *http.Client - WhitelistedSchemes []string - Hooks *datasource.Hooks -} - -type DataSourceGraphqlOptions struct { - HttpClient *http.Client - WhitelistedSchemes []string - Hooks *datasource.Hooks -} - -type ExecutionOptions struct { - ExtraArguments json.RawMessage -} - -type ExecutionEngine struct { - logger abstractlogger.Logger - basePlanner *datasource.BasePlanner - executorPool *sync.Pool - schema *Schema -} - -func NewExecutionEngine(logger abstractlogger.Logger, schema *Schema, plannerConfig datasource.PlannerConfiguration) (*ExecutionEngine, error) { - executorPool := sync.Pool{ - New: func() interface{} { - return execution.NewExecutor(nil) - }, - } - - basePlanner, err := datasource.NewBaseDataSourcePlanner(schema.rawSchema, plannerConfig, logger) - if err != nil { - return nil, err - } - - return &ExecutionEngine{ - logger: logger, - basePlanner: basePlanner, - executorPool: &executorPool, - schema: schema, - }, nil -} - -func (e *ExecutionEngine) AddHttpJsonDataSource(name string) error { - return e.AddHttpJsonDataSourceWithOptions(name, DataSourceHttpJsonOptions{}) -} - -func (e *ExecutionEngine) AddHttpJsonDataSourceWithOptions(name string, options DataSourceHttpJsonOptions) error { - httpJsonFactoryFactory := &datasource.HttpJsonDataSourcePlannerFactoryFactory{} - - if options.HttpClient != nil { - httpJsonFactoryFactory.Client = options.HttpClient - } - - if len(options.WhitelistedSchemes) > 0 { - httpJsonFactoryFactory.WhitelistedSchemes = options.WhitelistedSchemes - } - - if options.Hooks != nil { - httpJsonFactoryFactory.Hooks = *options.Hooks - } - - return e.AddDataSource(name, httpJsonFactoryFactory) -} - -func (e *ExecutionEngine) AddGraphqlDataSource(name string) error { - return e.AddGraphqlDataSourceWithOptions(name, DataSourceGraphqlOptions{}) -} - -func (e *ExecutionEngine) AddGraphqlDataSourceWithOptions(name string, options DataSourceGraphqlOptions) error { - graphqlFactoryFactory := &datasource.GraphQLDataSourcePlannerFactoryFactory{} - - if options.HttpClient != nil { - graphqlFactoryFactory.Client = options.HttpClient - } - - if len(options.WhitelistedSchemes) > 0 { - graphqlFactoryFactory.WhitelistedSchemes = options.WhitelistedSchemes - } - - if options.Hooks != nil { - graphqlFactoryFactory.Hooks = *options.Hooks - } - - return e.AddDataSource(name, graphqlFactoryFactory) -} - -func (e *ExecutionEngine) AddDataSource(name string, plannerFactoryFactory datasource.PlannerFactoryFactory) error { - return e.basePlanner.RegisterDataSourcePlannerFactory(name, plannerFactoryFactory) -} - -func (e *ExecutionEngine) ExecuteWithWriter(ctx context.Context, operation *Request, writer io.Writer, options ExecutionOptions) error { - var report operationreport.Report - - if !operation.IsNormalized() { - normalizationResult, err := operation.Normalize(e.schema) - if err != nil { - return err - } - - if !normalizationResult.Successful { - return normalizationResult.Errors - } - } - - planner := execution.NewPlanner(e.basePlanner) - plan := planner.Plan(&operation.document, e.basePlanner.Definition, operation.OperationName, &report) - if report.HasErrors() { - return report - } - - variables, extraArguments := execution.VariablesFromJson(operation.Variables, options.ExtraArguments) - executionContext := execution.Context{ - Context: ctx, - Variables: variables, - ExtraArguments: extraArguments, - } - - poolExecutor := e.executorPool.Get().(*execution.Executor) - defer e.executorPool.Put(poolExecutor) - return poolExecutor.Execute(executionContext, plan, writer) -} - -func (e *ExecutionEngine) Execute(ctx context.Context, operation *Request, options ExecutionOptions) (*ExecutionResult, error) { - var buf bytes.Buffer - err := e.ExecuteWithWriter(ctx, operation, &buf, options) - return &ExecutionResult{&buf}, err -} - -func (e *ExecutionEngine) NewExecutionHandler() *execution.Handler { - return execution.NewHandler(e.basePlanner, nil) -} - -type ExecutionResult struct { - buf *bytes.Buffer -} - -func (r *ExecutionResult) Buffer() *bytes.Buffer { - return r.buf -} - -func (r *ExecutionResult) GetAsHTTPResponse() (res *http.Response) { - if r.buf == nil { - return - } - - res = &http.Response{} - res.Body = io.NopCloser(r.buf) - res.Header = make(http.Header) - res.StatusCode = 200 - - res.Header.Set("Content-Type", "application/json") - - return -} diff --git a/pkg/graphql/execution_engine_test.go b/pkg/graphql/execution_engine_test.go deleted file mode 100644 index 6767c6dfd..000000000 --- a/pkg/graphql/execution_engine_test.go +++ /dev/null @@ -1,684 +0,0 @@ -package graphql - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "net/http/httptest" - "sync" - "testing" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" - "github.com/wundergraph/graphql-go-tools/pkg/starwars" -) - -type testRoundTripper func(req *http.Request) *http.Response - -func (t testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { - return t(req), nil -} - -type roundTripperTestCase struct { - expectedHost string - expectedPath string - expectedBody string - sendStatusCode int - sendResponseBody string -} - -func createTestRoundTripper(t *testing.T, testCase roundTripperTestCase) testRoundTripper { - return func(req *http.Request) *http.Response { - assert.Equal(t, testCase.expectedHost, req.URL.Host) - assert.Equal(t, testCase.expectedPath, req.URL.Path) - - if len(testCase.expectedBody) > 0 { - var receivedBodyBytes []byte - if req.Body != nil { - var err error - receivedBodyBytes, err = io.ReadAll(req.Body) - require.NoError(t, err) - } - require.Equal(t, testCase.expectedBody, string(receivedBodyBytes), "roundTripperTestCase body do not match") - } - - body := bytes.NewBuffer([]byte(testCase.sendResponseBody)) - return &http.Response{StatusCode: testCase.sendStatusCode, Body: io.NopCloser(body)} - } -} - -func TestExecutionEngine_ExecuteWithOptions(t *testing.T) { - type testCase struct { - schema *Schema - request func(t *testing.T) Request - plannerConfig datasource.PlannerConfiguration - roundTripper testRoundTripper - preExecutionTasks func(t *testing.T, request Request, schema *Schema, engine *ExecutionEngine) // optional - expectedResponse string - } - - run := func(tc testCase, hasExecutionError bool) func(t *testing.T) { - return func(t *testing.T) { - request := tc.request(t) - - extraVariables := map[string]string{ - "request": `{"Authorization": "Bearer ey123"}`, - } - extraVariablesBytes, err := json.Marshal(extraVariables) - require.NoError(t, err) - - engine, err := NewExecutionEngine(abstractlogger.NoopLogger, tc.schema, tc.plannerConfig) - assert.NoError(t, err) - - switch tc.plannerConfig.TypeFieldConfigurations[0].DataSource.Name { - case "HttpJsonDataSource": - httpJsonOptions := DataSourceHttpJsonOptions{ - HttpClient: &http.Client{ - Transport: tc.roundTripper, - }, - } - - err = engine.AddHttpJsonDataSourceWithOptions("HttpJsonDataSource", httpJsonOptions) - assert.NoError(t, err) - case "GraphqlDataSource": - graphqlOptions := DataSourceGraphqlOptions{ - HttpClient: &http.Client{ - Transport: tc.roundTripper, - }, - } - - err = engine.AddGraphqlDataSourceWithOptions("GraphqlDataSource", graphqlOptions) - assert.NoError(t, err) - } - - if tc.preExecutionTasks != nil { - tc.preExecutionTasks(t, request, tc.schema, engine) - } - - executionRes, err := engine.Execute(context.Background(), &request, ExecutionOptions{ExtraArguments: extraVariablesBytes}) - - if hasExecutionError { - assert.Error(t, err) - } else { - assert.NoError(t, err) - } - - assert.Equal(t, tc.expectedResponse, executionRes.Buffer().String()) - } - } - - runWithoutError := func(tc testCase) func(t *testing.T) { - return run(tc, false) - } - - runWithError := func(tc testCase) func(t *testing.T) { - return run(tc, true) - } - - t.Run("execute with custom roundtripper for simple hero query on HttpJsonDatasource", runWithoutError(testCase{ - schema: starwarsSchema(t), - request: loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil), - plannerConfig: heroHttpJsonPlannerConfig, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"hero": {"name": "Luke Skywalker"}}`, - sendStatusCode: 200, - }), - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - })) - - t.Run("execute with empty request object should not panic", runWithError(testCase{ - schema: starwarsSchema(t), - request: func(t *testing.T) Request { - return Request{} - }, - plannerConfig: heroHttpJsonPlannerConfig, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"hero": {"name": "Luke Skywalker"}}`, - sendStatusCode: 200, - }), - expectedResponse: "", - })) - - t.Run("execute with custom roundtripper for simple hero query on GraphqlDataSource", runWithoutError(testCase{ - schema: starwarsSchema(t), - request: loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil), - plannerConfig: heroGraphqlDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - sendStatusCode: 200, - }), - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - })) - - t.Run("execute the correct query when sending multiple queries", runWithoutError(testCase{ - schema: starwarsSchema(t), - request: func(t *testing.T) Request { - request := loadStarWarsQuery(starwars.FileMultiQueries, nil)(t) - request.OperationName = "SingleHero" - return request - }, - plannerConfig: heroGraphqlDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - sendStatusCode: 200, - }), - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - })) - - t.Run("execute query with variables for arguments", runWithoutError(testCase{ - schema: starwarsSchema(t), - request: loadStarWarsQuery(starwars.FileDroidWithArgAndVarQuery, map[string]interface{}{"droidID": "R2D2"}), - plannerConfig: droidGraphqlDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"droid":{"name":"R2D2"}}}`, - sendStatusCode: 200, - }), - preExecutionTasks: normalizeAndValidatePreExecutionTasks, - expectedResponse: `{"data":{"droid":{"name":"R2D2"}}}`, - })) - - t.Run("execute query with arguments", runWithoutError(testCase{ - schema: starwarsSchema(t), - request: loadStarWarsQuery(starwars.FileDroidWithArgQuery, nil), - plannerConfig: droidGraphqlDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"droid":{"name":"R2D2"}}}`, - sendStatusCode: 200, - }), - preExecutionTasks: normalizeAndValidatePreExecutionTasks, - expectedResponse: `{"data":{"droid":{"name":"R2D2"}}}`, - })) - - t.Run("execute single mutation with arguments on document with multiple operations", runWithoutError(testCase{ - schema: moviesSchema(t), - request: func(t *testing.T) Request { - return Request{ - OperationName: "AddWithInput", - Variables: nil, - Query: `mutation AddToWatchlist { - addToWatchlist(movieID:3) { - id - name - year - } - } - - - mutation AddWithInput { - addToWatchlistWithInput(input: {id: 2}) { - id - name - year - } - }`, - } - }, - plannerConfig: movieHttpJsonDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"added_movie":{"id":2, "name": "Episode V – The Empire Strikes Back", "year": 1980}}`, - sendStatusCode: 200, - }), - preExecutionTasks: normalizeAndValidatePreExecutionTasks, - expectedResponse: `{"data":{"addToWatchlistWithInput":{"id":2,"name":"Episode V – The Empire Strikes Back","year":1980}}}`, - })) - - t.Run("execute operation with rest data source and arguments", runWithoutError(testCase{ - schema: heroWithArgumentSchema(t), - request: func(t *testing.T) Request { - return Request{ - OperationName: "MyHero", - Variables: stringify(map[string]interface{}{ - "heroName": "Luke Skywalker", - }), - Query: `query MyHero($heroName: String){ - hero(name: $heroName) - }`, - } - }, - plannerConfig: heroWithArgumentHttpJsonDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{ "name": "Luke Skywalker" }`, - sendResponseBody: `{"race": "Human"}`, - sendStatusCode: 200, - }), - expectedResponse: `{"data":{"hero":"Human"}}`, - })) - - t.Run("execute query and apply input coercion for lists", runWithoutError(testCase{ - schema: inputCoercionForListSchema(t), - request: func(t *testing.T) Request { - return Request{ - OperationName: "charactersByIds", - Variables: stringify(map[string]interface{}{ - "ids": 1, - }), - Query: `query($ids: [Int]) {charactersByIds(ids: $ids) { name }}`, - } - }, - plannerConfig: inputCoercionHttpJsonDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{ "ids": [1] }`, - sendResponseBody: `{"charactersByIds":[{"name": "Luke"}]}`, - sendStatusCode: 200, - }), - preExecutionTasks: normalizeAndValidatePreExecutionTasks, - expectedResponse: `{"data":{"charactersByIds":[{"name":"Luke"}]}}`, - })) - - t.Run("execute query and apply input coercion for lists with inline integer value", runWithoutError(testCase{ - schema: inputCoercionForListSchema(t), - request: func(t *testing.T) Request { - return Request{ - OperationName: "charactersByIds", - Variables: stringify(map[string]interface{}{"ids": 1}), - // the library would fail to parse the query without input coercion. - Query: `query($ids: [Int]) {charactersByIds(ids: $ids) { name }}`, - } - }, - plannerConfig: inputCoercionHttpJsonDataSource, - roundTripper: createTestRoundTripper(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{ "ids": [1] }`, - sendResponseBody: `{"charactersByIds":[{"name": "Luke"}]}`, - sendStatusCode: 200, - }), - preExecutionTasks: normalizeAndValidatePreExecutionTasks, - expectedResponse: `{"data":{"charactersByIds":[{"name":"Luke"}]}}`, - })) -} - -func normalizeAndValidatePreExecutionTasks(t *testing.T, request Request, schema *Schema, engine *ExecutionEngine) { - normalizationResult, err := request.Normalize(schema) - require.NoError(t, err) - require.True(t, normalizationResult.Successful) - - validationResult, err := request.ValidateForSchema(schema) - require.NoError(t, err) - require.True(t, validationResult.Valid) -} - -func stringify(any interface{}) []byte { - out, _ := json.Marshal(any) - return out -} - -func stringPtr(str string) *string { - return &str -} - -func moviesSchema(t *testing.T) *Schema { - schemaString := ` -type Movie { - id: Int! - name: String! - year: Int! -} - -type Mutation { - addToWatchlist(movieID: Int!): Movie - addToWatchlistWithInput(input: WatchlistInput!): Movie -} - -type Query { - default: String -} - -input WatchlistInput { - id: Int! -}` - schema, err := NewSchemaFromString(schemaString) - require.NoError(t, err) - return schema -} - -func heroWithArgumentSchema(t *testing.T) *Schema { - schemaString := ` - type Query { - hero(name: String): String - heroDefault(name: String = "Any"): String - heroDefaultRequired(name: String! = "AnyRequired"): String - heroes(names: [String!]!): [String!] - }` - - schema, err := NewSchemaFromString(schemaString) - require.NoError(t, err) - return schema -} - -func TestExampleExecutionEngine_Concatenation(t *testing.T) { - - schema, err := NewSchemaFromString(` - schema { query: Query } - type Query { friend: Friend } - type Friend { firstName: String lastName: String fullName: String } - `) - - assert.NoError(t, err) - - friendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - _, _ = w.Write([]byte(`{"firstName":"Jens","lastName":"Neuse"}`)) - })) - - defer friendServer.Close() - - pipelineConcat := ` - { - "steps": [ - { - "kind": "JSON", - "config": { - "template": "{\"fullName\":\"{{ .firstName }} {{ .lastName }}\"}" - } - } - ] - }` - - plannerConfig := datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "friend", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: stringify(datasource.HttpJsonDataSourceConfig{ - URL: friendServer.URL, - Method: stringPtr("GET"), - }), - }, - }, - { - TypeName: "Friend", - FieldName: "fullName", - DataSource: datasource.SourceConfig{ - Name: "FriendFullName", - Config: stringify(datasource.PipelineDataSourceConfig{ - ConfigString: stringPtr(pipelineConcat), - InputJSON: `{"firstName":"{{ .object.firstName }}","lastName":"{{ .object.lastName }}"}`, - }), - }, - }, - }, - } - - engine, err := NewExecutionEngine(abstractlogger.NoopLogger, schema, plannerConfig) - assert.NoError(t, err) - err = engine.AddHttpJsonDataSource("HttpJsonDataSource") - assert.NoError(t, err) - err = engine.AddDataSource("FriendFullName", datasource.PipelineDataSourcePlannerFactoryFactory{}) - assert.NoError(t, err) - - request := &Request{ - Query: `query { friend { firstName lastName fullName }}`, - } - - executionRes, err := engine.Execute(context.Background(), request, ExecutionOptions{}) - assert.NoError(t, err) - - expected := `{"data":{"friend":{"firstName":"Jens","lastName":"Neuse","fullName":"Jens Neuse"}}}` - actual := executionRes.Buffer().String() - assert.Equal(t, expected, actual) -} - -func BenchmarkExecutionEngine(b *testing.B) { - - newEngine := func() *ExecutionEngine { - schema, err := NewSchemaFromString(`type Query { hello: String}`) - assert.NoError(b, err) - plannerConfig := datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "hello", - Mapping: &datasource.MappingConfiguration{ - Disabled: true, - }, - DataSource: datasource.SourceConfig{ - Name: "HelloDataSource", - Config: stringify(datasource.StaticDataSourceConfig{ - Data: "world", - }), - }, - }, - }, - } - engine, err := NewExecutionEngine(abstractlogger.NoopLogger, schema, plannerConfig) - assert.NoError(b, err) - assert.NoError(b, engine.AddDataSource("HelloDataSource", datasource.StaticDataSourcePlannerFactoryFactory{})) - return engine - } - - ctx := context.Background() - req := &Request{ - Query: "{hello}", - } - out := bytes.Buffer{} - err := newEngine().ExecuteWithWriter(ctx, req, &out, ExecutionOptions{}) - assert.NoError(b, err) - assert.Equal(b, "{\"data\":{\"hello\":\"world\"}}", out.String()) - - pool := sync.Pool{ - New: func() interface{} { - return newEngine() - }, - } - - b.SetBytes(int64(out.Len())) - b.ResetTimer() - b.ReportAllocs() - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - engine := pool.Get().(*ExecutionEngine) - _ = engine.ExecuteWithWriter(ctx, req, io.Discard, ExecutionOptions{}) - pool.Put(engine) - } - }) -} - -var heroHttpJsonPlannerConfig = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "hero", - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - DefaultTypeName: func() *string { - typeName := "Hero" - return &typeName - }(), - }) - return data - }(), - }, - }, - }, -} - -var movieHttpJsonDataSource = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "addToWatchlistWithInput", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "added_movie", - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - DefaultTypeName: func() *string { - typeName := "Movie" - return &typeName - }(), - }) - return data - }(), - }, - }, - }, -} - -var inputCoercionHttpJsonDataSource = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "Query", - FieldName: "charactersByIds", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "charactersByIds", - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - Body: stringPtr(`{ "ids": {{ .arguments.ids }} }`), - DefaultTypeName: func() *string { - typeName := "Character" - return &typeName - }(), - }) - return data - }(), - }, - }, - }, -} - -var heroWithArgumentHttpJsonDataSource = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "race", - }, - DataSource: datasource.SourceConfig{ - Name: "HttpJsonDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.HttpJsonDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - Body: stringPtr(`{ "name": "{{ .arguments.name }}" }`), - DefaultTypeName: func() *string { - typeName := "Hero" - return &typeName - }(), - }) - return data - }(), - }, - }, - }, -} - -var heroGraphqlDataSource = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "hero", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "hero", - }, - DataSource: datasource.SourceConfig{ - Name: "GraphqlDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.GraphQLDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - }) - return data - }(), - }, - }, - }, -} - -var droidGraphqlDataSource = datasource.PlannerConfiguration{ - TypeFieldConfigurations: []datasource.TypeFieldConfiguration{ - { - TypeName: "query", - FieldName: "droid", - Mapping: &datasource.MappingConfiguration{ - Disabled: false, - Path: "droid", - }, - DataSource: datasource.SourceConfig{ - Name: "GraphqlDataSource", - Config: func() []byte { - data, _ := json.Marshal(datasource.GraphQLDataSourceConfig{ - URL: "example.com/", - Method: func() *string { - method := "GET" - return &method - }(), - }) - return data - }(), - }, - }, - }, -} diff --git a/pkg/graphql/execution_engine_v2.go b/pkg/graphql/execution_engine_v2.go deleted file mode 100644 index 8ca7f3bd9..000000000 --- a/pkg/graphql/execution_engine_v2.go +++ /dev/null @@ -1,328 +0,0 @@ -package graphql - -import ( - "bytes" - "compress/flate" - "compress/gzip" - "context" - "errors" - "io" - "net/http" - "strconv" - "sync" - - lru "github.com/hashicorp/golang-lru" - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/introspection_datasource" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/pool" - "github.com/wundergraph/graphql-go-tools/pkg/postprocess" -) - -type EngineResultWriter struct { - buf *bytes.Buffer - flushCallback func(data []byte) -} - -func NewEngineResultWriter() EngineResultWriter { - return EngineResultWriter{ - buf: &bytes.Buffer{}, - } -} - -func NewEngineResultWriterFromBuffer(buf *bytes.Buffer) EngineResultWriter { - return EngineResultWriter{ - buf: buf, - } -} - -func (e *EngineResultWriter) SetFlushCallback(flushCb func(data []byte)) { - e.flushCallback = flushCb -} - -func (e *EngineResultWriter) Write(p []byte) (n int, err error) { - return e.buf.Write(p) -} - -func (e *EngineResultWriter) Read(p []byte) (n int, err error) { - return e.buf.Read(p) -} - -func (e *EngineResultWriter) Flush() { - if e.flushCallback != nil { - e.flushCallback(e.Bytes()) - } - - e.Reset() -} - -func (e *EngineResultWriter) Len() int { - return e.buf.Len() -} - -func (e *EngineResultWriter) Bytes() []byte { - return e.buf.Bytes() -} - -func (e *EngineResultWriter) String() string { - return e.buf.String() -} - -func (e *EngineResultWriter) Reset() { - e.buf.Reset() -} - -func (e *EngineResultWriter) AsHTTPResponse(status int, headers http.Header) *http.Response { - b := &bytes.Buffer{} - - switch headers.Get(httpclient.ContentEncodingHeader) { - case "gzip": - gzw := gzip.NewWriter(b) - _, _ = gzw.Write(e.Bytes()) - _ = gzw.Close() - case "deflate": - fw, _ := flate.NewWriter(b, 1) - _, _ = fw.Write(e.Bytes()) - _ = fw.Close() - default: - headers.Del(httpclient.ContentEncodingHeader) // delete unsupported compression header - b = e.buf - } - - res := &http.Response{} - res.Body = io.NopCloser(b) - res.Header = headers - res.StatusCode = status - res.ContentLength = int64(b.Len()) - res.Header.Set("Content-Length", strconv.Itoa(b.Len())) - return res -} - -type internalExecutionContext struct { - resolveContext *resolve.Context - postProcessor *postprocess.Processor -} - -func newInternalExecutionContext() *internalExecutionContext { - return &internalExecutionContext{ - resolveContext: resolve.NewContext(context.Background()), - postProcessor: postprocess.DefaultProcessor(), - } -} - -func (e *internalExecutionContext) prepare(ctx context.Context, variables []byte, request resolve.Request) { - e.setContext(ctx) - e.setVariables(variables) - e.setRequest(request) -} - -func (e *internalExecutionContext) setRequest(request resolve.Request) { - e.resolveContext.Request = request -} - -func (e *internalExecutionContext) setContext(ctx context.Context) { - e.resolveContext = e.resolveContext.WithContext(ctx) -} - -func (e *internalExecutionContext) setVariables(variables []byte) { - e.resolveContext.Variables = variables -} - -func (e *internalExecutionContext) reset() { - e.resolveContext.Free() -} - -type ExecutionEngineV2 struct { - logger abstractlogger.Logger - config EngineV2Configuration - planner *plan.Planner - plannerMu sync.Mutex - resolver *resolve.Resolver - internalExecutionContextPool sync.Pool - executionPlanCache *lru.Cache -} - -type WebsocketBeforeStartHook interface { - OnBeforeStart(reqCtx context.Context, operation *Request) error -} - -type ExecutionOptionsV2 func(ctx *internalExecutionContext) - -func WithBeforeFetchHook(hook resolve.BeforeFetchHook) ExecutionOptionsV2 { - return func(ctx *internalExecutionContext) { - ctx.resolveContext.SetBeforeFetchHook(hook) - } -} - -func WithAfterFetchHook(hook resolve.AfterFetchHook) ExecutionOptionsV2 { - return func(ctx *internalExecutionContext) { - ctx.resolveContext.SetAfterFetchHook(hook) - } -} - -func WithAdditionalHttpHeaders(headers http.Header, excludeByKeys ...string) ExecutionOptionsV2 { - return func(ctx *internalExecutionContext) { - if len(headers) == 0 { - return - } - - if ctx.resolveContext.Request.Header == nil { - ctx.resolveContext.Request.Header = make(http.Header) - } - - excludeMap := make(map[string]bool) - for _, key := range excludeByKeys { - excludeMap[key] = true - } - - for headerKey, headerValues := range headers { - if excludeMap[headerKey] { - continue - } - - for _, headerValue := range headerValues { - ctx.resolveContext.Request.Header.Add(headerKey, headerValue) - } - } - } -} - -func NewExecutionEngineV2(ctx context.Context, logger abstractlogger.Logger, engineConfig EngineV2Configuration) (*ExecutionEngineV2, error) { - executionPlanCache, err := lru.New(1024) - if err != nil { - return nil, err - } - fetcher := resolve.NewFetcher(engineConfig.dataLoaderConfig.EnableSingleFlightLoader) - - if !engineConfig.options.disableIntrospection { - introspectionCfg, err := introspection_datasource.NewIntrospectionConfigFactory(&engineConfig.schema.document) - if err != nil { - return nil, err - } - - engineConfig.AddDataSource(introspectionCfg.BuildDataSourceConfiguration()) - for _, fieldCfg := range introspectionCfg.BuildFieldConfigurations() { - engineConfig.AddFieldConfiguration(fieldCfg) - } - } - - return &ExecutionEngineV2{ - logger: logger, - config: engineConfig, - planner: plan.NewPlanner(ctx, engineConfig.plannerConfig), - resolver: resolve.New(ctx, fetcher, engineConfig.dataLoaderConfig.EnableDataLoader), - internalExecutionContextPool: sync.Pool{ - New: func() interface{} { - return newInternalExecutionContext() - }, - }, - executionPlanCache: executionPlanCache, - }, nil -} - -func (e *ExecutionEngineV2) Execute(ctx context.Context, operation *Request, writer resolve.FlushWriter, options ...ExecutionOptionsV2) error { - if e.config.options.disableIntrospection { - isIntrospection, _ := operation.IsIntrospectionQuery() - if isIntrospection { - _, _ = writer.Write([]byte(`{"data":null}`)) - // writer.Flush() - return nil - } - } - - if !operation.IsNormalized() { - result, err := operation.Normalize(e.config.schema) - if err != nil { - return err - } - - if !result.Successful { - return result.Errors - } - } - - result, err := operation.ValidateForSchema(e.config.schema) - if err != nil { - return err - } - if !result.Valid { - return result.Errors - } - - execContext := e.getExecutionCtx() - defer e.putExecutionCtx(execContext) - - execContext.prepare(ctx, operation.Variables, operation.request) - - for i := range options { - options[i](execContext) - } - - var report operationreport.Report - cachedPlan := e.getCachedPlan(execContext, &operation.document, &e.config.schema.document, operation.OperationName, &report) - if report.HasErrors() { - return report - } - - switch p := cachedPlan.(type) { - case *plan.SynchronousResponsePlan: - err = e.resolver.ResolveGraphQLResponse(execContext.resolveContext, p.Response, nil, writer) - case *plan.SubscriptionResponsePlan: - err = e.resolver.ResolveGraphQLSubscription(execContext.resolveContext, p.Response, writer) - default: - return errors.New("execution of operation is not possible") - } - - return err -} - -func (e *ExecutionEngineV2) getCachedPlan(ctx *internalExecutionContext, operation, definition *ast.Document, operationName string, report *operationreport.Report) plan.Plan { - - hash := pool.Hash64.Get() - hash.Reset() - defer pool.Hash64.Put(hash) - err := astprinter.Print(operation, definition, hash) - if err != nil { - report.AddInternalError(err) - return nil - } - - cacheKey := hash.Sum64() - - if cached, ok := e.executionPlanCache.Get(cacheKey); ok { - if p, ok := cached.(plan.Plan); ok { - return p - } - } - - e.plannerMu.Lock() - defer e.plannerMu.Unlock() - planResult := e.planner.Plan(operation, definition, operationName, report) - if report.HasErrors() { - return nil - } - - p := ctx.postProcessor.Process(planResult) - e.executionPlanCache.Add(cacheKey, p) - return p -} - -func (e *ExecutionEngineV2) GetWebsocketBeforeStartHook() WebsocketBeforeStartHook { - return e.config.websocketBeforeStartHook -} - -func (e *ExecutionEngineV2) getExecutionCtx() *internalExecutionContext { - return e.internalExecutionContextPool.Get().(*internalExecutionContext) -} - -func (e *ExecutionEngineV2) putExecutionCtx(ctx *internalExecutionContext) { - ctx.reset() - e.internalExecutionContextPool.Put(ctx) -} diff --git a/pkg/graphql/execution_engine_v2_norace_test.go b/pkg/graphql/execution_engine_v2_norace_test.go deleted file mode 100644 index cbb07b2fa..000000000 --- a/pkg/graphql/execution_engine_v2_norace_test.go +++ /dev/null @@ -1,170 +0,0 @@ -//go:build !race - -package graphql - -import ( - "context" - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting" - "github.com/wundergraph/graphql-go-tools/pkg/testing/flags" -) - -// This tests produces data races in the generated gql code. Disable it when the race -// detector is enabled. -func TestExecutionEngineV2_FederationAndSubscription_IntegrationTest(t *testing.T) { - if flags.IsWindows { - t.Skip("skip on windows - test is timing dependent") - } - - runIntegration := func(t *testing.T, enableDataLoader bool, secondRun bool) { - t.Helper() - ctx, cancelFn := context.WithCancel(context.Background()) - setup := newFederationSetup() - t.Cleanup(func() { - cancelFn() - setup.accountsUpstreamServer.Close() - setup.productsUpstreamServer.Close() - setup.reviewsUpstreamServer.Close() - setup.pollingUpstreamServer.Close() - }) - - engine, schema, err := newFederationEngine(ctx, setup, enableDataLoader) - require.NoError(t, err) - - t.Run("should successfully execute a federation operation", func(t *testing.T) { - gqlRequest := &Request{ - OperationName: "", - Variables: nil, - Query: federationtesting.QueryReviewsOfMe, - } - - validationResult, err := gqlRequest.ValidateForSchema(schema) - require.NoError(t, err) - require.True(t, validationResult.Valid) - - execCtx, execCtxCancelFn := context.WithCancel(context.Background()) - defer execCtxCancelFn() - - resultWriter := NewEngineResultWriter() - err = engine.Execute(execCtx, gqlRequest, &resultWriter) - if assert.NoError(t, err) { - assert.Equal(t, - `{"data":{"me":{"reviews":[{"body":"A highly effective form of birth control.","product":{"upc":"top-1","name":"Trilby","price":11}},{"body":"Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","product":{"upc":"top-2","name":"Fedora","price":22}}]}}}`, - resultWriter.String(), - ) - } - }) - - t.Run("should successfully execute a federation subscription", func(t *testing.T) { - query := ` -subscription UpdatedPrice { - updatedPrice { - name - price - reviews { - body - author { - id - username - } - } - } -}` - - gqlRequest := &Request{ - OperationName: "", - Variables: nil, - Query: query, - } - - validationResult, err := gqlRequest.ValidateForSchema(schema) - require.NoError(t, err) - require.True(t, validationResult.Valid) - - execCtx, execCtxCancelFn := context.WithCancel(context.Background()) - defer execCtxCancelFn() - - message := make(chan string) - resultWriter := NewEngineResultWriter() - resultWriter.SetFlushCallback(func(data []byte) { - message <- string(data) - }) - - go func() { - err := engine.Execute(execCtx, gqlRequest, &resultWriter) - assert.NoError(t, err) - }() - - if assert.NoError(t, err) { - assert.Eventuallyf(t, func() bool { - msg := `{"data":{"updatedPrice":{"name":"Trilby","price":%d,"reviews":[{"body":"A highly effective form of birth control.","author":{"id":"1234","username":"Me"}}]}}}` - price := 10 - if secondRun { - price += 2 - } - - firstMessage := <-message - expectedFirstMessage := fmt.Sprintf(msg, price) - assert.Equal(t, expectedFirstMessage, firstMessage) - - secondMessage := <-message - expectedSecondMessage := fmt.Sprintf(msg, price+1) - assert.Equal(t, expectedSecondMessage, secondMessage) - return true - }, time.Second, 10*time.Millisecond, "did not receive expected messages") - } - }) - - /* Uncomment when polling subscriptions are ready: - - t.Run("should successfully subscribe to rest data source", func(t *testing.T) { - gqlRequest := &Request{ - OperationName: "", - Variables: nil, - Query: "subscription Counter { counter }", - } - - validationResult, err := gqlRequest.ValidateForSchema(setup.schema) - require.NoError(t, err) - require.True(t, validationResult.Valid) - - execCtx, execCtxCancelFn := context.WithCancel(context.Background()) - defer execCtxCancelFn() - - message := make(chan string) - resultWriter := NewEngineResultWriter() - resultWriter.SetFlushCallback(func(data []byte) { - fmt.Println(string(data)) - message <- string(data) - }) - - err = setup.engine.Execute(execCtx, gqlRequest, &resultWriter) - assert.NoError(t, err) - - if assert.NoError(t, err) { - assert.Eventuallyf(t, func() bool { - firstMessage := <-message - assert.Equal(t, `{"data":{"counter":1}}`, firstMessage) - secondMessage := <-message - assert.Equal(t, `{"data":{"counter":2}}`, secondMessage) - return true - }, time.Second, 10*time.Millisecond, "did not receive expected messages") - } - }) - */ - - } - - t.Run("federation", func(t *testing.T) { - runIntegration(t, false, false) - }) - - t.Run("federation with data loader enabled", func(t *testing.T) { - runIntegration(t, true, true) - }) -} diff --git a/pkg/graphql/execution_engine_v2_test.go b/pkg/graphql/execution_engine_v2_test.go deleted file mode 100644 index 62739c80e..000000000 --- a/pkg/graphql/execution_engine_v2_test.go +++ /dev/null @@ -1,2408 +0,0 @@ -package graphql - -import ( - "bytes" - "compress/flate" - "compress/gzip" - "context" - "encoding/json" - "fmt" - "io" - "net/http" - "net/http/httptest" - "sync" - "testing" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/rest_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/staticdatasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/execution" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/starwars" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting" - accounts "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph" - products "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph" - reviews "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph" -) - -type customResolver struct{} - -func (customResolver) Resolve(value []byte) ([]byte, error) { - return value, nil -} - -func TestEngineResponseWriter_AsHTTPResponse(t *testing.T) { - t.Run("no compression", func(t *testing.T) { - rw := NewEngineResultWriter() - _, err := rw.Write([]byte(`{"key": "value"}`)) - require.NoError(t, err) - - headers := make(http.Header) - headers.Set("Content-Type", "application/json") - response := rw.AsHTTPResponse(http.StatusOK, headers) - body, err := io.ReadAll(response.Body) - require.NoError(t, err) - - assert.Equal(t, http.StatusOK, response.StatusCode) - assert.Equal(t, "application/json", response.Header.Get("Content-Type")) - assert.Equal(t, `{"key": "value"}`, string(body)) - }) - - t.Run("compression based on content encoding header", func(t *testing.T) { - rw := NewEngineResultWriter() - _, err := rw.Write([]byte(`{"key": "value"}`)) - require.NoError(t, err) - - headers := make(http.Header) - headers.Set("Content-Type", "application/json") - - t.Run("gzip", func(t *testing.T) { - headers.Set(httpclient.ContentEncodingHeader, "gzip") - - response := rw.AsHTTPResponse(http.StatusOK, headers) - assert.Equal(t, http.StatusOK, response.StatusCode) - assert.Equal(t, "application/json", response.Header.Get("Content-Type")) - assert.Equal(t, "gzip", response.Header.Get(httpclient.ContentEncodingHeader)) - - reader, err := gzip.NewReader(response.Body) - require.NoError(t, err) - - body, err := io.ReadAll(reader) - require.NoError(t, err) - - assert.Equal(t, `{"key": "value"}`, string(body)) - }) - - t.Run("deflate", func(t *testing.T) { - headers.Set(httpclient.ContentEncodingHeader, "deflate") - - response := rw.AsHTTPResponse(http.StatusOK, headers) - assert.Equal(t, http.StatusOK, response.StatusCode) - assert.Equal(t, "application/json", response.Header.Get("Content-Type")) - assert.Equal(t, "deflate", response.Header.Get(httpclient.ContentEncodingHeader)) - - reader := flate.NewReader(response.Body) - body, err := io.ReadAll(reader) - require.NoError(t, err) - - assert.Equal(t, `{"key": "value"}`, string(body)) - }) - }) -} - -func TestWithAdditionalHttpHeaders(t *testing.T) { - reqHeader := http.Header{ - http.CanonicalHeaderKey("X-Other-Key"): []string{"x-other-value"}, - http.CanonicalHeaderKey("Date"): []string{"date-value"}, - http.CanonicalHeaderKey("Host"): []string{"host-value"}, - http.CanonicalHeaderKey("Sec-WebSocket-Key"): []string{"sec-websocket-value"}, - http.CanonicalHeaderKey("User-Agent"): []string{"user-agent-value"}, - http.CanonicalHeaderKey("Content-Length"): []string{"content-length-value"}, - } - - t.Run("should add all headers to request without excluded keys", func(t *testing.T) { - internalExecutionCtx := &internalExecutionContext{ - resolveContext: &resolve.Context{ - Request: resolve.Request{ - Header: nil, - }, - }, - } - - optionsFn := WithAdditionalHttpHeaders(reqHeader) - optionsFn(internalExecutionCtx) - - assert.Equal(t, reqHeader, internalExecutionCtx.resolveContext.Request.Header) - }) - - t.Run("should only add headers that are not excluded", func(t *testing.T) { - internalExecutionCtx := &internalExecutionContext{ - resolveContext: &resolve.Context{ - Request: resolve.Request{ - Header: nil, - }, - }, - } - - excludableRuntimeHeaders := []string{ - http.CanonicalHeaderKey("Date"), - http.CanonicalHeaderKey("Host"), - http.CanonicalHeaderKey("Sec-WebSocket-Key"), - http.CanonicalHeaderKey("User-Agent"), - http.CanonicalHeaderKey("Content-Length"), - } - - optionsFn := WithAdditionalHttpHeaders(reqHeader, excludableRuntimeHeaders...) - optionsFn(internalExecutionCtx) - - expectedHeaders := http.Header{ - http.CanonicalHeaderKey("X-Other-Key"): []string{"x-other-value"}, - } - assert.Equal(t, expectedHeaders, internalExecutionCtx.resolveContext.Request.Header) - }) -} - -type ExecutionEngineV2TestCase struct { - schema *Schema - operation func(t *testing.T) Request - dataSources []plan.DataSourceConfiguration - generateChildrenForFirstRootField bool - fields plan.FieldConfigurations - engineOptions []ExecutionOptionsV2 - expectedResponse string - customResolveMap map[string]resolve.CustomResolve -} - -func TestExecutionEngineV2_Execute(t *testing.T) { - run := func(testCase ExecutionEngineV2TestCase, withError bool, expectedErrorMessage string) func(t *testing.T) { - t.Helper() - - return func(t *testing.T) { - t.Helper() - - engineConf := NewEngineV2Configuration(testCase.schema) - if testCase.generateChildrenForFirstRootField { - for i := 0; i < len(testCase.dataSources); i++ { - children := testCase.schema.GetAllNestedFieldChildrenFromTypeField(testCase.dataSources[i].RootNodes[0].TypeName, testCase.dataSources[i].RootNodes[0].FieldNames[0]) - testCase.dataSources[i].ChildNodes = make([]plan.TypeField, len(children)) - for j, child := range children { - testCase.dataSources[i].ChildNodes[j] = plan.TypeField{ - TypeName: child.TypeName, - FieldNames: child.FieldNames, - } - } - } - } - engineConf.SetDataSources(testCase.dataSources) - engineConf.SetFieldConfigurations(testCase.fields) - engineConf.SetCustomResolveMap(testCase.customResolveMap) - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - engine, err := NewExecutionEngineV2(ctx, abstractlogger.Noop{}, engineConf) - require.NoError(t, err) - - operation := testCase.operation(t) - resultWriter := NewEngineResultWriter() - execCtx, execCtxCancel := context.WithCancel(context.Background()) - defer execCtxCancel() - err = engine.Execute(execCtx, &operation, &resultWriter, testCase.engineOptions...) - - actualResponse := resultWriter.String() - assert.Equal(t, testCase.expectedResponse, actualResponse) - - if withError { - assert.Error(t, err) - if expectedErrorMessage != "" { - assert.Contains(t, err.Error(), expectedErrorMessage) - } - } else { - assert.NoError(t, err) - } - } - } - - runWithError := func(testCase ExecutionEngineV2TestCase) func(t *testing.T) { - return run(testCase, true, "") - } - - runWithAndCompareError := func(testCase ExecutionEngineV2TestCase, expectedErrorMessage string) func(t *testing.T) { - return run(testCase, true, expectedErrorMessage) - } - - runWithoutError := func(testCase ExecutionEngineV2TestCase) func(t *testing.T) { - return run(testCase, false, "") - } - - t.Run("execute with empty request object should not panic", runWithError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: func(t *testing.T) Request { - return Request{} - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{}, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: "", - }, - )) - - t.Run("unescape json", func(t *testing.T) { - schemaSDL := ` - scalar JSON - - schema { - query: Query - } - - type Query { - hero: Character! - } - - type Character { - info: JSON! - infos: [JSON!]! - } - ` - - operation := func(t *testing.T) Request { - return Request{ - OperationName: "", - Query: `query { hero {info infos} }`, - } - } - - datasourceCustomConfig := rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }) - - fieldConfigurations := []plan.FieldConfiguration{ - { - TypeName: "Character", - FieldName: "info", - UnescapeResponseJson: true, - }, - { - TypeName: "Character", - FieldName: "infos", - UnescapeResponseJson: true, - }, - } - - roundTripperRegularJson := roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"hero":{"info":{"name":"Luke Skywalker"},"infos":[{"name":"Luke Skywalker"}]}}`, - sendStatusCode: 200, - } - - roundTripperEncodedJson := roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"hero":{"info":"{\"name\":\"Luke Skywalker\"}","infos":["{\"name\":\"Luke Skywalker\"}"]}}`, - sendStatusCode: 200, - } - - schema, _ := NewSchemaFromString(schemaSDL) - - t.Run("with field configurations", func(t *testing.T) { - t.Run("regular json in response", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: operation, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperRegularJson), - }, - Custom: datasourceCustomConfig, - }, - }, - fields: fieldConfigurations, - expectedResponse: `{"data":{"hero":{"info":{"name":"Luke Skywalker"},"infos":[{"name":"Luke Skywalker"}]}}}`, - }, - )) - t.Run("encoded json in response", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: operation, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperEncodedJson), - }, - Custom: datasourceCustomConfig, - }, - }, - fields: fieldConfigurations, - expectedResponse: `{"data":{"hero":{"info":{"name":"Luke Skywalker"},"infos":[{"name":"Luke Skywalker"}]}}}`, - }, - )) - }) - - t.Run("without field configurations", func(t *testing.T) { - t.Run("regular json in response", runWithError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: operation, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperRegularJson), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - expectedResponse: ``, - }, - )) - - t.Run("encoded json in response", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: operation, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperEncodedJson), - }, - Custom: datasourceCustomConfig, - }, - }, - expectedResponse: `{"data":{"hero":{"info":"{\"name\":\"Luke Skywalker\"}","infos":["{\"name\":\"Luke Skywalker\"}"]}}}`, - }, - )) - }) - }) - - t.Run("introspection", func(t *testing.T) { - schema := starwarsSchema(t) - - t.Run("execute type introspection query", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: func(t *testing.T) Request { - return Request{ - OperationName: "myIntrospection", - Query: ` - query myIntrospection(){ - q: __type(name: "Query") { - name - kind - fields { - name - } - } - h: __type(name: "Human") { - name - fields { - name - } - } - } - `, - } - }, - expectedResponse: `{"data":{"q":{"name":"Query","kind":"OBJECT","fields":[{"name":"droid"},{"name":"search"},{"name":"searchResults"}]},"h":{"name":"Human","fields":[{"name":"name"},{"name":"friends"}]}}}`, - }, - )) - - t.Run("execute type introspection query for not existing type", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: func(t *testing.T) Request { - return Request{ - OperationName: "myIntrospection", - Query: ` - query myIntrospection(){ - __type(name: "NotExisting") { - name - kind - fields { - name - } - } - } - `, - } - }, - expectedResponse: `{"data":{"__type":null}}`, - }, - )) - - t.Run("execute type introspection query with deprecated fields", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: func(t *testing.T) Request { - return Request{ - OperationName: "myIntrospection", - Query: `query myIntrospection(){ - __type(name: "Query") { - name - kind - fields(includeDeprecated: true) { - name - } - } - }`, - } - }, - expectedResponse: `{"data":{"__type":{"name":"Query","kind":"OBJECT","fields":[{"name":"hero"},{"name":"droid"},{"name":"search"},{"name":"searchResults"}]}}}`, - }, - )) - - t.Run("execute full introspection query", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schema, - operation: func(t *testing.T) Request { - return requestForQuery(t, starwars.FileIntrospectionQuery) - }, - expectedResponse: `{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":{"name":"Mutation"},"subscriptionType":{"name":"Subscription"},"types":[{"kind":"UNION","name":"SearchResult","description":"","fields":null,"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[{"kind":"OBJECT","name":"Human","ofType":null},{"kind":"OBJECT","name":"Droid","ofType":null},{"kind":"OBJECT","name":"Starship","ofType":null}]},{"kind":"OBJECT","name":"Query","description":"","fields":[{"name":"hero","description":"","args":[],"type":{"kind":"INTERFACE","name":"Character","ofType":null},"isDeprecated":true,"deprecationReason":"No longer supported"},{"name":"droid","description":"","args":[{"name":"id","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Droid","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"search","description":"","args":[{"name":"name","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"defaultValue":null}],"type":{"kind":"UNION","name":"SearchResult","ofType":null},"isDeprecated":false,"deprecationReason":null},{"name":"searchResults","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"UNION","name":"SearchResult","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"OBJECT","name":"Mutation","description":"","fields":[{"name":"createReview","description":"","args":[{"name":"episode","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"ENUM","name":"Episode","ofType":null}},"defaultValue":null},{"name":"review","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"INPUT_OBJECT","name":"ReviewInput","ofType":null}},"defaultValue":null}],"type":{"kind":"OBJECT","name":"Review","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"OBJECT","name":"Subscription","description":"","fields":[{"name":"remainingJedis","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"INPUT_OBJECT","name":"ReviewInput","description":"","fields":null,"inputFields":[{"name":"stars","description":"","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"defaultValue":null},{"name":"commentary","description":"","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":null}],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"OBJECT","name":"Review","description":"","fields":[{"name":"id","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"ID","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"stars","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Int","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"commentary","description":"","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"ENUM","name":"Episode","description":"","fields":null,"inputFields":[],"interfaces":[],"enumValues":[{"name":"NEWHOPE","description":"","isDeprecated":false,"deprecationReason":null},{"name":"EMPIRE","description":"","isDeprecated":false,"deprecationReason":null},{"name":"JEDI","description":"","isDeprecated":true,"deprecationReason":"No longer supported"}],"possibleTypes":[]},{"kind":"INTERFACE","name":"Character","description":"","fields":[{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"friends","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"INTERFACE","name":"Character","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[{"kind":"OBJECT","name":"Human","ofType":null},{"kind":"OBJECT","name":"Droid","ofType":null}]},{"kind":"OBJECT","name":"Human","description":"","fields":[{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"height","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":true,"deprecationReason":"No longer supported"},{"name":"friends","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"INTERFACE","name":"Character","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[{"kind":"INTERFACE","name":"Character","ofType":null}],"enumValues":null,"possibleTypes":[]},{"kind":"OBJECT","name":"Droid","description":"","fields":[{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"primaryFunction","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"friends","description":"","args":[],"type":{"kind":"LIST","name":null,"ofType":{"kind":"INTERFACE","name":"Character","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[{"kind":"INTERFACE","name":"Character","ofType":null}],"enumValues":null,"possibleTypes":[]},{"kind":"INTERFACE","name":"Vehicle","description":"","fields":[{"name":"length","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Float","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[{"kind":"OBJECT","name":"Starship","ofType":null}]},{"kind":"OBJECT","name":"Starship","description":"","fields":[{"name":"name","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"String","ofType":null}},"isDeprecated":false,"deprecationReason":null},{"name":"length","description":"","args":[],"type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Float","ofType":null}},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[{"kind":"INTERFACE","name":"Vehicle","ofType":null}],"enumValues":null,"possibleTypes":[]},{"kind":"SCALAR","name":"Int","description":"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.","fields":null,"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"SCALAR","name":"Float","description":"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).","fields":null,"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"SCALAR","name":"String","description":"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.","fields":null,"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"SCALAR","name":"Boolean","description":"The 'Boolean' scalar type represents 'true' or 'false' .","fields":null,"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]},{"kind":"SCALAR","name":"ID","description":"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID.","fields":null,"inputFields":[],"interfaces":[],"enumValues":null,"possibleTypes":[]}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"skip","description":"Directs the executor to skip this field or fragment when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}]},{"name":"deprecated","description":"Marks an element of a GraphQL schema as no longer supported.","locations":["FIELD_DEFINITION","ENUM_VALUE"],"args":[{"name":"reason","description":"Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"\"No longer supported\""}]}]}}}`, - }, - )) - }) - - t.Run("execute simple hero operation with rest data source", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil), - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"hero": {"name": "Luke Skywalker"}}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - }, - )) - - t.Run("execute with header injection", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: func(t *testing.T) Request { - request := loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil)(t) - request.request.Header = map[string][]string{ - "Authorization": {"foo"}, - } - return request - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/foo", - expectedBody: "", - sendResponseBody: `{"hero": {"name": "Luke Skywalker"}}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/{{ .request.headers.Authorization }}", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - }, - )) - - t.Run("execute with additional headers", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: func(t *testing.T) Request { - request := loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil)(t) - return request - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/foo", - expectedBody: "", - sendResponseBody: `{"hero": {"name": "Luke Skywalker"}}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/{{ .request.headers.X-Other-Header }}", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - engineOptions: []ExecutionOptionsV2{ - WithAdditionalHttpHeaders(http.Header{ - "X-Other-Header": []string{"foo"}, - }), - }, - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - }, - )) - - t.Run("execute with .object and .arguments placeholder", runWithoutError( - ExecutionEngineV2TestCase{ - schema: func(t *testing.T) *Schema { - t.Helper() - schema := ` - type Query { - getPet(id: ID, metadata: APIMetadata): Pet - countries: [Country] - } - - input APIMetadata { - version: String! - } - - type Country { - name: String - } - - type Pet { - id: Int - name: String - status: String - country: Country - } - - type Mutation { - createPet(id: Int, name: String, status: String): Pet - }` - parseSchema, err := NewSchemaFromString(schema) - assert.NoError(t, err) - return parseSchema - }(t), - operation: func(t *testing.T) Request { - t.Helper() - return Request{ - OperationName: "MyQuery", - Query: ` - query MyQuery($metadata: APIMetadata) { - getPet(id: 1, metadata: $metadata) { - id - name - country { - name - } - } - } - `, - Variables: []byte(`{"metadata":{"version":"v2"}}`), - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"getPet"}}, - }, - ChildNodes: []plan.TypeField{ - {TypeName: "Pet", FieldNames: []string{"id", "name", "status"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "petstore.swagger.io", - expectedPath: "/v2/pet/1", - expectedBody: "", - sendResponseBody: `{"id":1,"category":{"id":1,"name":"dog"},"name":"doggie"}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://petstore.swagger.io/{{.arguments.metadata.version}}/pet/{{.arguments.id}}", - Method: "GET", - }, - }), - }, - { - RootNodes: []plan.TypeField{ - {TypeName: "Pet", FieldNames: []string{"country"}}, - }, - ChildNodes: []plan.TypeField{ - {TypeName: "Country", FieldNames: []string{"name"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "rest-countries.example.com", - expectedPath: "/type/1-dog/name/doggie", - expectedBody: "", - sendResponseBody: `{"name":"Germany"}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://rest-countries.example.com/type/{{.object.category.id}}-{{.object.category.name}}/name/{{.object.name}}", - Method: "POST", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "getPet", - DisableDefaultMapping: true, - Path: []string{""}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "metadata", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Pet", - FieldName: "country", - DisableDefaultMapping: true, - Path: []string{""}, - }, - }, - expectedResponse: `{"data":{"getPet":{"id":1,"name":"doggie","country":{"name":"Germany"}}}}`, - }, - )) - - t.Run("execute simple hero operation with graphql data source", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil), - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"hero"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - }, - )) - - t.Run("execute the correct operation when sending multiple queries", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: func(t *testing.T) Request { - request := loadStarWarsQuery(starwars.FileMultiQueries, nil)(t) - request.OperationName = "SingleHero" - return request - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"hero"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - }, - )) - - schemaWithCustomScalar, _ := NewSchemaFromString(string(` - scalar Long - type Asset { - id: Long! - } - type Query { - asset: Asset - } - `)) - t.Run("query with custom scalar", runWithoutError( - ExecutionEngineV2TestCase{ - schema: schemaWithCustomScalar, - operation: func(t *testing.T) Request { - request := Request{} - body := execution.GraphqlRequest{ - Query: `{asset{id}}`, - OperationName: "", - Variables: nil, - } - jsonBytes, _ := json.Marshal(body) - err := UnmarshalRequest(bytes.NewBuffer(jsonBytes), &request) - require.NoError(t, err) - return request - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"asset"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Asset", - FieldNames: []string{"id"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"asset":{"id":1}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - customResolveMap: map[string]resolve.CustomResolve{ - "Long": &customResolver{}, - }, - expectedResponse: `{"data":{"asset":{"id":1}}}`, - }, - )) - - t.Run("execute operation with variables for arguments", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: loadStarWarsQuery(starwars.FileDroidWithArgAndVarQuery, map[string]interface{}{"droidID": "R2D2"}), - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Droid", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"droid":{"name":"R2D2"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Path: []string{"droid"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - RenderConfig: plan.RenderArgumentAsGraphQLValue, - }, - }, - }, - }, - expectedResponse: `{"data":{"droid":{"name":"R2D2"}}}`, - }, - )) - - t.Run("execute operation with array input type", runWithoutError(ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "MyHeroes", - Variables: stringify(map[string]interface{}{ - "heroNames": []string{"Luke Skywalker", "R2-D2"}, - }), - Query: `query MyHeroes($heroNames: [String!]!){ - heroes(names: $heroNames) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"heroes"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($heroNames: [String!]!){heroes(names: $heroNames)}","variables":{"heroNames":["Luke Skywalker","R2-D2"]}}`, - sendResponseBody: `{"data":{"heroes":["Human","Droid"]}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "POST", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "heroes", - Path: []string{"heroes"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "names", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: `{"data":{"heroes":["Human","Droid"]}}`, - })) - - t.Run("execute operation with null and omitted input variables", runWithoutError(ExecutionEngineV2TestCase{ - schema: func(t *testing.T) *Schema { - t.Helper() - schema := ` - type Query { - heroes(names: [String!], height: String): [String!] - }` - parseSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - return parseSchema - }(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "MyHeroes", - Variables: []byte(`{"height": null}`), - Query: `query MyHeroes($heroNames: [String!], $height: String){ - heroes(names: $heroNames, height: $height) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"heroes"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($heroNames: [String!], $height: String){heroes(names: $heroNames, height: $height)}","variables":{"height":null}}`, - sendResponseBody: `{"data":{"heroes":[]}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "POST", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "heroes", - Path: []string{"heroes"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "names", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "height", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: `{"data":{"heroes":[]}}`, - })) - - t.Run("execute operation with null variable on required type", runWithError(ExecutionEngineV2TestCase{ - schema: func(t *testing.T) *Schema { - t.Helper() - schema := ` - type Query { - hero(name: String!): String! - }` - parseSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - return parseSchema - }(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "MyHero", - Variables: []byte(`{"heroName": null}`), - Query: `query MyHero($heroName: String!){ - hero(name: $heroName) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &graphql_datasource.Factory{}, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "POST", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - Path: []string{"hero"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: ``, - })) - - t.Run("execute operation and apply input coercion for lists without variables", runWithoutError(ExecutionEngineV2TestCase{ - schema: inputCoercionForListSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "", - Variables: stringify(map[string]interface{}{}), - Query: `query{ - charactersByIds(ids: 1) { - name - } - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"charactersByIds"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($a: [Int]){charactersByIds(ids: $a){name}}","variables":{"a":[1]}}`, - sendResponseBody: `{"data":{"charactersByIds":[{"name": "Luke"}]}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "POST", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "charactersByIds", - Path: []string{"charactersByIds"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "ids", - SourceType: plan.FieldArgumentSource, - RenderConfig: plan.RenderArgumentAsGraphQLValue, - }, - }, - }, - }, - expectedResponse: `{"data":{"charactersByIds":[{"name":"Luke"}]}}`, - })) - - t.Run("execute operation and apply input coercion for lists with variable extraction", runWithoutError(ExecutionEngineV2TestCase{ - schema: inputCoercionForListSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "", - Variables: stringify(map[string]interface{}{ - "ids": 1, - }), - Query: `query($ids: [Int]) { charactersByIds(ids: $ids) { name } }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"charactersByIds"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($ids: [Int]){charactersByIds(ids: $ids){name}}","variables":{"ids":[1]}}`, - sendResponseBody: `{"data":{"charactersByIds":[{"name": "Luke"}]}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "POST", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "charactersByIds", - Path: []string{"charactersByIds"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "ids", - SourceType: plan.FieldArgumentSource, - RenderConfig: plan.RenderArgumentAsGraphQLValue, - }, - }, - }, - }, - expectedResponse: `{"data":{"charactersByIds":[{"name":"Luke"}]}}`, - })) - - t.Run("execute operation with arguments", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: loadStarWarsQuery(starwars.FileDroidWithArgQuery, nil), - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Droid", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"droid":{"name":"R2D2"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - RenderConfig: plan.RenderArgumentAsGraphQLValue, - }, - }, - }, - }, - expectedResponse: `{"data":{"droid":{"name":"R2D2"}}}`, - }, - )) - - t.Run("execute operation with default arguments", func(t *testing.T) { - t.Run("query variables with default value", runWithoutError( - ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "queryVariables", - Variables: nil, - Query: `query queryVariables($name: String! = "R2D2", $nameOptional: String = "R2D2") { - hero(name: $name) - hero2: hero(name: $nameOptional) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($name: String!, $nameOptional: String){hero(name: $name) hero2: hero(name: $nameOptional)}","variables":{"nameOptional":"R2D2","name":"R2D2"}}`, - sendResponseBody: `{"data":{"hero":"R2D2","hero2":"R2D2"}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - Path: []string{"hero"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: `{"data":{"hero":"R2D2","hero2":"R2D2"}}`, - }, - )) - - t.Run("query variables with default value when args provided", runWithoutError( - ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "queryVariables", - Variables: stringify(map[string]interface{}{ - "name": "Luke", - "nameOptional": "Skywalker", - }), - Query: `query queryVariables($name: String! = "R2D2", $nameOptional: String = "R2D2") { - hero(name: $name) - hero2: hero(name: $nameOptional) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($name: String!, $nameOptional: String){hero(name: $name) hero2: hero(name: $nameOptional)}","variables":{"nameOptional":"Skywalker","name":"Luke"}}`, - sendResponseBody: `{"data":{"hero":"R2D2","hero2":"R2D2"}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - Path: []string{"hero"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: `{"data":{"hero":"R2D2","hero2":"R2D2"}}`, - }, - )) - - t.Run("query variables with default values for fields with required and optional args", runWithoutError( - ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "queryVariables", - Variables: nil, - Query: `query queryVariables($name: String! = "R2D2", $nameOptional: String = "R2D2") { - hero: heroDefault(name: $name) - hero2: heroDefault(name: $nameOptional) - hero3: heroDefaultRequired(name: $name) - hero4: heroDefaultRequired(name: $nameOptional) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"heroDefault", "heroDefaultRequired"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($name: String!, $nameOptional: String!){hero: heroDefault(name: $name) hero2: heroDefault(name: $nameOptional) hero3: heroDefaultRequired(name: $name) hero4: heroDefaultRequired(name: $nameOptional)}","variables":{"nameOptional":"R2D2","name":"R2D2"}}`, - sendResponseBody: `{"data":{"hero":"R2D2","hero2":"R2D2","hero3":"R2D2","hero4":"R2D2"}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "heroDefault", - Path: []string{"heroDefault"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "heroDefaultRequired", - Path: []string{"heroDefaultRequired"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: `{"data":{"hero":"R2D2","hero2":"R2D2","hero3":"R2D2","hero4":"R2D2"}}`, - }, - )) - - t.Run("query fields with default value", runWithoutError( - ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "fieldArgs", - Variables: nil, - Query: `query fieldArgs { - heroDefault - heroDefaultRequired - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"heroDefault", "heroDefaultRequired"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"query($a: String, $b: String!){heroDefault(name: $a) heroDefaultRequired(name: $b)}","variables":{"b":"AnyRequired","a":"Any"}}`, - sendResponseBody: `{"data":{"heroDefault":"R2D2","heroDefaultRequired":"R2D2"}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "heroDefault", - Path: []string{"heroDefault"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Query", - FieldName: "heroDefaultRequired", - Path: []string{"heroDefaultRequired"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }, - expectedResponse: `{"data":{"heroDefault":"R2D2","heroDefaultRequired":"R2D2"}}`, - }, - )) - - }) - - t.Run("execute query with data source on field with interface return type", runWithoutError( - ExecutionEngineV2TestCase{ - schema: createCountriesSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "", - Variables: nil, - Query: `{ codeType { code ...on Country { name } } }`, - } - }, - generateChildrenForFirstRootField: true, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"codeType"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{"query":"{codeType {code __typename ... on Country {name}}}"}`, - sendResponseBody: `{"data":{"codeType":{"__typename":"Country","code":"de","name":"Germany"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"codeType":{"code":"de","name":"Germany"}}}`, - }, - )) - - t.Run("execute single mutation with arguments on document with multiple operations", runWithoutError( - ExecutionEngineV2TestCase{ - schema: moviesSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "AddWithInput", - Variables: nil, - Query: `mutation AddToWatchlist { - addToWatchlist(movieID:3) { - id - name - year - } - } - - - mutation AddWithInput { - addToWatchlistWithInput(input: {id: 2}) { - id - name - year - } - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Mutation", FieldNames: []string{"addToWatchlistWithInput"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"added_movie":{"id":2, "name": "Episode V – The Empire Strikes Back", "year": 1980}}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "addToWatchlistWithInput", - DisableDefaultMapping: false, - Path: []string{"added_movie"}, - }, - }, - expectedResponse: `{"data":{"addToWatchlistWithInput":{"id":2,"name":"Episode V – The Empire Strikes Back","year":1980}}}`, - }, - )) - - t.Run("execute operation with rest data source and arguments", runWithoutError( - ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "MyHero", - Variables: stringify(map[string]interface{}{ - "heroName": "Luke Skywalker", - }), - Query: `query MyHero($heroName: String){ - hero(name: $heroName) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: `{ "name": "Luke Skywalker" }`, - sendResponseBody: `{"race": "Human"}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "POST", - Body: `{ "name": {{ .arguments.name }} }`, - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - DisableDefaultMapping: false, - Path: []string{"race"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - RenderConfig: plan.RenderArgumentAsJSONValue, - }, - }, - }, - }, - expectedResponse: `{"data":{"hero":"Human"}}`, - }, - )) - - t.Run("execute operation with rest data source and arguments in url", runWithoutError( - ExecutionEngineV2TestCase{ - schema: heroWithArgumentSchema(t), - operation: func(t *testing.T) Request { - return Request{ - OperationName: "MyHero", - Variables: stringify(map[string]interface{}{ - "heroName": "luke", - }), - Query: `query MyHero($heroName: String){ - hero(name: $heroName) - }`, - } - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hero"}}, - }, - Factory: &rest_datasource.Factory{ - Client: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/name/luke", - expectedBody: "", - sendResponseBody: `{"race": "Human"}`, - sendStatusCode: 200, - }), - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: "https://example.com/name/{{ .arguments.name }}", - Method: "POST", - Body: "", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hero", - DisableDefaultMapping: false, - Path: []string{"race"}, - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - RenderConfig: plan.RenderArgumentDefault, - }, - }, - }, - }, - expectedResponse: `{"data":{"hero":"Human"}}`, - }, - )) - - t.Run("Spreading a fragment on an invalid type returns ErrInvalidFragmentSpread", runWithAndCompareError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: loadStarWarsQuery(starwars.FileInvalidFragmentsQuery, nil), - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"droid"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Droid", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"droid":{"name":"R2D2"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "droid", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "id", - SourceType: plan.FieldArgumentSource, - RenderConfig: plan.RenderArgumentAsGraphQLValue, - }, - }, - }, - }, - expectedResponse: ``, - }, - "fragment spread: fragment reviewFields must be spread on type Review and not type Droid", - )) - - t.Run("execute the correct operation when sending multiple queries", runWithoutError( - ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: func(t *testing.T) Request { - request := loadStarWarsQuery(starwars.FileInterfaceFragmentsOnUnion, nil)(t) - request.OperationName = "SearchResults" - return request - }, - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"searchResults"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name"}, - }, - { - TypeName: "Vehicle", - FieldNames: []string{"length"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"searchResults":[{"name"":"Luke Skywalker"},{"length":13.37}]}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"searchResults":null}}`, - }, - )) -} - -func testNetHttpClient(t *testing.T, testCase roundTripperTestCase) *http.Client { - defaultClient := httpclient.DefaultNetHttpClient - return &http.Client{ - Transport: createTestRoundTripper(t, testCase), - CheckRedirect: defaultClient.CheckRedirect, - Jar: defaultClient.Jar, - Timeout: defaultClient.Timeout, - } -} - -type beforeFetchHook struct { - input string -} - -func (b *beforeFetchHook) OnBeforeFetch(_ resolve.HookContext, input []byte) { - b.input += string(input) -} - -type afterFetchHook struct { - data string - err string -} - -func (a *afterFetchHook) OnData(_ resolve.HookContext, output []byte, _ bool) { - a.data += string(output) -} - -func (a *afterFetchHook) OnError(_ resolve.HookContext, output []byte, _ bool) { - a.err += string(output) -} - -func TestExecutionWithOptions(t *testing.T) { - - closer := make(chan struct{}) - defer close(closer) - - testCase := ExecutionEngineV2TestCase{ - schema: starwarsSchema(t), - operation: loadStarWarsQuery(starwars.FileSimpleHeroQuery, nil), - dataSources: []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"hero"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Character", - FieldNames: []string{"name"}, - }, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: testNetHttpClient(t, roundTripperTestCase{ - expectedHost: "example.com", - expectedPath: "/", - expectedBody: "", - sendResponseBody: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - sendStatusCode: 200, - }), - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: "https://example.com/", - Method: "GET", - }, - }), - }, - }, - fields: []plan.FieldConfiguration{}, - expectedResponse: `{"data":{"hero":{"name":"Luke Skywalker"}}}`, - } - - engineConf := NewEngineV2Configuration(testCase.schema) - engineConf.SetDataSources(testCase.dataSources) - engineConf.SetFieldConfigurations(testCase.fields) - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - engine, err := NewExecutionEngineV2(ctx, abstractlogger.Noop{}, engineConf) - require.NoError(t, err) - - before := &beforeFetchHook{} - after := &afterFetchHook{} - - operation := testCase.operation(t) - resultWriter := NewEngineResultWriter() - err = engine.Execute(context.Background(), &operation, &resultWriter, WithBeforeFetchHook(before), WithAfterFetchHook(after)) - - assert.Equal(t, `{"method":"GET","url":"https://example.com/","body":{"query":"{hero {name}}"}}`, before.input) - assert.Equal(t, `{"hero":{"name":"Luke Skywalker"}}`, after.data) - assert.Equal(t, "", after.err) - assert.NoError(t, err) -} - -func TestExecutionEngineV2_GetCachedPlan(t *testing.T) { - schema, err := NewSchemaFromString(testSubscriptionDefinition) - require.NoError(t, err) - - gqlRequest := Request{ - OperationName: "LastRegisteredUser", - Variables: nil, - Query: testSubscriptionLastRegisteredUserOperation, - } - - validationResult, err := gqlRequest.ValidateForSchema(schema) - require.NoError(t, err) - require.True(t, validationResult.Valid) - - normalizationResult, err := gqlRequest.Normalize(schema) - require.NoError(t, err) - require.True(t, normalizationResult.Successful) - - differentGqlRequest := Request{ - OperationName: "LiveUserCount", - Variables: nil, - Query: testSubscriptionLiveUserCountOperation, - } - - validationResult, err = differentGqlRequest.ValidateForSchema(schema) - require.NoError(t, err) - require.True(t, validationResult.Valid) - - normalizationResult, err = differentGqlRequest.Normalize(schema) - require.NoError(t, err) - require.True(t, normalizationResult.Successful) - - engineConfig := NewEngineV2Configuration(schema) - engineConfig.SetDataSources([]plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "Subscription", - FieldNames: []string{"lastRegisteredUser", "liveUserCount"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "username", "email"}, - }, - }, - Factory: &graphql_datasource.Factory{}, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Subscription: graphql_datasource.SubscriptionConfiguration{ - URL: "http://localhost:8080", - }, - }), - }, - }) - - engine, err := NewExecutionEngineV2(context.Background(), abstractlogger.NoopLogger, engineConfig) - require.NoError(t, err) - - t.Run("should reuse cached plan", func(t *testing.T) { - t.Cleanup(engine.executionPlanCache.Purge) - require.Equal(t, 0, engine.executionPlanCache.Len()) - - firstInternalExecCtx := newInternalExecutionContext() - firstInternalExecCtx.resolveContext.Request.Header = http.Header{ - http.CanonicalHeaderKey("Authorization"): []string{"123abc"}, - } - - report := operationreport.Report{} - cachedPlan := engine.getCachedPlan(firstInternalExecCtx, &gqlRequest.document, &schema.document, gqlRequest.OperationName, &report) - _, oldestCachedPlan, _ := engine.executionPlanCache.GetOldest() - assert.False(t, report.HasErrors()) - assert.Equal(t, 1, engine.executionPlanCache.Len()) - assert.Equal(t, cachedPlan, oldestCachedPlan.(*plan.SubscriptionResponsePlan)) - - secondInternalExecCtx := newInternalExecutionContext() - secondInternalExecCtx.resolveContext.Request.Header = http.Header{ - http.CanonicalHeaderKey("Authorization"): []string{"123abc"}, - } - - cachedPlan = engine.getCachedPlan(secondInternalExecCtx, &gqlRequest.document, &schema.document, gqlRequest.OperationName, &report) - _, oldestCachedPlan, _ = engine.executionPlanCache.GetOldest() - assert.False(t, report.HasErrors()) - assert.Equal(t, 1, engine.executionPlanCache.Len()) - assert.Equal(t, cachedPlan, oldestCachedPlan.(*plan.SubscriptionResponsePlan)) - }) - - t.Run("should create new plan and cache it", func(t *testing.T) { - t.Cleanup(engine.executionPlanCache.Purge) - require.Equal(t, 0, engine.executionPlanCache.Len()) - - firstInternalExecCtx := newInternalExecutionContext() - firstInternalExecCtx.resolveContext.Request.Header = http.Header{ - http.CanonicalHeaderKey("Authorization"): []string{"123abc"}, - } - - report := operationreport.Report{} - cachedPlan := engine.getCachedPlan(firstInternalExecCtx, &gqlRequest.document, &schema.document, gqlRequest.OperationName, &report) - _, oldestCachedPlan, _ := engine.executionPlanCache.GetOldest() - assert.False(t, report.HasErrors()) - assert.Equal(t, 1, engine.executionPlanCache.Len()) - assert.Equal(t, cachedPlan, oldestCachedPlan.(*plan.SubscriptionResponsePlan)) - - secondInternalExecCtx := newInternalExecutionContext() - secondInternalExecCtx.resolveContext.Request.Header = http.Header{ - http.CanonicalHeaderKey("Authorization"): []string{"xyz098"}, - } - - cachedPlan = engine.getCachedPlan(secondInternalExecCtx, &differentGqlRequest.document, &schema.document, differentGqlRequest.OperationName, &report) - _, oldestCachedPlan, _ = engine.executionPlanCache.GetOldest() - assert.False(t, report.HasErrors()) - assert.Equal(t, 2, engine.executionPlanCache.Len()) - assert.NotEqual(t, cachedPlan, oldestCachedPlan.(*plan.SubscriptionResponsePlan)) - }) -} - -func BenchmarkExecutionEngineV2(b *testing.B) { - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - type benchCase struct { - engine *ExecutionEngineV2 - writer *EngineResultWriter - } - - newEngine := func() *ExecutionEngineV2 { - schema, err := NewSchemaFromString(`type Query { hello: String}`) - require.NoError(b, err) - - engineConf := NewEngineV2Configuration(schema) - engineConf.SetDataSources([]plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"hello"}}, - }, - Factory: &staticdatasource.Factory{}, - Custom: staticdatasource.ConfigJSON(staticdatasource.Configuration{ - Data: "world", - }), - }, - }) - engineConf.SetFieldConfigurations([]plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "hello", - DisableDefaultMapping: true, - }, - }) - - engine, err := NewExecutionEngineV2(ctx, abstractlogger.NoopLogger, engineConf) - require.NoError(b, err) - - return engine - } - - newBenchCase := func() *benchCase { - writer := NewEngineResultWriter() - return &benchCase{ - engine: newEngine(), - writer: &writer, - } - } - - ctx = context.Background() - req := Request{ - Query: "{hello}", - } - - writer := NewEngineResultWriter() - engine := newEngine() - require.NoError(b, engine.Execute(ctx, &req, &writer)) - require.Equal(b, "{\"data\":{\"hello\":\"world\"}}", writer.String()) - - pool := sync.Pool{ - New: func() interface{} { - return newBenchCase() - }, - } - - b.SetBytes(int64(writer.Len())) - b.ResetTimer() - b.ReportAllocs() - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - bc := pool.Get().(*benchCase) - bc.writer.Reset() - _ = bc.engine.Execute(ctx, &req, bc.writer) - pool.Put(bc) - } - }) - -} - -type federationSetup struct { - accountsUpstreamServer *httptest.Server - productsUpstreamServer *httptest.Server - reviewsUpstreamServer *httptest.Server - pollingUpstreamServer *httptest.Server -} - -func newFederationSetup() *federationSetup { - return &federationSetup{ - accountsUpstreamServer: httptest.NewServer(accounts.GraphQLEndpointHandler(accounts.TestOptions)), - productsUpstreamServer: httptest.NewServer(products.GraphQLEndpointHandler(products.TestOptions)), - reviewsUpstreamServer: httptest.NewServer(reviews.GraphQLEndpointHandler(reviews.TestOptions)), - pollingUpstreamServer: httptest.NewServer(newPollingUpstreamHandler()), - } -} - -func newFederationEngine(ctx context.Context, setup *federationSetup, enableDataLoader bool) (engine *ExecutionEngineV2, schema *Schema, err error) { - accountsSDL, err := federationtesting.LoadSDLFromExamplesDirectoryWithinPkg(federationtesting.UpstreamAccounts) - if err != nil { - return - } - - productsSDL, err := federationtesting.LoadSDLFromExamplesDirectoryWithinPkg(federationtesting.UpstreamProducts) - if err != nil { - return - } - - reviewsSDL, err := federationtesting.LoadSDLFromExamplesDirectoryWithinPkg(federationtesting.UpstreamReviews) - if err != nil { - return - } - - batchFactory := graphql_datasource.NewBatchFactory() - - accountsDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"me"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "name", "username"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"id", "name", "username"}, - }, - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: setup.accountsUpstreamServer.URL, - Method: http.MethodPost, - }, - Federation: graphql_datasource.FederationConfiguration{ - Enabled: true, - ServiceSDL: string(accountsSDL), - }, - }), - Factory: &graphql_datasource.Factory{ - BatchFactory: batchFactory, - HTTPClient: httpclient.DefaultNetHttpClient, - }, - } - - productsDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "Query", - FieldNames: []string{"topProducts"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price", "weight"}, - }, - { - TypeName: "Subscription", - FieldNames: []string{"updatedPrice"}, - }, - { - TypeName: "Mutation", - FieldNames: []string{"setPrice"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Product", - FieldNames: []string{"upc", "name", "price", "weight"}, - }, - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: setup.productsUpstreamServer.URL, - Method: http.MethodPost, - }, - Subscription: graphql_datasource.SubscriptionConfiguration{ - URL: setup.productsUpstreamServer.URL, - }, - Federation: graphql_datasource.FederationConfiguration{ - Enabled: true, - ServiceSDL: string(productsSDL), - }, - }), - Factory: &graphql_datasource.Factory{ - BatchFactory: batchFactory, - HTTPClient: httpclient.DefaultNetHttpClient, - }, - } - - reviewsDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "User", - FieldNames: []string{"reviews"}, - }, - { - TypeName: "Product", - FieldNames: []string{"reviews"}, - }, - }, - ChildNodes: []plan.TypeField{ - { - TypeName: "Review", - FieldNames: []string{"id", "body", "author", "product"}, - }, - { - TypeName: "User", - FieldNames: []string{"id", "username", "reviews"}, - }, - { - TypeName: "Product", - FieldNames: []string{"upc", "reviews"}, - }, - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: setup.reviewsUpstreamServer.URL, - Method: http.MethodPost, - }, - Subscription: graphql_datasource.SubscriptionConfiguration{ - URL: setup.reviewsUpstreamServer.URL, - }, - Federation: graphql_datasource.FederationConfiguration{ - Enabled: true, - ServiceSDL: string(reviewsSDL), - }, - }), - Factory: &graphql_datasource.Factory{ - BatchFactory: batchFactory, - HTTPClient: httpclient.DefaultNetHttpClient, - }, - } - - pollingDataSource := plan.DataSourceConfiguration{ - RootNodes: []plan.TypeField{ - { - TypeName: "Subscription", - FieldNames: []string{"counter"}, - }, - }, - ChildNodes: nil, - Factory: &rest_datasource.Factory{ - Client: httpclient.DefaultNetHttpClient, - }, - Custom: rest_datasource.ConfigJSON(rest_datasource.Configuration{ - Fetch: rest_datasource.FetchConfiguration{ - URL: setup.pollingUpstreamServer.URL, - Method: http.MethodPost, - }, - Subscription: rest_datasource.SubscriptionConfiguration{ - PollingIntervalMillis: 10, - SkipPublishSameResponse: true, - }, - }), - } - - fieldConfigs := plan.FieldConfigurations{ - { - TypeName: "User", - FieldName: "name", - RequiresFields: []string{"id"}, - }, - { - TypeName: "User", - FieldName: "username", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Product", - FieldName: "name", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product", - FieldName: "price", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Product", - FieldName: "weight", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "User", - FieldName: "reviews", - RequiresFields: []string{"id"}, - }, - { - TypeName: "Product", - FieldName: "reviews", - RequiresFields: []string{"upc"}, - }, - { - TypeName: "Query", - FieldName: "topProducts", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "first", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Mutation", - FieldName: "setPrice", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "upc", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "price", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - } - - schema, err = federationSchema() - if err != nil { - return - } - - engineConfig := NewEngineV2Configuration(schema) - engineConfig.AddDataSource(accountsDataSource) - engineConfig.AddDataSource(productsDataSource) - engineConfig.AddDataSource(reviewsDataSource) - engineConfig.AddDataSource(pollingDataSource) - engineConfig.SetFieldConfigurations(fieldConfigs) - engineConfig.EnableDataLoader(enableDataLoader) - - engine, err = NewExecutionEngineV2(ctx, abstractlogger.Noop{}, engineConfig) - if err != nil { - return - } - - return -} - -// nolint -func federationSchema() (*Schema, error) { - rawSchema := ` -type Query { - me: User - topProducts(first: Int = 5): [Product] -} - -type Mutation { - setPrice(upc: String!, price: Int!): Product -} - -type Subscription { - updatedPrice: Product! - counter: Int! -} - -type User { - id: ID! - name: String - username: String - reviews: [Review] -} - -type Product { - upc: String! - name: String - price: Int - weight: Int - reviews: [Review] -} - -type Review { - id: ID! - body: String - author: User - product: Product -} -` - - return NewSchemaFromString(rawSchema) -} - -func newPollingUpstreamHandler() http.Handler { - counter := 0 - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - counter++ - respBody := fmt.Sprintf(`{"counter":%d}`, counter) - _, _ = w.Write([]byte(respBody)) - }) -} - -func createCountriesSchema(t *testing.T) *Schema { - schema, err := NewSchemaFromString(countriesSchema) - require.NoError(t, err) - return schema -} diff --git a/pkg/graphql/extractor.go b/pkg/graphql/extractor.go deleted file mode 100644 index 7d8f73b9b..000000000 --- a/pkg/graphql/extractor.go +++ /dev/null @@ -1,66 +0,0 @@ -package graphql - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type Extractor struct { - walker *astvisitor.Walker - visitor *requestVisitor -} - -func NewExtractor() *Extractor { - walker := astvisitor.NewWalker(48) - visitor := requestVisitor{ - Walker: &walker, - } - - walker.RegisterEnterFieldVisitor(&visitor) - - return &Extractor{ - walker: &walker, - visitor: &visitor, - } -} - -func (e *Extractor) ExtractFieldsFromRequest(request *Request, schema *Schema, report *operationreport.Report, data RequestTypes) { - if !request.IsNormalized() { - result, err := request.Normalize(schema) - if err != nil { - report.AddInternalError(err) - } - - if !result.Successful { - report.AddInternalError(result.Errors) - } - } - - e.visitor.data = data - e.visitor.operation = &request.document - e.visitor.definition = &schema.document - e.walker.Walk(&request.document, &schema.document, report) -} - -type requestVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - data RequestTypes -} - -func (p *requestVisitor) EnterField(ref int) { - fieldName := p.operation.FieldNameString(ref) - parentTypeName := p.definition.NodeNameString(p.EnclosingTypeDefinition) - - t, ok := p.data[parentTypeName] - if !ok { - t = make(RequestFields) - } - - if _, ok := t[fieldName]; !ok { - t[fieldName] = struct{}{} - } - - p.data[parentTypeName] = t -} diff --git a/pkg/graphql/extractor_test.go b/pkg/graphql/extractor_test.go deleted file mode 100644 index dd9462b77..000000000 --- a/pkg/graphql/extractor_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package graphql - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestExtractor_ExtractFieldsFromRequest(t *testing.T) { - schema, err := NewSchemaFromString(testDefinition) - require.NoError(t, err) - - request := Request{ - OperationName: "PostsUserQuery", - Variables: nil, - Query: testOperation, - } - - fields := make(RequestTypes) - report := operationreport.Report{} - NewExtractor().ExtractFieldsFromRequest(&request, schema, &report, fields) - - expectedFields := RequestTypes{ - "Foo": {"fooField": {}}, - "Post": {"description": {}, "id": {}, "user": {}}, - "Query": {"foo": {}, "posts": {}}, - "User": {"id": {}, "name": {}}, - } - - assert.False(t, report.HasErrors()) - assert.Equal(t, expectedFields, fields) -} - -const testOperation = `query PostsUserQuery { - posts { - id - description - user { - id - name - } - } -} -fragment FirstFragment on Post { - id -} -query ArgsQuery { - foo(bar: "barValue", baz: true){ - fooField - } -} -query VariableQuery($bar: String, $baz: Boolean) { - foo(bar: $bar, baz: $baz){ - fooField - } -} -query VariableQuery { - posts { - id @include(if: true) - } -} -` - -const testDefinition = ` -directive @include(if: Boolean!) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -schema { - query: Query -} -type Query { - posts: [Post] - foo(bar: String!, baz: Boolean!): Foo -} -type User { - id: ID - name: String - posts: [Post] -} -type Post { - id: ID - description: String - user: User -} -type Foo { - fooField: String -} -scalar ID -scalar String -` diff --git a/pkg/graphql/fixtures/introspection_response.golden b/pkg/graphql/fixtures/introspection_response.golden deleted file mode 100644 index ebd723492..000000000 --- a/pkg/graphql/fixtures/introspection_response.golden +++ /dev/null @@ -1 +0,0 @@ -{"data":{"__schema":{"queryType":{"name":"Query"},"mutationType":null,"subscriptionType":null,"types":[{"kind":"OBJECT","name":"Query","description":"","fields":[{"name":"hello","description":"","args":[],"type":{"kind":"SCALAR","name":"String","ofType":null},"isDeprecated":false,"deprecationReason":null}],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Int","description":"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Float","description":"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"String","description":"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"Boolean","description":"The 'Boolean' scalar type represents 'true' or 'false' .","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]},{"kind":"SCALAR","name":"ID","description":"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID.","fields":[],"inputFields":[],"interfaces":[],"enumValues":[],"possibleTypes":[]}],"directives":[{"name":"include","description":"Directs the executor to include this field or fragment only when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Included when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}],"isRepeatable":false},{"name":"skip","description":"Directs the executor to skip this field or fragment when the argument is true.","locations":["FIELD","FRAGMENT_SPREAD","INLINE_FRAGMENT"],"args":[{"name":"if","description":"Skipped when true.","type":{"kind":"NON_NULL","name":null,"ofType":{"kind":"SCALAR","name":"Boolean","ofType":null}},"defaultValue":null}],"isRepeatable":false},{"name":"deprecated","description":"Marks an element of a GraphQL schema as no longer supported.","locations":["FIELD_DEFINITION","ENUM_VALUE"],"args":[{"name":"reason","description":"Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).","type":{"kind":"SCALAR","name":"String","ofType":null},"defaultValue":"\"No longer supported\""}],"isRepeatable":false}]}}} diff --git a/pkg/graphql/lookup.go b/pkg/graphql/lookup.go deleted file mode 100644 index c3ed7adfc..000000000 --- a/pkg/graphql/lookup.go +++ /dev/null @@ -1,24 +0,0 @@ -package graphql - -import ( - "fmt" -) - -type TypeFieldLookupKey string - -func CreateTypeFieldLookupKey(typeName string, fieldName string) TypeFieldLookupKey { - return TypeFieldLookupKey(fmt.Sprintf("%s.%s", typeName, fieldName)) -} - -func CreateTypeFieldArgumentsLookupMap(typeFieldArgs []TypeFieldArguments) map[TypeFieldLookupKey]TypeFieldArguments { - if len(typeFieldArgs) == 0 { - return nil - } - - lookupMap := make(map[TypeFieldLookupKey]TypeFieldArguments) - for _, currentTypeFieldArgs := range typeFieldArgs { - lookupMap[CreateTypeFieldLookupKey(currentTypeFieldArgs.TypeName, currentTypeFieldArgs.FieldName)] = currentTypeFieldArgs - } - - return lookupMap -} diff --git a/pkg/graphql/lookup_test.go b/pkg/graphql/lookup_test.go deleted file mode 100644 index a40892076..000000000 --- a/pkg/graphql/lookup_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package graphql - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCreateTypeFieldLookupKey(t *testing.T) { - lookupKey := CreateTypeFieldLookupKey("Query", "hello") - assert.Equal(t, TypeFieldLookupKey("Query.hello"), lookupKey) -} - -func TestCreateTypeFieldArgumentsLookupMap(t *testing.T) { - t.Run("should return nil if slice is empty", func(t *testing.T) { - lookupMap := CreateTypeFieldArgumentsLookupMap([]TypeFieldArguments{}) - assert.Nil(t, lookupMap) - }) - - t.Run("should return a lookup map", func(t *testing.T) { - typeFieldArgs := []TypeFieldArguments{ - { - TypeName: "Query", - FieldName: "hello", - ArgumentNames: []string{"name"}, - }, - } - - lookupMap := CreateTypeFieldArgumentsLookupMap(typeFieldArgs) - assert.Equal(t, lookupMap[TypeFieldLookupKey("Query.hello")], typeFieldArgs[0]) - }) -} diff --git a/pkg/graphql/normalization.go b/pkg/graphql/normalization.go deleted file mode 100644 index 55e8f89ba..000000000 --- a/pkg/graphql/normalization.go +++ /dev/null @@ -1,69 +0,0 @@ -package graphql - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type NormalizationResult struct { - Successful bool - Errors NormalizationErrors -} - -type NormalizationErrors Errors - -func (r *Request) Normalize(schema *Schema) (result NormalizationResult, err error) { - if schema == nil { - return NormalizationResult{Successful: false, Errors: nil}, ErrNilSchema - } - - report := r.parseQueryOnce() - if report.HasErrors() { - return normalizationResultFromReport(report) - } - - r.document.Input.Variables = r.Variables - - normalizer := astnormalization.NewWithOpts( - astnormalization.WithExtractVariables(), - astnormalization.WithRemoveFragmentDefinitions(), - astnormalization.WithRemoveUnusedVariables(), - ) - - if r.OperationName != "" { - normalizer.NormalizeNamedOperation(&r.document, &schema.document, []byte(r.OperationName), &report) - } else { - normalizer.NormalizeOperation(&r.document, &schema.document, &report) - } - - if report.HasErrors() { - return normalizationResultFromReport(report) - } - - r.isNormalized = true - - r.Variables = r.document.Input.Variables - - return NormalizationResult{Successful: true, Errors: nil}, nil -} - -func normalizationResultFromReport(report operationreport.Report) (NormalizationResult, error) { - result := NormalizationResult{ - Successful: false, - Errors: nil, - } - - if !report.HasErrors() { - result.Successful = true - return result, nil - } - - result.Errors = RequestErrorsFromOperationReport(report) - - var err error - if len(report.InternalErrors) > 0 { - err = report.InternalErrors[0] - } - - return result, err -} diff --git a/pkg/graphql/normalization_test.go b/pkg/graphql/normalization_test.go deleted file mode 100644 index 10db22e2d..000000000 --- a/pkg/graphql/normalization_test.go +++ /dev/null @@ -1,283 +0,0 @@ -package graphql - -import ( - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeprinter" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/starwars" -) - -func TestRequest_Normalize(t *testing.T) { - t.Run("should return error when schema is nil", func(t *testing.T) { - request := Request{ - OperationName: "Hello", - Variables: nil, - Query: `query Hello { hello }`, - } - - result, err := request.Normalize(nil) - assert.Error(t, err) - assert.Equal(t, ErrNilSchema, err) - assert.False(t, result.Successful) - assert.False(t, request.isNormalized) - }) - - t.Run("should successfully normalize request with fragments", func(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileFragmentsQuery) - documentBeforeNormalization := request.document - - result, err := request.Normalize(schema) - assert.NoError(t, err) - assert.NotEqual(t, documentBeforeNormalization, request.document) - assert.True(t, result.Successful) - assert.True(t, request.isNormalized) - - normalizedOperation := `query Fragments($droidID: ID!){ - hero { - name - } - droid(id: $droidID){ - name - } -}` - op := unsafeprinter.PrettyPrint(&request.document, nil) - assert.Equal(t, normalizedOperation, op) - }) - - runNormalizationWithSchema := func(t *testing.T, schema *Schema, request *Request, expectedVars string, expectedNormalizedOperation string) { - t.Helper() - - documentBeforeNormalization := request.document - - result, err := request.Normalize(schema) - assert.NoError(t, err) - assert.NotEqual(t, documentBeforeNormalization, request.document) - assert.Equal(t, []byte(expectedVars), request.document.Input.Variables) - assert.True(t, result.Successful) - assert.True(t, request.isNormalized) - - op := unsafeprinter.PrettyPrint(&request.document, nil) - assert.Equal(t, expectedNormalizedOperation, op) - } - - runNormalization := func(t *testing.T, request *Request, expectedVars string, expectedNormalizedOperation string) { - t.Helper() - - schema := starwarsSchema(t) - - runNormalizationWithSchema(t, schema, request, expectedVars, expectedNormalizedOperation) - } - - t.Run("should successfully normalize single query with arguments", func(t *testing.T) { - request := requestForQuery(t, starwars.FileDroidWithArgQuery) - - runNormalization(t, &request, `{"a":"R2D2"}`, `query($a: ID!){ - droid(id: $a){ - name - } -}`) - }) - - t.Run("should successfully normalize query and remove unused variables", func(t *testing.T) { - request := Request{ - OperationName: "MySearch", - Variables: stringify(map[string]interface{}{ - "s": "Luke", - "other": "other", - }), - Query: `query MySearch($s: String!, $other: String) {search(name: $s) {...on Human {name}}}`, - } - - runNormalization(t, &request, `{"s":"Luke"}`, `query MySearch($s: String!){ - search(name: $s){ - ... on Human { - name - } - } -}`) - }) - - t.Run("should successfully normalize query and remove unused variables and values", func(t *testing.T) { - const expectedVar = "query MySearch($s: String!){\n search(name: $s){\n ... on Human {\n name\n }\n }\n}" - for _, v := range []Request{ - { - OperationName: "MySearch", - Variables: stringify(map[string]interface{}{ - "s": "Luke", - "s2": nil, - "s3": nil, - }), - Query: `query MySearch($s: String!, $s2: String, $s3: String) {search(name: $s) {...on Human {name}}}`, - }, - { - OperationName: "MySearch", - Variables: stringify(map[string]interface{}{ - "s": "Luke", - "s2": 12, - "s3": "", - }), - Query: `query MySearch($s: String!, $s2: Int, $s3: String) {search(name: $s) {...on Human {name}}}`, - }, - { - OperationName: "MySearch", - Variables: stringify(map[string]interface{}{ - "s": "Luke", - "s3": "value", - }), - Query: `query MySearch($s: String!, $s2: Int, $s3: String) {search(name: $s) {...on Human {name}}}`, - }, - { - OperationName: "MySearch", - Variables: []byte(`{"s":"Luke", "s2": null, "s3": 78.8}`), - Query: `query MySearch($s: String!, $s2: String, $s3: String) {search(name: $s) {...on Human {name}}}`, - }, - } { - runNormalization(t, &v, `{"s":"Luke"}`, expectedVar) - } - }) - - t.Run("should successfully normalize query and remove variables with no value provided", func(t *testing.T) { - request := Request{ - OperationName: "MySearch", - Variables: stringify(map[string]interface{}{ - "s": "Luke", - }), - Query: `query MySearch($s: String!, $other: String) {search(name: $s) {...on Human {name}}}`, - } - runNormalization(t, &request, `{"s":"Luke"}`, `query MySearch($s: String!){ - search(name: $s){ - ... on Human { - name - } - } -}`) - }) - - t.Run("should successfully normalize multiple queries with arguments", func(t *testing.T) { - request := requestForQuery(t, starwars.FileMultiQueriesWithArguments) - request.OperationName = "GetDroid" - - runNormalization(t, &request, `{"a":"1"}`, `query GetDroid($a: ID!){ - droid(id: $a){ - name - } -} - -query Search { - search(name: "C3PO"){ - ... on Droid { - name - primaryFunction - } - ... on Human { - name - height - } - ... on Starship { - name - length - } - } -}`) - }) - - t.Run("input coercion for lists without variables", func(t *testing.T) { - schema := inputCoercionForListSchema(t) - request := Request{ - OperationName: "charactersByIds", - Variables: stringify(map[string]interface{}{"a": 1}), - Query: `query ($a: [Int]) { charactersByIds(ids: $a) { name }}`, - } - runNormalizationWithSchema(t, schema, &request, `{"a":[1]}`, `query($a: [Int]){ - charactersByIds(ids: $a){ - name - } -}`) - }) - - t.Run("input coercion for lists with variable extraction", func(t *testing.T) { - schema := inputCoercionForListSchema(t) - request := Request{ - OperationName: "GetCharactersByIds", - Variables: stringify(map[string]interface{}{}), - Query: `query GetCharactersByIds { charactersByIds(ids: 1) { name }}`, - } - runNormalizationWithSchema(t, schema, &request, `{"a":[1]}`, `query GetCharactersByIds($a: [Int]){ - charactersByIds(ids: $a){ - name - } -}`) - }) - - t.Run("input coercion for lists with variables", func(t *testing.T) { - schema := inputCoercionForListSchema(t) - request := Request{ - OperationName: "charactersByIds", - Variables: stringify(map[string]interface{}{ - "ids": 1, - }), - Query: `query($ids: [Int]) {charactersByIds(ids: $ids) { name }}`, - } - runNormalizationWithSchema(t, schema, &request, `{"ids":[1]}`, `query($ids: [Int]){ - charactersByIds(ids: $ids){ - name - } -}`) - }) -} - -func Test_normalizationResultFromReport(t *testing.T) { - t.Run("should return successful result when report does not have errors", func(t *testing.T) { - report := operationreport.Report{} - result, err := normalizationResultFromReport(report) - - assert.NoError(t, err) - assert.Equal(t, NormalizationResult{Successful: true, Errors: nil}, result) - }) - - t.Run("should return graphql errors and internal error when report contains them", func(t *testing.T) { - internalErr := errors.New("errors occurred") - externalErr := operationreport.ExternalError{ - Message: "graphql error", - Path: nil, - Locations: nil, - } - - report := operationreport.Report{} - report.AddInternalError(internalErr) - report.AddExternalError(externalErr) - - result, err := normalizationResultFromReport(report) - - assert.Error(t, err) - assert.Equal(t, internalErr, err) - assert.False(t, result.Successful) - assert.Equal(t, result.Errors.Count(), 1) - assert.Equal(t, "graphql error", result.Errors.(RequestErrors)[0].Message) - }) -} - -func inputCoercionForListSchema(t *testing.T) *Schema { - schemaString := `schema { - query: Query -} - -type Character { - id: Int - name: String -} - -type Query { - charactersByIds(ids: [Int]): [Character] -}` - - schema, err := NewSchemaFromString(schemaString) - require.NoError(t, err) - return schema -} diff --git a/pkg/graphql/request.go b/pkg/graphql/request.go deleted file mode 100644 index 2c47e208a..000000000 --- a/pkg/graphql/request.go +++ /dev/null @@ -1,201 +0,0 @@ -package graphql - -import ( - "encoding/json" - "errors" - "io" - "net/http" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/middleware/operation_complexity" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const ( - schemaIntrospectionFieldName = "__schema" - typeIntrospectionFieldName = "__type" -) - -type OperationType ast.OperationType - -const ( - OperationTypeUnknown OperationType = OperationType(ast.OperationTypeUnknown) - OperationTypeQuery OperationType = OperationType(ast.OperationTypeQuery) - OperationTypeMutation OperationType = OperationType(ast.OperationTypeMutation) - OperationTypeSubscription OperationType = OperationType(ast.OperationTypeSubscription) -) - -var ( - ErrEmptyRequest = errors.New("the provided request is empty") - ErrNilSchema = errors.New("the provided schema is nil") -) - -type Request struct { - OperationName string `json:"operationName"` - Variables json.RawMessage `json:"variables,omitempty"` - Query string `json:"query"` - - document ast.Document - isParsed bool - isNormalized bool - request resolve.Request - - validForSchema map[uint64]ValidationResult -} - -func UnmarshalRequest(reader io.Reader, request *Request) error { - requestBytes, err := io.ReadAll(reader) - if err != nil { - return err - } - - if len(requestBytes) == 0 { - return ErrEmptyRequest - } - - return json.Unmarshal(requestBytes, &request) -} - -func UnmarshalHttpRequest(r *http.Request, request *Request) error { - request.request.Header = r.Header - return UnmarshalRequest(r.Body, request) -} - -func (r *Request) SetHeader(header http.Header) { - r.request.Header = header -} - -func (r *Request) CalculateComplexity(complexityCalculator ComplexityCalculator, schema *Schema) (ComplexityResult, error) { - if schema == nil { - return ComplexityResult{}, ErrNilSchema - } - - report := r.parseQueryOnce() - if report.HasErrors() { - return complexityResult( - operation_complexity.OperationStats{}, - []operation_complexity.RootFieldStats{}, - report, - ) - } - - return complexityCalculator.Calculate(&r.document, &schema.document) -} - -func (r Request) Print(writer io.Writer) (n int, err error) { - report := r.parseQueryOnce() - if report.HasErrors() { - return 0, report - } - - return writer.Write(r.document.Input.RawBytes) -} - -func (r *Request) IsNormalized() bool { - return r.isNormalized -} - -func (r *Request) parseQueryOnce() (report operationreport.Report) { - if r.isParsed { - return report - } - - r.document, report = astparser.ParseGraphqlDocumentString(r.Query) - if !report.HasErrors() { - // If the given query has problems, and we failed to parse it, - // we shouldn't mark it as parsed. It can be misleading for - // the rest of the components. - r.isParsed = true - } - return report -} - -func (r *Request) IsIntrospectionQuery() (result bool, err error) { - report := r.parseQueryOnce() - if report.HasErrors() { - return false, report - } - - var operationDefinitionRef = ast.InvalidRef - var possibleOperationDefinitionRefs = make([]int, 0) - - for i := 0; i < len(r.document.RootNodes); i++ { - if r.document.RootNodes[i].Kind == ast.NodeKindOperationDefinition { - possibleOperationDefinitionRefs = append(possibleOperationDefinitionRefs, r.document.RootNodes[i].Ref) - } - } - - if len(possibleOperationDefinitionRefs) == 0 { - return - } else if len(possibleOperationDefinitionRefs) == 1 { - operationDefinitionRef = possibleOperationDefinitionRefs[0] - } else { - for i := 0; i < len(possibleOperationDefinitionRefs); i++ { - ref := possibleOperationDefinitionRefs[i] - name := r.document.OperationDefinitionNameString(ref) - - if r.OperationName == name { - operationDefinitionRef = ref - break - } - } - } - - if operationDefinitionRef == ast.InvalidRef { - return - } - - operationDef := r.document.OperationDefinitions[operationDefinitionRef] - if operationDef.OperationType != ast.OperationTypeQuery { - return - } - if !operationDef.HasSelections { - return - } - - selectionSet := r.document.SelectionSets[operationDef.SelectionSet] - if len(selectionSet.SelectionRefs) == 0 { - return - } - - for i := 0; i < len(selectionSet.SelectionRefs); i++ { - selection := r.document.Selections[selectionSet.SelectionRefs[i]] - if selection.Kind != ast.SelectionKindField { - continue - } - - fieldName := r.document.FieldNameUnsafeString(selection.Ref) - switch fieldName { - case schemaIntrospectionFieldName, typeIntrospectionFieldName: - continue - default: - return - } - } - - return true, nil -} - -func (r *Request) OperationType() (OperationType, error) { - report := r.parseQueryOnce() - if report.HasErrors() { - return OperationTypeUnknown, report - } - - for _, rootNode := range r.document.RootNodes { - if rootNode.Kind != ast.NodeKindOperationDefinition { - continue - } - - if r.OperationName != "" && r.document.OperationDefinitionNameString(rootNode.Ref) != r.OperationName { - continue - } - - opType := r.document.OperationDefinitions[rootNode.Ref].OperationType - return OperationType(opType), nil - } - - return OperationTypeUnknown, nil -} diff --git a/pkg/graphql/request_fields_validator.go b/pkg/graphql/request_fields_validator.go deleted file mode 100644 index 3d33ed6ca..000000000 --- a/pkg/graphql/request_fields_validator.go +++ /dev/null @@ -1,132 +0,0 @@ -package graphql - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type RequestFieldsValidator interface { - Validate(request *Request, schema *Schema, restrictions []Type) (RequestFieldsValidationResult, error) -} - -type FieldRestrictionValidator interface { - ValidateByFieldList(request *Request, schema *Schema, restrictionList FieldRestrictionList) (RequestFieldsValidationResult, error) -} - -type FieldRestrictionListKind int - -const ( - AllowList FieldRestrictionListKind = iota - BlockList -) - -type FieldRestrictionList struct { - Kind FieldRestrictionListKind - Types []Type -} - -type DefaultFieldsValidator struct { -} - -// Validate validates a request by checking if `restrictions` contains blocked fields. -// -// Deprecated: This function can only handle blocked fields. Use `ValidateByFieldList` if you -// want to check for blocked or allowed fields instead. -func (d DefaultFieldsValidator) Validate(request *Request, schema *Schema, restrictions []Type) (RequestFieldsValidationResult, error) { - restrictionList := FieldRestrictionList{ - Kind: BlockList, - Types: restrictions, - } - - return d.ValidateByFieldList(request, schema, restrictionList) -} - -// ValidateByFieldList will validate a request by using a list of allowed or blocked fields. -func (d DefaultFieldsValidator) ValidateByFieldList(request *Request, schema *Schema, restrictionList FieldRestrictionList) (RequestFieldsValidationResult, error) { - report := operationreport.Report{} - if len(restrictionList.Types) == 0 { - return fieldsValidationResult(report, true, "", "") - } - - requestedTypes := make(RequestTypes) - NewExtractor().ExtractFieldsFromRequest(request, schema, &report, requestedTypes) - - if restrictionList.Kind == BlockList { - return d.checkForBlockedFields(restrictionList, requestedTypes, report) - } - - return d.checkForAllowedFields(restrictionList, requestedTypes, report) -} - -func (d DefaultFieldsValidator) checkForBlockedFields(restrictionList FieldRestrictionList, requestTypes RequestTypes, report operationreport.Report) (RequestFieldsValidationResult, error) { - for _, typeFromList := range restrictionList.Types { - requestedFields, hasRestrictedType := requestTypes[typeFromList.Name] - if !hasRestrictedType { - continue - } - for _, field := range typeFromList.Fields { - _, requestHasField := requestedFields[field] - if requestHasField { - return fieldsValidationResult(report, false, typeFromList.Name, field) - } - } - } - - return fieldsValidationResult(report, true, "", "") -} - -func (d DefaultFieldsValidator) checkForAllowedFields(restrictionList FieldRestrictionList, requestTypes RequestTypes, report operationreport.Report) (RequestFieldsValidationResult, error) { - allowedFieldsLookupMap := make(map[string]map[string]bool) - for _, allowedType := range restrictionList.Types { - allowedFieldsLookupMap[allowedType.Name] = make(map[string]bool) - for _, allowedField := range allowedType.Fields { - allowedFieldsLookupMap[allowedType.Name][allowedField] = true - } - } - - for requestType, requestFields := range requestTypes { - for requestField := range requestFields { - isAllowedField := allowedFieldsLookupMap[requestType][requestField] - if !isAllowedField { - return fieldsValidationResult(report, false, requestType, requestField) - } - } - } - - return fieldsValidationResult(report, true, "", "") -} - -type RequestFieldsValidationResult struct { - Valid bool - Errors Errors -} - -func fieldsValidationResult(report operationreport.Report, valid bool, typeName, fieldName string) (RequestFieldsValidationResult, error) { - result := RequestFieldsValidationResult{ - Valid: valid, - Errors: nil, - } - - var errors RequestErrors - if !result.Valid { - errors = append(errors, RequestError{ - Message: fmt.Sprintf("field: %s is restricted on type: %s", fieldName, typeName), - }) - } - result.Errors = errors - - if !report.HasErrors() { - return result, nil - } - - errors = append(errors, RequestErrorsFromOperationReport(report)...) - result.Errors = errors - - var err error - if len(report.InternalErrors) > 0 { - err = report.InternalErrors[0] - } - - return result, err -} diff --git a/pkg/graphql/request_fields_validator_test.go b/pkg/graphql/request_fields_validator_test.go deleted file mode 100644 index cff982101..000000000 --- a/pkg/graphql/request_fields_validator_test.go +++ /dev/null @@ -1,136 +0,0 @@ -package graphql - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/starwars" -) - -func TestFieldsValidator_Validate(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - - t.Run("should invalidate if blocked fields are used", func(t *testing.T) { - - blockedFields := []Type{ - { - Name: "Character", - Fields: []string{"name"}, - }, - } - - validator := DefaultFieldsValidator{} - result, err := validator.Validate(&request, schema, blockedFields) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Equal(t, 1, result.Errors.Count()) - }) - - t.Run("should validate if non-blocked fields are used", func(t *testing.T) { - - blockedFields := []Type{ - { - Name: "Character", - Fields: []string{"friends"}, - }, - } - - validator := DefaultFieldsValidator{} - result, err := validator.Validate(&request, schema, blockedFields) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Equal(t, 0, result.Errors.Count()) - }) -} - -func TestFieldsValidator_ValidateByFieldList(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - - t.Run("block list", func(t *testing.T) { - t.Run("should invalidate if blocked fields are used", func(t *testing.T) { - blockList := FieldRestrictionList{ - Kind: BlockList, - Types: []Type{ - { - Name: "Character", - Fields: []string{"name"}, - }, - }, - } - - validator := DefaultFieldsValidator{} - result, err := validator.ValidateByFieldList(&request, schema, blockList) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Equal(t, 1, result.Errors.Count()) - }) - - t.Run("should validate if non-blocked fields are used", func(t *testing.T) { - blockList := FieldRestrictionList{ - Kind: BlockList, - Types: []Type{ - { - Name: "Character", - Fields: []string{"friends"}, - }, - }, - } - - validator := DefaultFieldsValidator{} - result, err := validator.ValidateByFieldList(&request, schema, blockList) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Equal(t, 0, result.Errors.Count()) - }) - }) - - t.Run("allow list", func(t *testing.T) { - t.Run("should invalidate if a field which is not allowed is used", func(t *testing.T) { - allowList := FieldRestrictionList{ - Kind: AllowList, - Types: []Type{ - { - Name: "Query", - Fields: []string{"hero"}, - }, - { - Name: "Character", - Fields: []string{"friends"}, - }, - }, - } - - validator := DefaultFieldsValidator{} - result, err := validator.ValidateByFieldList(&request, schema, allowList) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Equal(t, 1, result.Errors.Count()) - }) - - t.Run("should validate if all fields are allowed", func(t *testing.T) { - allowList := FieldRestrictionList{ - Kind: AllowList, - Types: []Type{ - { - Name: "Query", - Fields: []string{"hero"}, - }, - { - Name: "Character", - Fields: []string{"name"}, - }, - }, - } - - validator := DefaultFieldsValidator{} - result, err := validator.ValidateByFieldList(&request, schema, allowList) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Equal(t, 0, result.Errors.Count()) - }) - }) - -} diff --git a/pkg/graphql/request_test.go b/pkg/graphql/request_test.go deleted file mode 100644 index bc0d6755e..000000000 --- a/pkg/graphql/request_test.go +++ /dev/null @@ -1,313 +0,0 @@ -package graphql - -import ( - "bytes" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/starwars" -) - -func TestUnmarshalRequest(t *testing.T) { - t.Run("should return error when request is empty", func(t *testing.T) { - requestBytes := []byte("") - requestBuffer := bytes.NewBuffer(requestBytes) - - var request Request - err := UnmarshalRequest(requestBuffer, &request) - - assert.Error(t, err) - assert.Equal(t, ErrEmptyRequest, err) - }) - - t.Run("should successfully unmarshal request", func(t *testing.T) { - requestBytes := []byte(`{"operationName": "Hello", "variables": "", "query": "query Hello { hello }"}`) - requestBuffer := bytes.NewBuffer(requestBytes) - - var request Request - err := UnmarshalRequest(requestBuffer, &request) - - assert.NoError(t, err) - assert.Equal(t, "Hello", request.OperationName) - assert.Equal(t, "query Hello { hello }", request.Query) - }) -} - -func TestRequest_Print(t *testing.T) { - query := "query Hello { hello }" - request := Request{ - OperationName: "Hello", - Variables: nil, - Query: query, - } - - bytesBuf := new(bytes.Buffer) - n, err := request.Print(bytesBuf) - - assert.NoError(t, err) - assert.Greater(t, n, 0) - assert.Equal(t, query, bytesBuf.String()) -} - -func TestRequest_parseQueryOnce(t *testing.T) { - request := func() *Request { - return &Request{ - OperationName: "Hello", - Variables: nil, - Query: "query Hello { hello }", - } - } - - t.Run("valid query", func(t *testing.T) { - req := request() - report := req.parseQueryOnce() - assert.False(t, report.HasErrors()) - assert.True(t, req.isParsed) - }) - - t.Run("should not parse again", func(t *testing.T) { - req := request() - report := req.parseQueryOnce() - assert.False(t, report.HasErrors()) - assert.True(t, req.isParsed) - - req.Query = "{" - report = req.parseQueryOnce() - assert.False(t, report.HasErrors()) - }) - - t.Run("should not set is parsed for invalid query", func(t *testing.T) { - req := request() - req.Query = "{" - report := req.parseQueryOnce() - assert.True(t, report.HasErrors()) - assert.False(t, req.isParsed) - }) -} - -func TestRequest_CalculateComplexity(t *testing.T) { - t.Run("should return error when schema is nil", func(t *testing.T) { - request := Request{} - result, err := request.CalculateComplexity(DefaultComplexityCalculator, nil) - assert.Error(t, err) - assert.Equal(t, ErrNilSchema, err) - assert.Equal(t, 0, result.NodeCount, "unexpected node count") - assert.Equal(t, 0, result.Complexity, "unexpected complexity") - assert.Equal(t, 0, result.Depth, "unexpected depth") - assert.Nil(t, result.PerRootField, "per root field results is not nil") - }) - - t.Run("should successfully calculate the complexity of request", func(t *testing.T) { - schema := starwarsSchema(t) - - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - result, err := request.CalculateComplexity(DefaultComplexityCalculator, schema) - assert.NoError(t, err) - assert.Equal(t, 1, result.NodeCount, "unexpected node count") - assert.Equal(t, 1, result.Complexity, "unexpected complexity") - assert.Equal(t, 2, result.Depth, "unexpected depth") - assert.Equal(t, []FieldComplexityResult{ - { - TypeName: "Query", - FieldName: "hero", - Alias: "", - NodeCount: 1, - Complexity: 1, - Depth: 1, - }, - }, result.PerRootField, "unexpected per root field results") - }) - - t.Run("should successfully calculate the complexity of request with multiple query fields", func(t *testing.T) { - schema := starwarsSchema(t) - - request := requestForQuery(t, starwars.FileHeroWithAliasesQuery) - result, err := request.CalculateComplexity(DefaultComplexityCalculator, schema) - assert.NoError(t, err) - assert.Equal(t, 2, result.NodeCount, "unexpected node count") - assert.Equal(t, 2, result.Complexity, "unexpected complexity") - assert.Equal(t, 2, result.Depth, "unexpected depth") - assert.Equal(t, []FieldComplexityResult{ - { - TypeName: "Query", - FieldName: "hero", - Alias: "empireHero", - NodeCount: 1, - Complexity: 1, - Depth: 1, - }, - { - TypeName: "Query", - FieldName: "hero", - Alias: "jediHero", - NodeCount: 1, - Complexity: 1, - Depth: 1, - }}, result.PerRootField, "unexpected per root field results") - }) -} - -func TestRequest_IsIntrospectionQuery(t *testing.T) { - run := func(queryPayload string, expectedIsIntrospection bool) func(t *testing.T) { - return func(t *testing.T) { - t.Helper() - - var request Request - err := UnmarshalRequest(strings.NewReader(queryPayload), &request) - assert.NoError(t, err) - - actualIsIntrospection, err := request.IsIntrospectionQuery() - assert.NoError(t, err) - assert.Equal(t, expectedIsIntrospection, actualIsIntrospection) - } - } - - t.Run("schema introspection query", func(t *testing.T) { - t.Run("with operation name IntrospectionQuery", run(namedIntrospectionQuery, true)) - t.Run("without operation name IntrospectionQuery but as single query", run(singleNamedIntrospectionQueryWithoutOperationName, true)) - t.Run("with empty operation name", run(silentIntrospectionQuery, true)) - t.Run("with operation name but as silent query", run(silentIntrospectionQueryWithOperationName, true)) - t.Run("with multiple queries in payload", run(schemaIntrospectionQueryWithMultipleQueries, true)) - t.Run("with inline fragment", run(inlineFragmentedIntrospectionQueryType, true)) - t.Run("with inline fragment on type query", run(inlineFragmentedIntrospectionQueryWithFragmentOnQuery, true)) - t.Run("with fragment", run(fragmentedIntrospectionQuery, true)) - }) - - t.Run("type introspection query", func(t *testing.T) { - t.Run("as single introspection", run(typeIntrospectionQuery, true)) - t.Run("with multiple queries in payload", run(typeIntrospectionQueryWithMultipleQueries, true)) - }) - - t.Run("not introspection query", func(t *testing.T) { - t.Run("query with operation name IntrospectionQuery", run(nonIntrospectionQueryWithIntrospectionQueryName, false)) - t.Run("Foo query", run(nonIntrospectionQuery, false)) - t.Run("Foo mutation", run(mutationQuery, false)) - t.Run("fake schema introspection with alias", run(nonSchemaIntrospectionQueryWithAliases, false)) - t.Run("fake type introspection with alias", run(nonTypeIntrospectionQueryWithAliases, false)) - t.Run("schema introspection query with additional non-introspection fields", run(nonSchemaIntrospectionQueryWithAdditionalFields, false)) - t.Run("type introspection query with additional non-introspection fields", run(nonTypeIntrospectionQueryWithAdditionalFields, false)) - t.Run("schema introspection with multiple queries in payload", run(nonSchemaIntrospectionQueryWithMultipleQueries, false)) - t.Run("type introspection with multiple queries in payload", run(nonTypeIntrospectionQueryWithMultipleQueries, false)) - }) -} - -func TestRequest_OperationType(t *testing.T) { - request := Request{ - OperationName: "", - Variables: nil, - Query: "query HelloQuery { hello: String } mutation HelloMutation { hello: String } subscription HelloSubscription { hello: String }", - } - - t.Run("should return operation type 'Query'", func(t *testing.T) { - request.OperationName = "HelloQuery" - opType, err := request.OperationType() - assert.NoError(t, err) - assert.Equal(t, OperationTypeQuery, opType) - }) - - t.Run("should return operation type 'Mutation'", func(t *testing.T) { - request.OperationName = "HelloMutation" - opType, err := request.OperationType() - assert.NoError(t, err) - assert.Equal(t, OperationTypeMutation, opType) - }) - - t.Run("should return operation type 'Subscription'", func(t *testing.T) { - request.OperationName = "HelloSubscription" - opType, err := request.OperationType() - assert.NoError(t, err) - assert.Equal(t, OperationTypeSubscription, opType) - }) - - t.Run("should return operation type 'Unknown' on error", func(t *testing.T) { - emptyRequest := Request{ - Query: "Broken Query", - } - opType, err := emptyRequest.OperationType() - assert.Error(t, err) - assert.Equal(t, OperationTypeUnknown, opType) - }) - - t.Run("should return operation type 'Unknown' when empty and parsable", func(t *testing.T) { - emptyRequest := Request{} - opType, err := emptyRequest.OperationType() - assert.NoError(t, err) - assert.Equal(t, OperationTypeUnknown, opType) - }) - - t.Run("should return operation type 'Query' if no name and a single operation is provided", func(t *testing.T) { - singleOperationQueryRequest := Request{ - OperationName: "", - Variables: nil, - Query: "{ hello: String }", - } - - opType, err := singleOperationQueryRequest.OperationType() - assert.NoError(t, err) - assert.Equal(t, OperationTypeQuery, opType) - }) - - t.Run("should return operation type 'Mutation' if mutation is the only operation", func(t *testing.T) { - singleOperationMutationRequest := Request{ - OperationName: "", - Variables: nil, - Query: "mutation HelloMutation { hello: String }", - } - - opType, err := singleOperationMutationRequest.OperationType() - assert.NoError(t, err) - assert.Equal(t, OperationTypeMutation, opType) - }) -} - -const namedIntrospectionQuery = `{"operationName":"IntrospectionQuery","variables":{},"query":"query IntrospectionQuery {\n __schema {\n queryType {\n name\n }\n mutationType {\n name\n }\n subscriptionType {\n name\n }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n}\n\nfragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n}\n\nfragment InputValue on __InputValue {\n name\n description\n type {\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n"}` -const singleNamedIntrospectionQueryWithoutOperationName = `{"operationName":"","variables":{},"query":"query IntrospectionQuery {\n __schema {\n queryType {\n name\n }\n mutationType {\n name\n }\n subscriptionType {\n name\n }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n}\n\nfragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n}\n\nfragment InputValue on __InputValue {\n name\n description\n type {\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n"}` -const silentIntrospectionQuery = `{"operationName":null,"variables":{},"query":"{\n __schema {\n queryType {\n name\n }\n mutationType {\n name\n }\n subscriptionType {\n name\n }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n}\n\nfragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n}\n\nfragment InputValue on __InputValue {\n name\n description\n type {\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n"}` -const silentIntrospectionQueryWithOperationName = `{"operationName":"IntrospectionQuery","variables":{},"query":"{\n __schema {\n queryType {\n name\n }\n mutationType {\n name\n }\n subscriptionType {\n name\n }\n types {\n ...FullType\n }\n directives {\n name\n description\n locations\n args {\n ...InputValue\n }\n }\n }\n}\n\nfragment FullType on __Type {\n kind\n name\n description\n fields(includeDeprecated: true) {\n name\n description\n args {\n ...InputValue\n }\n type {\n ...TypeRef\n }\n isDeprecated\n deprecationReason\n }\n inputFields {\n ...InputValue\n }\n interfaces {\n ...TypeRef\n }\n enumValues(includeDeprecated: true) {\n name\n description\n isDeprecated\n deprecationReason\n }\n possibleTypes {\n ...TypeRef\n }\n}\n\nfragment InputValue on __InputValue {\n name\n description\n type {\n ...TypeRef\n }\n defaultValue\n}\n\nfragment TypeRef on __Type {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n ofType {\n kind\n name\n }\n }\n }\n }\n }\n }\n }\n}\n"}` -const schemaIntrospectionQueryWithMultipleQueries = `{"operationName":"IntrospectionQuery","query":"query Hello { world } query IntrospectionQuery { __schema { types { name } } }"}` -const inlineFragmentedIntrospectionQueryType = `{"operationName":"IntrospectionQuery","variables":{},"query":"query IntrospectionQuery { ... IntrospectionFragment } fragment IntrospectionFragment on Query { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description args { ...InputValue } onOperation onFragment onField } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }"}` -const inlineFragmentedIntrospectionQueryWithFragmentOnQuery = `{"operationName":"IntrospectionQuery","variables":{},"query":"query IntrospectionQuery { ... on Query { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description args { ...InputValue } onOperation onFragment onField } } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }"}` -const fragmentedIntrospectionQuery = `{"operationName":"IntrospectionQuery","variables":{},"query":"query IntrospectionQuery { ... IntrospectionFragment } fragment IntrospectionFragment on Query { __schema { queryType { name } mutationType { name } subscriptionType { name } types { ...FullType } directives { name description args { ...InputValue } onOperation onFragment onField } } } fragment FullType on __Type { kind name description fields(includeDeprecated: true) { name description args { ...InputValue } type { ...TypeRef } isDeprecated deprecationReason } inputFields { ...InputValue } interfaces { ...TypeRef } enumValues(includeDeprecated: true) { name description isDeprecated deprecationReason } possibleTypes { ...TypeRef } } fragment InputValue on __InputValue { name description type { ...TypeRef } defaultValue } fragment TypeRef on __Type { kind name ofType { kind name ofType { kind name ofType { kind name } } } }"}` -const typeIntrospectionQueryWithMultipleQueries = `{"operationName":"IntrospectionQuery","query":"query Hello { world } query IntrospectionQuery { __type(name: \"Droid\") { name } }"}` -const typeIntrospectionQuery = `{"operationName":null,"variables":{},"query":"{__type(name:\"Foo\"){kind}}"}` -const nonIntrospectionQuery = `{"operationName":"Foo","query":"query Foo {bar}"}` -const nonIntrospectionQueryWithIntrospectionQueryName = `{"operationName":"IntrospectionQuery","query":"query IntrospectionQuery {bar}"}` -const nonSchemaIntrospectionQueryWithAliases = `{"operationName":"IntrospectionQuery","query":"query IntrospectionQuery { __schema: user { name types: account { balance } } }"}` -const nonTypeIntrospectionQueryWithAliases = `{"operationName":"IntrospectionQuery","query":"query IntrospectionQuery { __type: user { name } }"}` -const nonSchemaIntrospectionQueryWithAdditionalFields = `{"operationName":"IntrospectionQuery","query":"query IntrospectionQuery { __schema { types { name } } user { name account { balance } } }"}` -const nonTypeIntrospectionQueryWithAdditionalFields = `{"operationName":"IntrospectionQuery","query":"query IntrospectionQuery { __type(name: \"Droid\") { name } user { name account { balance } } }"}` -const nonSchemaIntrospectionQueryWithMultipleQueries = `{"operationName":"Hello","query":"query Hello { world } query IntrospectionQuery { __schema { types { name } } }"}` -const nonTypeIntrospectionQueryWithMultipleQueries = `{"operationName":"Hello","query":"query Hello { world } query IntrospectionQuery { __type(name: \"Droid\") { name } }"}` - -const mutationQuery = `{"operationName":null,"query":"mutation Foo {bar}"}` - -const testSubscriptionDefinition = ` -type Subscription { - lastRegisteredUser: User - liveUserCount: Int! -} - -type User { - id: ID! - username: String! - email: String! -} -` - -const testSubscriptionLastRegisteredUserOperation = ` -subscription LastRegisteredUser { - lastRegisteredUser { - id - username - email - } -} -` - -const testSubscriptionLiveUserCountOperation = ` -subscription LiveUserCount { - liveUserCount -} -` diff --git a/pkg/graphql/response.go b/pkg/graphql/response.go deleted file mode 100644 index 1360341cf..000000000 --- a/pkg/graphql/response.go +++ /dev/null @@ -1,15 +0,0 @@ -package graphql - -import ( - "encoding/json" -) - -type Response struct { - Errors Errors `json:"errors,omitempty"` - // TODO: Data - // TODO: Extensions -} - -func (r Response) Marshal() ([]byte, error) { - return json.Marshal(r) -} diff --git a/pkg/graphql/schema.go b/pkg/graphql/schema.go deleted file mode 100644 index f64229f22..000000000 --- a/pkg/graphql/schema.go +++ /dev/null @@ -1,470 +0,0 @@ -package graphql - -import ( - "bytes" - "encoding/json" - "io" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/introspection" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/pool" -) - -type TypeFields struct { - TypeName string - FieldNames []string -} - -type TypeFieldArguments struct { - TypeName string - FieldName string - ArgumentNames []string -} - -type Schema struct { - rawInput []byte - rawSchema []byte - document ast.Document - isNormalized bool - hash uint64 -} - -// Hash returns the hash of the schema. -func (s *Schema) Hash() uint64 { - return s.hash -} - -// calcHash calculates the hash of the schema. -func (s *Schema) calcHash() error { - if s.hash != 0 { - return nil - } - h := pool.Hash64.Get() - h.Reset() - defer pool.Hash64.Put(h) - printer := astprinter.Printer{} - err := printer.Print(&s.document, nil, h) - if err != nil { - return err - } - s.hash = h.Sum64() - return nil -} - -func NewSchemaFromReader(reader io.Reader) (*Schema, error) { - schemaContent, err := io.ReadAll(reader) - if err != nil { - return nil, err - } - - return createSchema(schemaContent, true) -} - -func NewSchemaFromString(schema string) (*Schema, error) { - schemaContent := []byte(schema) - - return createSchema(schemaContent, true) -} - -func ValidateSchemaString(schema string) (result ValidationResult, err error) { - parsedSchema, err := NewSchemaFromString(schema) - if err != nil { - return ValidationResult{ - Valid: false, - Errors: SchemaValidationErrors{ - SchemaValidationError{Message: err.Error()}, - }, - }, nil - } - - return parsedSchema.Validate() -} - -func (s *Schema) Normalize() (result NormalizationResult, err error) { - if s.isNormalized { - return NormalizationResult{ - Successful: true, - Errors: nil, - }, nil - } - - report := operationreport.Report{} - astnormalization.NormalizeDefinition(&s.document, &report) - if report.HasErrors() { - return normalizationResultFromReport(report) - } - - normalizedSchemaBuffer := &bytes.Buffer{} - err = astprinter.PrintIndent(&s.document, nil, []byte(" "), normalizedSchemaBuffer) - if err != nil { - return NormalizationResult{ - Successful: false, - Errors: nil, - }, err - } - - normalizedSchema, err := createSchema(normalizedSchemaBuffer.Bytes(), false) - if err != nil { - return NormalizationResult{ - Successful: false, - Errors: nil, - }, err - } - - s.rawSchema = normalizedSchema.rawSchema - s.document = normalizedSchema.document - s.isNormalized = true - return NormalizationResult{Successful: true, Errors: nil}, nil -} - -func (s *Schema) Input() []byte { - return s.rawInput -} - -func (s *Schema) Document() []byte { - return s.rawSchema -} - -// HasQueryType TODO: should be deprecated? -func (s *Schema) HasQueryType() bool { - return len(s.document.Index.QueryTypeName) > 0 -} - -func (s *Schema) QueryTypeName() string { - return string(s.document.Index.QueryTypeName) -} - -func (s *Schema) IsNormalized() bool { - return s.isNormalized -} - -func (s *Schema) HasMutationType() bool { - return len(s.document.Index.MutationTypeName) > 0 -} - -func (s *Schema) MutationTypeName() string { - if !s.HasMutationType() { - return "" - } - - return string(s.document.Index.MutationTypeName) -} - -func (s *Schema) HasSubscriptionType() bool { - return len(s.document.Index.SubscriptionTypeName) > 0 -} - -func (s *Schema) SubscriptionTypeName() string { - if !s.HasSubscriptionType() { - return "" - } - - return string(s.document.Index.SubscriptionTypeName) -} - -func (s *Schema) Validate() (result ValidationResult, err error) { - var report operationreport.Report - var isValid bool - - validator := astvalidation.DefaultDefinitionValidator() - validationState := validator.Validate(&s.document, &report) - if validationState == astvalidation.Valid { - isValid = true - } - - return ValidationResult{ - Valid: isValid, - Errors: schemaValidationErrorsFromOperationReport(report), - }, nil -} - -// IntrospectionResponse - writes full schema introspection response into writer -func (s *Schema) IntrospectionResponse(out io.Writer) error { - var ( - introspectionData = struct { - Data introspection.Data `json:"data"` - }{} - report operationreport.Report - ) - gen := introspection.NewGenerator() - gen.Generate(&s.document, &report, &introspectionData.Data) - if report.HasErrors() { - return report - } - return json.NewEncoder(out).Encode(introspectionData) -} - -func (s *Schema) GetAllFieldArguments(skipFieldFuncs ...SkipFieldFunc) []TypeFieldArguments { - objectTypeExtensions := make(map[string]ast.ObjectTypeExtension) - for _, objectTypeExtension := range s.document.ObjectTypeExtensions { - typeName, ok := s.typeNameOfObjectTypeIfHavingFields(objectTypeExtension.ObjectTypeDefinition) - if !ok { - continue - } - - objectTypeExtensions[typeName] = objectTypeExtension - } - - typeFieldArguments := make([]TypeFieldArguments, 0) - for _, objectType := range s.document.ObjectTypeDefinitions { - typeName, ok := s.typeNameOfObjectTypeIfHavingFields(objectType) - if !ok { - continue - } - - for _, fieldRef := range objectType.FieldsDefinition.Refs { - fieldName, skip := s.determineIfFieldWithFieldNameShouldBeSkipped(fieldRef, typeName, skipFieldFuncs...) - if skip { - continue - } - - s.addTypeFieldArgsForFieldRef(fieldRef, typeName, fieldName, &typeFieldArguments) - } - - objectTypeExt, ok := objectTypeExtensions[typeName] - if !ok { - continue - } - - for _, fieldRef := range objectTypeExt.FieldsDefinition.Refs { - fieldName, skip := s.determineIfFieldWithFieldNameShouldBeSkipped(fieldRef, typeName, skipFieldFuncs...) - if skip { - continue - } - - s.addTypeFieldArgsForFieldRef(fieldRef, typeName, fieldName, &typeFieldArguments) - } - } - - return typeFieldArguments -} - -func (s *Schema) typeNameOfObjectTypeIfHavingFields(objectType ast.ObjectTypeDefinition) (typeName string, ok bool) { - if !objectType.HasFieldDefinitions { - return "", false - } - - return s.document.Input.ByteSliceString(objectType.Name), true -} - -func (s *Schema) fieldNameOfFieldDefinitionIfHavingArguments(field ast.FieldDefinition, ref int) (fieldName string, ok bool) { - if !field.HasArgumentsDefinitions { - return "", false - } - - return s.document.FieldDefinitionNameString(ref), true -} - -func (s *Schema) determineIfFieldWithFieldNameShouldBeSkipped(ref int, typeName string, skipFieldFuncs ...SkipFieldFunc) (fieldName string, skip bool) { - field := s.document.FieldDefinitions[ref] - fieldName, ok := s.fieldNameOfFieldDefinitionIfHavingArguments(field, ref) - if !ok { - return fieldName, true - } - - for _, skipFieldFunc := range skipFieldFuncs { - if skipFieldFunc != nil && skipFieldFunc(typeName, fieldName, s.document) { - skip = true - break - } - } - - return fieldName, skip -} - -func (s *Schema) addTypeFieldArgsForFieldRef(ref int, typeName string, fieldName string, fieldArguments *[]TypeFieldArguments) { - currentTypeFieldArgs := TypeFieldArguments{ - TypeName: typeName, - FieldName: fieldName, - ArgumentNames: make([]string, 0), - } - - for _, argRef := range s.document.FieldDefinitions[ref].ArgumentsDefinition.Refs { - argName := s.document.InputValueDefinitionNameString(argRef) - currentTypeFieldArgs.ArgumentNames = append(currentTypeFieldArgs.ArgumentNames, string(argName)) - } - - *fieldArguments = append(*fieldArguments, currentTypeFieldArgs) -} - -func (s *Schema) GetAllNestedFieldChildrenFromTypeField(typeName string, fieldName string, skipFieldFuncs ...SkipFieldFunc) []TypeFields { - node, fields := s.nodeFieldRefs(typeName) - if len(fields) == 0 { - return nil - } - childNodes := make([]TypeFields, 0) - s.findInterfaceImplementations(node, &childNodes, skipFieldFuncs...) - for _, ref := range fields { - if fieldName == s.document.FieldDefinitionNameString(ref) { - fieldTypeName := s.document.FieldDefinitionTypeNode(ref).NameString(&s.document) - s.findNestedFieldChildren(fieldTypeName, &childNodes, skipFieldFuncs...) - return childNodes - } - } - - return nil -} - -func (s *Schema) findInterfaceImplementations(node ast.Node, childNodes *[]TypeFields, skipFieldFuncs ...SkipFieldFunc) { - if node.Kind != ast.NodeKindInterfaceTypeDefinition { - return - } - - implementingNodes := s.document.InterfaceTypeDefinitionImplementedByRootNodes(node.Ref) - for i := 0; i < len(implementingNodes); i++ { - var typeName string - switch implementingNodes[i].Kind { - case ast.NodeKindObjectTypeDefinition: - typeName = s.document.ObjectTypeDefinitionNameString(implementingNodes[i].Ref) - case ast.NodeKindInterfaceTypeDefinition: - typeName = s.document.InterfaceTypeDefinitionNameString(implementingNodes[i].Ref) - } - - s.findNestedFieldChildren(typeName, childNodes, skipFieldFuncs...) - } -} - -func (s *Schema) findNestedFieldChildren(typeName string, childNodes *[]TypeFields, skipFieldFuncs ...SkipFieldFunc) { - node, fields := s.nodeFieldRefs(typeName) - if len(fields) == 0 { - return - } - - s.findInterfaceImplementations(node, childNodes, skipFieldFuncs...) - for _, ref := range fields { - fieldName := s.document.FieldDefinitionNameString(ref) - if len(skipFieldFuncs) > 0 { - skip := false - for _, skipFieldFunc := range skipFieldFuncs { - if skipFieldFunc != nil && skipFieldFunc(typeName, fieldName, s.document) { - skip = true - break - } - } - - if skip { - continue - } - } - - if added := s.putChildNode(childNodes, typeName, fieldName); !added { - continue - } - - fieldTypeName := s.document.FieldDefinitionTypeNode(ref).NameString(&s.document) - s.findNestedFieldChildren(fieldTypeName, childNodes, skipFieldFuncs...) - } -} - -func (s *Schema) nodeFieldRefs(typeName string) (node ast.Node, fieldsRefs []int) { - node, exists := s.document.Index.FirstNodeByNameStr(typeName) - if !exists { - return ast.Node{}, nil - } - - switch node.Kind { - case ast.NodeKindObjectTypeDefinition: - fieldsRefs = s.document.ObjectTypeDefinitions[node.Ref].FieldsDefinition.Refs - case ast.NodeKindInterfaceTypeDefinition: - fieldsRefs = s.document.InterfaceTypeDefinitions[node.Ref].FieldsDefinition.Refs - default: - return ast.Node{}, nil - } - - return node, fieldsRefs -} - -func (s *Schema) putChildNode(nodes *[]TypeFields, typeName, fieldName string) (added bool) { - for i := range *nodes { - if typeName != (*nodes)[i].TypeName { - continue - } - for j := range (*nodes)[i].FieldNames { - if fieldName == (*nodes)[i].FieldNames[j] { - return false - } - } - (*nodes)[i].FieldNames = append((*nodes)[i].FieldNames, fieldName) - return true - } - *nodes = append(*nodes, TypeFields{ - TypeName: typeName, - FieldNames: []string{fieldName}, - }) - return true -} - -func createSchema(schemaContent []byte, mergeWithBaseSchema bool) (*Schema, error) { - document, report := astparser.ParseGraphqlDocumentBytes(schemaContent) - if report.HasErrors() { - return nil, report - } - - rawSchema := schemaContent - if mergeWithBaseSchema { - err := asttransform.MergeDefinitionWithBaseSchema(&document) - if err != nil { - return nil, err - } - - rawSchemaBuffer := &bytes.Buffer{} - err = astprinter.PrintIndent(&document, nil, []byte(" "), rawSchemaBuffer) - if err != nil { - return nil, err - } - - rawSchema = rawSchemaBuffer.Bytes() - } - - schema := &Schema{ - rawInput: schemaContent, - rawSchema: rawSchema, - document: document, - } - if err := schema.calcHash(); err != nil { - return nil, err - } - - return schema, nil -} - -func SchemaIntrospection(schema *Schema) (*ExecutionResult, error) { - var buf bytes.Buffer - err := schema.IntrospectionResponse(&buf) - return &ExecutionResult{&buf}, err -} - -type SkipFieldFunc func(typeName, fieldName string, definition ast.Document) bool - -func NewIsDataSourceConfigV2RootFieldSkipFunc(dataSources []plan.DataSourceConfiguration) SkipFieldFunc { - return func(typeName, fieldName string, _ ast.Document) bool { - for i := range dataSources { - for j := range dataSources[i].RootNodes { - if typeName != dataSources[i].RootNodes[j].TypeName { - continue - } - for k := range dataSources[i].RootNodes[j].FieldNames { - if fieldName == dataSources[i].RootNodes[j].FieldNames[k] { - return true - } - } - } - } - return false - } -} - -func NewSkipReservedNamesFunc() SkipFieldFunc { - return func(typeName, fieldName string, _ ast.Document) bool { - prefix := "__" - return strings.HasPrefix(typeName, prefix) || strings.HasPrefix(fieldName, prefix) - } -} diff --git a/pkg/graphql/schema_test.go b/pkg/graphql/schema_test.go deleted file mode 100644 index 5c590ee6f..000000000 --- a/pkg/graphql/schema_test.go +++ /dev/null @@ -1,1932 +0,0 @@ -package graphql - -import ( - "bytes" - "io" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/asttransform" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestNewSchemaFromReader(t *testing.T) { - t.Run("should return error when an error occurs internally", func(t *testing.T) { - schemaBytes := []byte("query: Query") - schemaReader := bytes.NewBuffer(schemaBytes) - schema, err := NewSchemaFromReader(schemaReader) - - assert.Error(t, err) - assert.Nil(t, schema) - }) - - t.Run("should successfully read from io.Reader", func(t *testing.T) { - schemaBytes := []byte("schema { query: Query } type Query { hello: String }") - schemaReader := bytes.NewBuffer(schemaBytes) - schema, err := NewSchemaFromReader(schemaReader) - - assert.NoError(t, err) - assert.Equal(t, schemaBytes, schema.rawInput) - }) -} - -func TestNewSchemaFromString(t *testing.T) { - t.Run("should return error when an error occurs internally", func(t *testing.T) { - schemaBytes := []byte("query: Query") - schema, err := NewSchemaFromString(string(schemaBytes)) - - assert.Error(t, err) - assert.Nil(t, schema) - }) - - t.Run("should successfully read from string", func(t *testing.T) { - schemaBytes := []byte("schema { query: Query } type Query { hello: String }") - schema, err := NewSchemaFromString(string(schemaBytes)) - - assert.NoError(t, err) - assert.Equal(t, schemaBytes, schema.rawInput) - }) -} - -func TestSchema_Normalize(t *testing.T) { - t.Run("should successfully normalize schema", func(t *testing.T) { - parsedSchema, err := NewSchemaFromString("type Query { me: String } extend type Query { you: String }") - require.NoError(t, err) - - require.False(t, parsedSchema.IsNormalized()) - normalizationResult, err := parsedSchema.Normalize() - - assert.NoError(t, err) - assert.True(t, normalizationResult.Successful) - assert.Nil(t, normalizationResult.Errors) - assert.True(t, parsedSchema.IsNormalized()) - - normalizationResult, err = parsedSchema.Normalize() - assert.NoError(t, err) - assert.True(t, normalizationResult.Successful) - assert.Nil(t, normalizationResult.Errors) - }) -} - -func TestSchema_HasQueryType(t *testing.T) { - run := func(schema string, expectation bool) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := createSchema([]byte(schema), false) - require.NoError(t, err) - - result := parsedSchema.HasQueryType() - assert.Equal(t, expectation, result) - } - } - - t.Run("schema without base definition", func(t *testing.T) { - t.Run("should return false when there is no query type present", run(` - schema { - mutation: Mutation - } - type Mutation { - save: Boolean! - }`, false), - ) - - t.Run("should return true when there is a query type present", run(` - schema { - query: Query - } - type Query { - hello: String! - }`, true), - ) - }) -} - -func TestSchema_QueryTypeName(t *testing.T) { - run := func(schema string, expectation string) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - - result := parsedSchema.QueryTypeName() - assert.Equal(t, expectation, result) - } - } - - t.Run("should return default query name when no query type is present", run(` - schema { - mutation: Mutation - } - type Mutation { - save: Boolean! - }`, "Query"), - ) - - t.Run("should return 'Query' when there is a query type named 'Query'", run(` - schema { - query: Query - } - type Query { - hello: String! - }`, "Query"), - ) - - t.Run("should return 'Other' when there is a query type named 'Other'", run(` - schema { - query: Other - } - type Other { - hello: String! - }`, "Other"), - ) -} - -func TestSchema_HasMutationType(t *testing.T) { - run := func(schema string, expectation bool) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - - result := parsedSchema.HasMutationType() - assert.Equal(t, expectation, result) - } - } - - t.Run("should return false when there is no mutation type present", run(` - schema { - query: Query - } - type Query { - hello: String! - }`, false), - ) - - t.Run("should return true when there is a mutation type present", run(` - schema { - mutation: Mutation - } - type Mutation { - save: Boolean! - }`, true), - ) -} - -func TestSchema_MutationTypeName(t *testing.T) { - run := func(schema string, expectation string) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - - result := parsedSchema.MutationTypeName() - assert.Equal(t, expectation, result) - } - } - - t.Run("should return empty string when no mutation type is present", run(` - schema { - query: Query - } - type Query { - hello: String! - }`, ""), - ) - - t.Run("should return 'Mutation' when there is a mutation type named 'Mutation'", run(` - schema { - mutation: Mutation - } - type Mutation { - save: Boolean! - }`, "Mutation"), - ) - - t.Run("should return 'Other' when there is a mutation type named 'Other'", run(` - schema { - mutation: Other - } - type Other { - save: Boolean! - }`, "Other"), - ) -} - -func TestSchema_HasSubscriptionType(t *testing.T) { - run := func(schema string, expectation bool) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - - result := parsedSchema.HasSubscriptionType() - assert.Equal(t, expectation, result) - } - } - - t.Run("should return false when there is no subscription type present", run(` - schema { - query: Query - } - type Query { - hello: String! - }`, false), - ) - - t.Run("should return true when there is a subscription type present", run(` - schema { - subscription: Subscription - } - type Subscription { - news: String! - }`, true), - ) -} - -func TestSchema_SubscriptionTypeName(t *testing.T) { - run := func(schema string, expectation string) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - - result := parsedSchema.SubscriptionTypeName() - assert.Equal(t, expectation, result) - } - } - - t.Run("should return empty string when no subscription type is present", run(` - schema { - query: Query - } - type Query { - hello: String! - }`, ""), - ) - - t.Run("should return 'Subscription' when there is a subscription type named 'Subscription'", run(` - schema { - subscription: Subscription - } - type Subscription { - news: String! - }`, "Subscription"), - ) - - t.Run("should return 'Other' when there is a subscription type named 'Other'", run(` - schema { - subscription: Other - } - type Other { - news: String! - }`, "Other"), - ) -} - -func TestSchema_Document(t *testing.T) { - schemaBytes := []byte("schema { query: Query } type Query { hello: String }") - schema, err := NewSchemaFromString(string(schemaBytes)) - require.NoError(t, err) - - document, report := astparser.ParseGraphqlDocumentBytes(schemaBytes) - require.False(t, report.HasErrors()) - - err = asttransform.MergeDefinitionWithBaseSchema(&document) - require.NoError(t, err) - - expectedSchemaBytesBuffer := &bytes.Buffer{} - err = astprinter.PrintIndent(&document, nil, []byte(" "), expectedSchemaBytesBuffer) - require.NoError(t, err) - - assert.Equal(t, expectedSchemaBytesBuffer.Bytes(), schema.Document()) -} - -func TestValidateSchemaString(t *testing.T) { - run := func(schema string, expectedValid bool, expectedValidationErrorCount int) func(t *testing.T) { - return func(t *testing.T) { - validationResult, err := ValidateSchemaString(schema) - assert.NoError(t, err) - assert.Equal(t, expectedValid, validationResult.Valid) - assert.Equal(t, expectedValidationErrorCount, validationResult.Errors.Count()) - } - } - - t.Run("should successfully validate broken schema as invalid", run( - `type Query {`, - false, - 1, - )) - - t.Run("should successfully validate schema with duplicate fields on query as invalid", run( - `type Mutation { - default: String - } - type Query { - default: String - default: String - }`, - false, - 1, - )) - - t.Run("should successfully validate invalid schema schema as invalid", run( - invalidSchema, - false, - 1, - )) - - t.Run("should successfully validate countries schema as valid", run( - countriesSchema, - true, - 0, - )) - - t.Run("should successfully validate swapi schema as valid", run( - swapiSchema, - true, - 0, - )) -} - -func TestSchema_Validate(t *testing.T) { - run := func(schema string, expectedValid bool, expectedValidationErrorCount int) func(t *testing.T) { - return func(t *testing.T) { - parsedSchema, err := NewSchemaFromString(schema) - require.NoError(t, err) - - validationResult, err := parsedSchema.Validate() - assert.NoError(t, err) - assert.Equal(t, expectedValid, validationResult.Valid) - assert.Equal(t, expectedValidationErrorCount, validationResult.Errors.Count()) - } - } - - t.Run("should successfully validate invalid schema schema as invalid", run( - invalidSchema, - false, - 1, - )) - - t.Run("should successfully validate schema with duplicate fields on query as invalid", run( - `type Mutation { - default: String - } - type Query { - default: String - default: String - }`, - false, - 1, - )) - - t.Run("should successfully validate countries schema as valid", run( - countriesSchema, - true, - 0, - )) - - t.Run("should successfully validate swapi schema as valid", run( - swapiSchema, - true, - 0, - )) -} - -func TestSchema_IntrospectionResponse(t *testing.T) { - schemaBytes := []byte("schema { query: Query } type Query { hello: String }") - schemaReader := bytes.NewBuffer(schemaBytes) - schema, err := NewSchemaFromReader(schemaReader) - assert.NoError(t, err) - out := &bytes.Buffer{} - err = schema.IntrospectionResponse(out) - assert.NoError(t, err) - goldie.Assert(t, "introspection_response", out.Bytes()) -} - -func TestSchemaIntrospection(t *testing.T) { - schemaString := "schema { query: Query } type Query { hello: String }" - schema, err := NewSchemaFromString(schemaString) - assert.NoError(t, err) - - result, err := SchemaIntrospection(schema) - assert.NoError(t, err) - - resp := result.GetAsHTTPResponse() - assert.NotNil(t, resp) - assert.NotNil(t, resp.Body) - - bodyBytes, err := io.ReadAll(resp.Body) - assert.NoError(t, err) - - goldie.Assert(t, "introspection_response", bodyBytes) -} - -func TestSchema_GetAllFieldArguments(t *testing.T) { - schema, err := NewSchemaFromString(schemaWithChildren) - require.NoError(t, err) - - t.Run("should get all field arguments without skip function", func(t *testing.T) { - fieldArguments := schema.GetAllFieldArguments() - expectedFieldArguments := []TypeFieldArguments{ - { - TypeName: "Query", - FieldName: "singleArgLevel1", - ArgumentNames: []string{"lvl"}, - }, - { - TypeName: "Query", - FieldName: "_entities", - ArgumentNames: []string{"representations"}, - }, - { - TypeName: "Query", - FieldName: "__type", - ArgumentNames: []string{"name"}, - }, - { - TypeName: "Query", - FieldName: "multiArgLevel1", - ArgumentNames: []string{"lvl", "number"}, - }, - { - TypeName: "SingleArgLevel1", - FieldName: "singleArgLevel2", - ArgumentNames: []string{"lvl"}, - }, - { - TypeName: "MultiArgLevel1", - FieldName: "multiArgLevel2", - ArgumentNames: []string{"lvl", "number"}, - }, - { - TypeName: "__Type", - FieldName: "fields", - ArgumentNames: []string{"includeDeprecated"}, - }, - { - TypeName: "__Type", - FieldName: "enumValues", - ArgumentNames: []string{"includeDeprecated"}, - }, - } - assert.Equal(t, expectedFieldArguments, fieldArguments) - }) - - t.Run("should get all field arguments excluding skipped fields by skip field funcs", func(t *testing.T) { - fieldArguments := schema.GetAllFieldArguments(NewSkipReservedNamesFunc()) - expectedFieldArguments := []TypeFieldArguments{ - { - TypeName: "Query", - FieldName: "singleArgLevel1", - ArgumentNames: []string{"lvl"}, - }, - { - TypeName: "Query", - FieldName: "_entities", - ArgumentNames: []string{"representations"}, - }, - { - TypeName: "Query", - FieldName: "multiArgLevel1", - ArgumentNames: []string{"lvl", "number"}, - }, - { - TypeName: "SingleArgLevel1", - FieldName: "singleArgLevel2", - ArgumentNames: []string{"lvl"}, - }, - { - TypeName: "MultiArgLevel1", - FieldName: "multiArgLevel2", - ArgumentNames: []string{"lvl", "number"}, - }, - } - assert.Equal(t, expectedFieldArguments, fieldArguments) - }) -} - -func TestSchema_GetAllNestedFieldChildrenFromTypeField(t *testing.T) { - schema, err := NewSchemaFromString(schemaWithChildren) - require.NoError(t, err) - - t.Run("should return nil when type or field does not exist", func(t *testing.T) { - typeFields := schema.GetAllNestedFieldChildrenFromTypeField("Not", "existent") - assert.Equal(t, []TypeFields(nil), typeFields) - }) - - t.Run("should get field children without skip function", func(t *testing.T) { - typeFields := schema.GetAllNestedFieldChildrenFromTypeField("Query", "withChildren") - expectedTypeFields := []TypeFields{ - { - TypeName: "WithChildren", - FieldNames: []string{"id", "name", "nested", "__typename"}, - }, - { - TypeName: "Nested", - FieldNames: []string{"id", "name", "__typename"}, - }, - } - - assert.Equal(t, expectedTypeFields, typeFields) - }) - - t.Run("should get field children without skip function on field with interface type", func(t *testing.T) { - typeFields := schema.GetAllNestedFieldChildrenFromTypeField("Query", "idType") - expectedTypeFields := []TypeFields{ - { - TypeName: "WithChildren", - FieldNames: []string{"id", "name", "nested", "__typename"}, - }, - { - TypeName: "Nested", - FieldNames: []string{"id", "name", "__typename"}, - }, - { - TypeName: "IDType", - FieldNames: []string{"id", "__typename"}, - }, - } - - assert.Equal(t, expectedTypeFields, typeFields) - }) - - t.Run("should get field children with skip function for engine v2 data source config", func(t *testing.T) { - dataSources := []plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - { - TypeName: "WithChildren", - FieldNames: []string{"nested"}, - }, - }, - }, - } - typeFields := schema.GetAllNestedFieldChildrenFromTypeField("Query", "withChildren", NewIsDataSourceConfigV2RootFieldSkipFunc(dataSources)) - expectedTypeFields := []TypeFields{ - { - TypeName: "WithChildren", - FieldNames: []string{"id", "name", "__typename"}, - }, - } - - assert.Equal(t, expectedTypeFields, typeFields) - }) - - t.Run("should get field children from schema with recursive references", func(t *testing.T) { - schema, err = NewSchemaFromString(countriesSchema) - require.NoError(t, err) - - typeFields := schema.GetAllNestedFieldChildrenFromTypeField("Query", "countries") - expectedTypeFields := []TypeFields{ - { - TypeName: "Country", - FieldNames: []string{"code", "name", "native", "phone", "continent", "capital", "currency", "languages", "emoji", "emojiU", "states", "__typename"}, - }, - { - TypeName: "Continent", - FieldNames: []string{"code", "name", "countries", "__typename"}, - }, - { - TypeName: "Language", - FieldNames: []string{"code", "name", "native", "rtl", "__typename"}, - }, - { - TypeName: "State", - FieldNames: []string{"code", "name", "country", "__typename"}, - }, - } - - assert.Equal(t, expectedTypeFields, typeFields) - }) - - t.Run("should get field children from schema with recursive references on field with interface type", func(t *testing.T) { - schema, err = NewSchemaFromString(countriesSchema) - require.NoError(t, err) - - typeFields := schema.GetAllNestedFieldChildrenFromTypeField("Query", "codeType") - expectedTypeFields := []TypeFields{ - { - TypeName: "Continent", - FieldNames: []string{"code", "name", "countries", "__typename"}, - }, - { - TypeName: "Country", - FieldNames: []string{"code", "name", "native", "phone", "continent", "capital", "currency", "languages", "emoji", "emojiU", "states", "__typename"}, - }, - { - TypeName: "Language", - FieldNames: []string{"code", "name", "native", "rtl", "__typename"}, - }, - { - TypeName: "State", - FieldNames: []string{"code", "name", "country", "__typename"}, - }, - { - TypeName: "CodeNameType", - FieldNames: []string{"code", "name", "__typename"}, - }, - { - TypeName: "CodeType", - FieldNames: []string{"code", "__typename"}, - }, - } - - assert.Equal(t, expectedTypeFields, typeFields) - }) -} - -var invalidSchema = `type Query { - foo: Bar -}` - -var schemaWithChildren = `scalar _Any -union _Entity = WithChildren - -type Query { - withChildren: WithChildren - singleArgLevel1(lvl: int): SingleArgLevel1 - _entities(representations: [_Any!]!): [_Entity]! - idType: IDType! -} - -extend type Query { - multiArgLevel1(lvl: int, number: int): MultiArgLevel1 -} - -interface IDType { - id: ID! -} - -type WithChildren implements IDType { - id: ID! - name: String - nested: Nested -} - -type Nested implements IDType { - id: ID! - name: String! -} - -type SingleArgLevel1 { - singleArgLevel2(lvl: int): String -} - -type MultiArgLevel1 { - multiArgLevel2(lvl: int, number: int): String -}` - -var countriesSchema = `directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT | INTERFACE - -schema { - query: Query -} - -interface CodeType { - code: ID! -} - -interface CodeNameType implements CodeType { - code: ID! - name: String! -} - -enum CacheControlScope { - PUBLIC - PRIVATE -} - -type Continent implements CodeNameType & CodeType { - code: ID! - name: String! - countries: [Country!]! -} - -input ContinentFilterInput { - code: StringQueryOperatorInput -} - -type Country implements CodeNameType & CodeType { - code: ID! - name: String! - native: String! - phone: String! - continent: Continent! - capital: String - currency: String - languages: [Language!]! - emoji: String! - emojiU: String! - states: [State!]! -} - -input CountryFilterInput { - code: StringQueryOperatorInput - currency: StringQueryOperatorInput - continent: StringQueryOperatorInput -} - -type Language { - code: ID! - name: String - native: String - rtl: Boolean! -} - -input LanguageFilterInput { - code: StringQueryOperatorInput -} - -type Query { - continents(filter: ContinentFilterInput): [Continent!]! - continent(code: ID!): Continent - countries(filter: CountryFilterInput): [Country!]! - country(code: ID!): Country - languages(filter: LanguageFilterInput): [Language!]! - language(code: ID!): Language - codeType: CodeType! -} - -type State { - code: String - name: String! - country: Country! -} - -input StringQueryOperatorInput { - eq: String - ne: String - in: [String] - nin: [String] - regex: String - glob: String -} - -"""The Upload scalar type represents a file upload.""" -scalar Upload` - -var swapiSchema = `schema { - query: Root -} - -"""A single film.""" -type Film implements Node { - """The title of this film.""" - title: String - - """The episode number of this film.""" - episodeID: Int - - """The opening paragraphs at the beginning of this film.""" - openingCrawl: String - - """The name of the director of this film.""" - director: String - - """The name(s) of the producer(s) of this film.""" - producers: [String] - - """The ISO 8601 date format of film release at original creator country.""" - releaseDate: String - speciesConnection(after: String, first: Int, before: String, last: Int): FilmSpeciesConnection - starshipConnection(after: String, first: Int, before: String, last: Int): FilmStarshipsConnection - vehicleConnection(after: String, first: Int, before: String, last: Int): FilmVehiclesConnection - characterConnection(after: String, first: Int, before: String, last: Int): FilmCharactersConnection - planetConnection(after: String, first: Int, before: String, last: Int): FilmPlanetsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! -} - -"""A connection to a list of items.""" -type FilmCharactersConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmCharactersEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - characters: [Person] -} - -"""An edge in a connection.""" -type FilmCharactersEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type FilmPlanetsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmPlanetsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - planets: [Planet] -} - -"""An edge in a connection.""" -type FilmPlanetsEdge { - """The item at the end of the edge""" - node: Planet - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type FilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] -} - -"""An edge in a connection.""" -type FilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type FilmSpeciesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmSpeciesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - species: [Species] -} - -"""An edge in a connection.""" -type FilmSpeciesEdge { - """The item at the end of the edge""" - node: Species - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type FilmStarshipsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmStarshipsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - starships: [Starship] -} - -"""An edge in a connection.""" -type FilmStarshipsEdge { - """The item at the end of the edge""" - node: Starship - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type FilmVehiclesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [FilmVehiclesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - vehicles: [Vehicle] -} - -"""An edge in a connection.""" -type FilmVehiclesEdge { - """The item at the end of the edge""" - node: Vehicle - - """A cursor for use in pagination""" - cursor: String! -} - -"""An object with an ID""" -interface Node { - """The id of the object.""" - id: ID! -} - -"""Information about pagination in a connection.""" -type PageInfo { - """When paginating forwards, are there more items?""" - hasNextPage: Boolean! - - """When paginating backwards, are there more items?""" - hasPreviousPage: Boolean! - - """When paginating backwards, the cursor to continue.""" - startCursor: String - - """When paginating forwards, the cursor to continue.""" - endCursor: String -} - -"""A connection to a list of items.""" -type PeopleConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PeopleEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - people: [Person] -} - -"""An edge in a connection.""" -type PeopleEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! -} - -"""An individual person or character within the Star Wars universe.""" -type Person implements Node { - """The name of this person.""" - name: String - - """ - The birth year of the person, using the in-universe standard of BBY or ABY - - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is - a battle that occurs at the end of Star Wars episode IV: A New Hope. - """ - birthYear: String - - """ - The eye color of this person. Will be "unknown" if not known or "n/a" if the - person does not have an eye. - """ - eyeColor: String - - """ - The gender of this person. Either "Male", "Female" or "unknown", - "n/a" if the person does not have a gender. - """ - gender: String - - """ - The hair color of this person. Will be "unknown" if not known or "n/a" if the - person does not have hair. - """ - hairColor: String - - """The height of the person in centimeters.""" - height: Int - - """The mass of the person in kilograms.""" - mass: Float - - """The skin color of this person.""" - skinColor: String - - """A planet that this person was born on or inhabits.""" - homeworld: Planet - filmConnection(after: String, first: Int, before: String, last: Int): PersonFilmsConnection - - """The species that this person belongs to, or null if unknown.""" - species: Species - starshipConnection(after: String, first: Int, before: String, last: Int): PersonStarshipsConnection - vehicleConnection(after: String, first: Int, before: String, last: Int): PersonVehiclesConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! -} - -"""A connection to a list of items.""" -type PersonFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PersonFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] -} - -"""An edge in a connection.""" -type PersonFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type PersonStarshipsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PersonStarshipsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - starships: [Starship] -} - -"""An edge in a connection.""" -type PersonStarshipsEdge { - """The item at the end of the edge""" - node: Starship - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type PersonVehiclesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PersonVehiclesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - vehicles: [Vehicle] -} - -"""An edge in a connection.""" -type PersonVehiclesEdge { - """The item at the end of the edge""" - node: Vehicle - - """A cursor for use in pagination""" - cursor: String! -} - -""" -A large mass, planet or planetoid in the Star Wars Universe, at the time of -0 ABY. -""" -type Planet implements Node { - """The name of this planet.""" - name: String - - """The diameter of this planet in kilometers.""" - diameter: Int - - """ - The number of standard hours it takes for this planet to complete a single - rotation on its axis. - """ - rotationPeriod: Int - - """ - The number of standard days it takes for this planet to complete a single orbit - of its local star. - """ - orbitalPeriod: Int - - """ - A number denoting the gravity of this planet, where "1" is normal or 1 standard - G. "2" is twice or 2 standard Gs. "0.5" is half or 0.5 standard Gs. - """ - gravity: String - - """The average population of sentient beings inhabiting this planet.""" - population: Float - - """The climates of this planet.""" - climates: [String] - - """The terrains of this planet.""" - terrains: [String] - - """ - The percentage of the planet surface that is naturally occurring water or bodies - of water. - """ - surfaceWater: Float - residentConnection(after: String, first: Int, before: String, last: Int): PlanetResidentsConnection - filmConnection(after: String, first: Int, before: String, last: Int): PlanetFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! -} - -"""A connection to a list of items.""" -type PlanetFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PlanetFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] -} - -"""An edge in a connection.""" -type PlanetFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type PlanetResidentsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PlanetResidentsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - residents: [Person] -} - -"""An edge in a connection.""" -type PlanetResidentsEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type PlanetsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [PlanetsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - planets: [Planet] -} - -"""An edge in a connection.""" -type PlanetsEdge { - """The item at the end of the edge""" - node: Planet - - """A cursor for use in pagination""" - cursor: String! -} - -type Root { - allFilms(after: String, first: Int, before: String, last: Int): FilmsConnection - film(id: ID, filmID: ID): Film - allPeople(after: String, first: Int, before: String, last: Int): PeopleConnection - person(id: ID, personID: ID): Person - allPlanets(after: String, first: Int, before: String, last: Int): PlanetsConnection - planet(id: ID, planetID: ID): Planet - allSpecies(after: String, first: Int, before: String, last: Int): SpeciesConnection - species(id: ID, speciesID: ID): Species - allStarships(after: String, first: Int, before: String, last: Int): StarshipsConnection - starship(id: ID, starshipID: ID): Starship - allVehicles(after: String, first: Int, before: String, last: Int): VehiclesConnection - vehicle(id: ID, vehicleID: ID): Vehicle - - """Fetches an object given its ID""" - node( - """The ID of an object""" - id: ID! - ): Node -} - -"""A type of person or character within the Star Wars Universe.""" -type Species implements Node { - """The name of this species.""" - name: String - - """The classification of this species, such as "mammal" or "reptile".""" - classification: String - - """The designation of this species, such as "sentient".""" - designation: String - - """The average height of this species in centimeters.""" - averageHeight: Float - - """The average lifespan of this species in years, null if unknown.""" - averageLifespan: Int - - """ - Common eye colors for this species, null if this species does not typically - have eyes. - """ - eyeColors: [String] - - """ - Common hair colors for this species, null if this species does not typically - have hair. - """ - hairColors: [String] - - """ - Common skin colors for this species, null if this species does not typically - have skin. - """ - skinColors: [String] - - """The language commonly spoken by this species.""" - language: String - - """A planet that this species originates from.""" - homeworld: Planet - personConnection(after: String, first: Int, before: String, last: Int): SpeciesPeopleConnection - filmConnection(after: String, first: Int, before: String, last: Int): SpeciesFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! -} - -"""A connection to a list of items.""" -type SpeciesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [SpeciesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - species: [Species] -} - -"""An edge in a connection.""" -type SpeciesEdge { - """The item at the end of the edge""" - node: Species - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type SpeciesFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [SpeciesFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] -} - -"""An edge in a connection.""" -type SpeciesFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type SpeciesPeopleConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [SpeciesPeopleEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - people: [Person] -} - -"""An edge in a connection.""" -type SpeciesPeopleEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! -} - -"""A single transport craft that has hyperdrive capability.""" -type Starship implements Node { - """The name of this starship. The common name, such as "Death Star".""" - name: String - - """ - The model or official name of this starship. Such as "T-65 X-wing" or "DS-1 - Orbital Battle Station". - """ - model: String - - """ - The class of this starship, such as "Starfighter" or "Deep Space Mobile - Battlestation" - """ - starshipClass: String - - """The manufacturers of this starship.""" - manufacturers: [String] - - """The cost of this starship new, in galactic credits.""" - costInCredits: Float - - """The length of this starship in meters.""" - length: Float - - """The number of personnel needed to run or pilot this starship.""" - crew: String - - """The number of non-essential people this starship can transport.""" - passengers: String - - """ - The maximum speed of this starship in atmosphere. null if this starship is - incapable of atmosphering flight. - """ - maxAtmospheringSpeed: Int - - """The class of this starships hyperdrive.""" - hyperdriveRating: Float - - """ - The Maximum number of Megalights this starship can travel in a standard hour. - A "Megalight" is a standard unit of distance and has never been defined before - within the Star Wars universe. This figure is only really useful for measuring - the difference in speed of starships. We can assume it is similar to AU, the - distance between our Sun (Sol) and Earth. - """ - MGLT: Int - - """The maximum number of kilograms that this starship can transport.""" - cargoCapacity: Float - - """ - The maximum length of time that this starship can provide consumables for its - entire crew without having to resupply. - """ - consumables: String - pilotConnection(after: String, first: Int, before: String, last: Int): StarshipPilotsConnection - filmConnection(after: String, first: Int, before: String, last: Int): StarshipFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! -} - -"""A connection to a list of items.""" -type StarshipFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [StarshipFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] -} - -"""An edge in a connection.""" -type StarshipFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type StarshipPilotsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [StarshipPilotsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - pilots: [Person] -} - -"""An edge in a connection.""" -type StarshipPilotsEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type StarshipsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [StarshipsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - starships: [Starship] -} - -"""An edge in a connection.""" -type StarshipsEdge { - """The item at the end of the edge""" - node: Starship - - """A cursor for use in pagination""" - cursor: String! -} - -"""A single transport craft that does not have hyperdrive capability""" -type Vehicle implements Node { - """ - The name of this vehicle. The common name, such as "Sand Crawler" or "Speeder - bike". - """ - name: String - - """ - The model or official name of this vehicle. Such as "All-Terrain Attack - Transport". - """ - model: String - - """The class of this vehicle, such as "Wheeled" or "Repulsorcraft".""" - vehicleClass: String - - """The manufacturers of this vehicle.""" - manufacturers: [String] - - """The cost of this vehicle new, in Galactic Credits.""" - costInCredits: Float - - """The length of this vehicle in meters.""" - length: Float - - """The number of personnel needed to run or pilot this vehicle.""" - crew: String - - """The number of non-essential people this vehicle can transport.""" - passengers: String - - """The maximum speed of this vehicle in atmosphere.""" - maxAtmospheringSpeed: Int - - """The maximum number of kilograms that this vehicle can transport.""" - cargoCapacity: Float - - """ - The maximum length of time that this vehicle can provide consumables for its - entire crew without having to resupply. - """ - consumables: String - pilotConnection(after: String, first: Int, before: String, last: Int): VehiclePilotsConnection - filmConnection(after: String, first: Int, before: String, last: Int): VehicleFilmsConnection - - """The ISO 8601 date format of the time that this resource was created.""" - created: String - - """The ISO 8601 date format of the time that this resource was edited.""" - edited: String - - """The ID of an object""" - id: ID! -} - -"""A connection to a list of items.""" -type VehicleFilmsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [VehicleFilmsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - films: [Film] -} - -"""An edge in a connection.""" -type VehicleFilmsEdge { - """The item at the end of the edge""" - node: Film - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type VehiclePilotsConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [VehiclePilotsEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - pilots: [Person] -} - -"""An edge in a connection.""" -type VehiclePilotsEdge { - """The item at the end of the edge""" - node: Person - - """A cursor for use in pagination""" - cursor: String! -} - -"""A connection to a list of items.""" -type VehiclesConnection { - """Information to aid in pagination.""" - pageInfo: PageInfo! - - """A list of edges.""" - edges: [VehiclesEdge] - - """ - A count of the total number of objects in this connection, ignoring pagination. - This allows a client to fetch the first five objects by passing "5" as the - argument to "first", then fetch the total count so it could display "5 of 83", - for example. - """ - totalCount: Int - - """ - A list of all of the objects returned in the connection. This is a convenience - field provided for quickly exploring the API; rather than querying for - "{ edges { node } }" when no edge data is needed, this field can be be used - instead. Note that when clients like Relay need to fetch the "cursor" field on - the edge to enable efficient pagination, this shortcut cannot be used, and the - full "{ edges { node } }" version should be used instead. - """ - vehicles: [Vehicle] -} - -"""An edge in a connection.""" -type VehiclesEdge { - """The item at the end of the edge""" - node: Vehicle - - """A cursor for use in pagination""" - cursor: String! -}` diff --git a/pkg/graphql/starwars_helpers_test.go b/pkg/graphql/starwars_helpers_test.go deleted file mode 100644 index a89ad40e1..000000000 --- a/pkg/graphql/starwars_helpers_test.go +++ /dev/null @@ -1,41 +0,0 @@ -package graphql - -import ( - "bytes" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/starwars" -) - -func starwarsSchema(t *testing.T) *Schema { - starwars.SetRelativePathToStarWarsPackage("../starwars") - schemaBytes := starwars.Schema(t) - - schema, err := NewSchemaFromString(string(schemaBytes)) - require.NoError(t, err) - - return schema -} - -func requestForQuery(t *testing.T, fileName string) Request { - rawRequest := starwars.LoadQuery(t, fileName, nil) - - var request Request - err := UnmarshalRequest(bytes.NewBuffer(rawRequest), &request) - require.NoError(t, err) - - return request -} - -func loadStarWarsQuery(starwarsFile string, variables starwars.QueryVariables) func(t *testing.T) Request { - return func(t *testing.T) Request { - query := starwars.LoadQuery(t, starwarsFile, variables) - request := Request{} - err := UnmarshalRequest(bytes.NewBuffer(query), &request) - require.NoError(t, err) - - return request - } -} diff --git a/pkg/graphql/subscription.go b/pkg/graphql/subscription.go deleted file mode 100644 index 869fb0a57..000000000 --- a/pkg/graphql/subscription.go +++ /dev/null @@ -1,16 +0,0 @@ -package graphql - -type SubscriptionType int - -const ( - // SubscriptionTypeUnknown is for unknown or undefined subscriptions. - SubscriptionTypeUnknown = iota - // SubscriptionTypeSSE is for Server-Sent Events (SSE) subscriptions. - SubscriptionTypeSSE - // SubscriptionTypeGraphQLWS is for subscriptions using a WebSocket connection with - // 'graphql-ws' as protocol. - SubscriptionTypeGraphQLWS - // SubscriptionTypeGraphQLTransportWS is for subscriptions using a WebSocket connection with - // 'graphql-transport-ws' as protocol. - SubscriptionTypeGraphQLTransportWS -) diff --git a/pkg/graphql/types.go b/pkg/graphql/types.go deleted file mode 100644 index f9844bf95..000000000 --- a/pkg/graphql/types.go +++ /dev/null @@ -1,11 +0,0 @@ -package graphql - -type ( - Type struct { - Name string `json:"name"` - Fields []string `json:"fields"` - } - - RequestFields map[string]struct{} - RequestTypes map[string]RequestFields -) diff --git a/pkg/graphql/validation.go b/pkg/graphql/validation.go deleted file mode 100644 index 0d50fa96f..000000000 --- a/pkg/graphql/validation.go +++ /dev/null @@ -1,96 +0,0 @@ -package graphql - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/astvalidation" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type ValidationResult struct { - Valid bool - Errors ValidationErrors -} - -type ValidationErrors Errors - -func (r *Request) ValidateForSchema(schema *Schema) (result ValidationResult, err error) { - if schema == nil { - return ValidationResult{Valid: false, Errors: nil}, ErrNilSchema - } - - schemaHash := schema.Hash() - - if r.validForSchema == nil { - r.validForSchema = map[uint64]ValidationResult{} - } - - if result, ok := r.validForSchema[schemaHash]; ok { - return result, nil - } - - report := r.parseQueryOnce() - if report.HasErrors() { - return operationValidationResultFromReport(report) - } - - validator := astvalidation.DefaultOperationValidator() - validator.Validate(&r.document, &schema.document, &report) - result, err = operationValidationResultFromReport(report) - if err != nil { - return result, err - } - r.validForSchema[schemaHash] = result - return result, err -} - -// ValidateRestrictedFields validates a request by checking if `restrictedFields` contains blocked fields. -// -// Deprecated: This function can only handle blocked fields. Use `ValidateFieldRestrictions` if you -// want to check for blocked or allowed fields instead. -func (r *Request) ValidateRestrictedFields(schema *Schema, restrictedFields []Type) (RequestFieldsValidationResult, error) { - if schema == nil { - return RequestFieldsValidationResult{Valid: false}, ErrNilSchema - } - - report := r.parseQueryOnce() - if report.HasErrors() { - return fieldsValidationResult(report, false, "", "") - } - - var fieldsValidator RequestFieldsValidator = DefaultFieldsValidator{} - return fieldsValidator.Validate(r, schema, restrictedFields) -} - -// ValidateFieldRestrictions will validate a request by using a list of allowed or blocked fields. -func (r *Request) ValidateFieldRestrictions(schema *Schema, restrictedFieldsList FieldRestrictionList, validator FieldRestrictionValidator) (RequestFieldsValidationResult, error) { - if schema == nil { - return RequestFieldsValidationResult{Valid: false}, ErrNilSchema - } - - report := r.parseQueryOnce() - if report.HasErrors() { - return fieldsValidationResult(report, false, "", "") - } - - return validator.ValidateByFieldList(r, schema, restrictedFieldsList) -} - -func operationValidationResultFromReport(report operationreport.Report) (ValidationResult, error) { - result := ValidationResult{ - Valid: false, - Errors: nil, - } - - if !report.HasErrors() { - result.Valid = true - return result, nil - } - - result.Errors = RequestErrorsFromOperationReport(report) - - var err error - if len(report.InternalErrors) > 0 { - err = report.InternalErrors[0] - } - - return result, err -} diff --git a/pkg/graphql/validation_test.go b/pkg/graphql/validation_test.go deleted file mode 100644 index fd8f059ca..000000000 --- a/pkg/graphql/validation_test.go +++ /dev/null @@ -1,323 +0,0 @@ -package graphql - -import ( - "bytes" - "errors" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" - "github.com/wundergraph/graphql-go-tools/pkg/starwars" -) - -func TestRequest_ValidateForSchema(t *testing.T) { - t.Run("should return error when schema is nil", func(t *testing.T) { - request := Request{ - OperationName: "Hello", - Variables: nil, - Query: `query Hello { hello }`, - } - - result, err := request.ValidateForSchema(nil) - assert.Error(t, err) - assert.Equal(t, ErrNilSchema, err) - assert.Equal(t, ValidationResult{Valid: false, Errors: nil}, result) - }) - - t.Run("should return gql errors no valid operation is in the the request", func(t *testing.T) { - request := Request{} - - schema, err := NewSchemaFromString("schema { query: Query } type Query { hello: String }") - require.NoError(t, err) - - result, err := request.ValidateForSchema(schema) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Greater(t, result.Errors.Count(), 0) - }) - - t.Run("should return gql errors when validation fails", func(t *testing.T) { - request := Request{ - OperationName: "Goodbye", - Variables: nil, - Query: `query Goodbye { goodbye }`, - } - - schema, err := NewSchemaFromString("schema { query: Query } type Query { hello: String }") - require.NoError(t, err) - - result, err := request.ValidateForSchema(schema) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Greater(t, result.Errors.Count(), 0) - }) - - t.Run("should successfully validate even when schema definition is missing", func(t *testing.T) { - request := Request{ - OperationName: "Hello", - Variables: nil, - Query: `query Hello { hello }`, - } - - schema, err := NewSchemaFromString("type Query { hello: String }") - require.NoError(t, err) - - result, err := request.ValidateForSchema(schema) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Nil(t, result.Errors) - }) - - t.Run("should return valid result for introspection query after normalization", func(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileIntrospectionQuery) - - normalizationResult, err := request.Normalize(schema) - require.NoError(t, err) - require.True(t, normalizationResult.Successful) - require.True(t, request.IsNormalized()) - - result, err := request.ValidateForSchema(schema) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Nil(t, result.Errors) - }) - - t.Run("should return valid result when validation is successful", func(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - - result, err := request.ValidateForSchema(schema) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Nil(t, result.Errors) - }) -} - -func TestRequest_ValidateRestrictedFields(t *testing.T) { - t.Run("should return error when schema is nil", func(t *testing.T) { - request := Request{} - result, err := request.ValidateRestrictedFields(nil, nil) - assert.Error(t, err) - assert.Equal(t, ErrNilSchema, err) - assert.False(t, result.Valid) - }) - - t.Run("should allow request when no restrictions set", func(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - - result, err := request.ValidateRestrictedFields(schema, nil) - assert.NoError(t, err) - assert.True(t, result.Valid) - }) - - t.Run("when restrictions set", func(t *testing.T) { - schema := starwarsSchema(t) - restrictedFields := []Type{ - {Name: "Query", Fields: []string{"droid"}}, - {Name: "Mutation", Fields: []string{"createReview"}}, - {Name: "Character", Fields: []string{"friends"}}, - {Name: "Starship", Fields: []string{"length"}}, - } - - t.Run("should allow request", func(t *testing.T) { - t.Run("when only allowed fields requested", func(t *testing.T) { - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - result, err := request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Empty(t, result.Errors) - - request = requestForQuery(t, starwars.FileHeroWithAliasesQuery) - result, err = request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Empty(t, result.Errors) - }) - }) - - t.Run("should disallow request", func(t *testing.T) { - t.Run("when query is restricted", func(t *testing.T) { - request := requestForQuery(t, starwars.FileDroidWithArgAndVarQuery) - result, err := request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - - var buf bytes.Buffer - _, _ = result.Errors.WriteResponse(&buf) - assert.Equal(t, `{"errors":[{"message":"field: droid is restricted on type: Query"}]}`, buf.String()) - }) - - t.Run("when mutation is restricted", func(t *testing.T) { - request := requestForQuery(t, starwars.FileCreateReviewMutation) - result, err := request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - }) - - t.Run("when type field is restricted", func(t *testing.T) { - request := requestForQuery(t, starwars.FileUnionQuery) - result, err := request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - }) - - t.Run("when mutation response type has restricted field", func(t *testing.T) { - restrictedFields := []Type{ - {Name: "Review", Fields: []string{"id"}}, - } - - request := requestForQuery(t, starwars.FileCreateReviewMutation) - result, err := request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - }) - }) - }) - -} - -func TestRequest_ValidateFieldRestrictions(t *testing.T) { - validator := DefaultFieldsValidator{} - - t.Run("should return error when schema is nil", func(t *testing.T) { - request := Request{} - result, err := request.ValidateFieldRestrictions(nil, FieldRestrictionList{}, validator) - assert.Error(t, err) - assert.Equal(t, ErrNilSchema, err) - assert.False(t, result.Valid) - }) - - t.Run("should allow request when no restrictions set", func(t *testing.T) { - schema := starwarsSchema(t) - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - - result, err := request.ValidateFieldRestrictions(schema, FieldRestrictionList{ - Kind: BlockList, - }, validator) - assert.NoError(t, err) - assert.True(t, result.Valid) - }) - - t.Run("when restrictions set", func(t *testing.T) { - schema := starwarsSchema(t) - restrictedFields := []Type{ - {Name: "Query", Fields: []string{"droid"}}, - {Name: "Mutation", Fields: []string{"createReview"}}, - {Name: "Character", Fields: []string{"friends"}}, - {Name: "Starship", Fields: []string{"length"}}, - } - - t.Run("should allow request", func(t *testing.T) { - t.Run("when only allowed fields requested", func(t *testing.T) { - request := requestForQuery(t, starwars.FileSimpleHeroQuery) - result, err := request.ValidateFieldRestrictions(schema, FieldRestrictionList{ - Kind: BlockList, - Types: restrictedFields, - }, validator) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Empty(t, result.Errors) - - request = requestForQuery(t, starwars.FileHeroWithAliasesQuery) - result, err = request.ValidateRestrictedFields(schema, restrictedFields) - assert.NoError(t, err) - assert.True(t, result.Valid) - assert.Empty(t, result.Errors) - }) - }) - - t.Run("should disallow request", func(t *testing.T) { - t.Run("when query is restricted", func(t *testing.T) { - request := requestForQuery(t, starwars.FileDroidWithArgAndVarQuery) - result, err := request.ValidateFieldRestrictions(schema, FieldRestrictionList{ - Kind: BlockList, - Types: restrictedFields, - }, validator) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - - var buf bytes.Buffer - _, _ = result.Errors.WriteResponse(&buf) - assert.Equal(t, `{"errors":[{"message":"field: droid is restricted on type: Query"}]}`, buf.String()) - }) - - t.Run("when mutation is restricted", func(t *testing.T) { - request := requestForQuery(t, starwars.FileCreateReviewMutation) - result, err := request.ValidateFieldRestrictions(schema, FieldRestrictionList{ - Kind: BlockList, - Types: restrictedFields, - }, validator) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - }) - - t.Run("when type field is restricted", func(t *testing.T) { - request := requestForQuery(t, starwars.FileUnionQuery) - result, err := request.ValidateFieldRestrictions(schema, FieldRestrictionList{ - Kind: BlockList, - Types: restrictedFields, - }, validator) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - }) - - t.Run("when mutation response type has restricted field", func(t *testing.T) { - restrictedFields := []Type{ - {Name: "Review", Fields: []string{"id"}}, - } - - request := requestForQuery(t, starwars.FileCreateReviewMutation) - result, err := request.ValidateFieldRestrictions(schema, FieldRestrictionList{ - Kind: BlockList, - Types: restrictedFields, - }, validator) - assert.NoError(t, err) - assert.False(t, result.Valid) - assert.Error(t, result.Errors) - }) - }) - }) - -} - -func Test_operationValidationResultFromReport(t *testing.T) { - t.Run("should return result for valid when report does not have errors", func(t *testing.T) { - report := operationreport.Report{} - result, err := operationValidationResultFromReport(report) - - assert.NoError(t, err) - assert.Equal(t, ValidationResult{Valid: true, Errors: nil}, result) - }) - - t.Run("should return validation error and internal error when report contain them", func(t *testing.T) { - internalErr := errors.New("errors occurred") - externalErr := operationreport.ExternalError{ - Message: "graphql error", - Path: nil, - Locations: nil, - } - - report := operationreport.Report{} - report.AddInternalError(internalErr) - report.AddExternalError(externalErr) - - result, err := operationValidationResultFromReport(report) - - assert.Error(t, err) - assert.Equal(t, internalErr, err) - assert.False(t, result.Valid) - assert.Len(t, result.Errors.(RequestErrors), 1) - assert.Equal(t, "graphql error", result.Errors.(RequestErrors)[0].Message) - }) -} diff --git a/pkg/graphqlerrors/location.go b/pkg/graphqlerrors/location.go deleted file mode 100644 index 4658acd21..000000000 --- a/pkg/graphqlerrors/location.go +++ /dev/null @@ -1,6 +0,0 @@ -package graphqlerrors - -type Location struct { - Line uint32 `json:"line"` - Column uint32 `json:"column"` -} diff --git a/pkg/graphqljsonschema/jsonschema.go b/pkg/graphqljsonschema/jsonschema.go deleted file mode 100644 index 603560f93..000000000 --- a/pkg/graphqljsonschema/jsonschema.go +++ /dev/null @@ -1,414 +0,0 @@ -package graphqljsonschema - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/buger/jsonparser" - "github.com/santhosh-tekuri/jsonschema/v5" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -type options struct { - overrides map[string]JsonSchema - path []string -} - -type Option func(opts *options) - -func WithOverrides(overrides map[string]JsonSchema) Option { - return func(opts *options) { - opts.overrides = overrides - } -} - -func WithPath(path []string) Option { - return func(opts *options) { - opts.path = path - } -} - -func FromTypeRef(operation, definition *ast.Document, typeRef int, opts ...Option) JsonSchema { - appliedOptions := &options{} - for _, opt := range opts { - opt(appliedOptions) - } - - var resolver *fromTypeRefResolver - if len(appliedOptions.overrides) > 0 { - resolver = &fromTypeRefResolver{ - overrides: appliedOptions.overrides, - } - } else { - resolver = &fromTypeRefResolver{ - overrides: map[string]JsonSchema{}, - } - } - - jsonSchema := resolver.fromTypeRef(operation, definition, typeRef) - return resolveJsonSchemaPath(jsonSchema, appliedOptions.path) -} - -func resolveJsonSchemaPath(jsonSchema JsonSchema, path []string) JsonSchema { - switch typedJsonSchema := jsonSchema.(type) { - case Object: - for i := 0; i < len(path); i++ { - propertyJsonSchema, exists := typedJsonSchema.Properties[path[i]] - if !exists { - return jsonSchema - } - jsonSchema = propertyJsonSchema - } - } - - return jsonSchema -} - -type fromTypeRefResolver struct { - overrides map[string]JsonSchema - defs *map[string]JsonSchema -} - -func (r *fromTypeRefResolver) fromTypeRef(operation, definition *ast.Document, typeRef int) JsonSchema { - - t := operation.Types[typeRef] - - nonNull := false - if operation.TypeIsNonNull(typeRef) { - t = operation.Types[t.OfType] - nonNull = true - } - - switch t.TypeKind { - case ast.TypeKindList: - var defs map[string]JsonSchema - isRoot := false - if r.defs == nil { - defs = make(map[string]JsonSchema, 48) - r.defs = &defs - isRoot = true - } - itemSchema := r.fromTypeRef(operation, definition, t.OfType) - arr := NewArray(itemSchema, nonNull) - if isRoot { - arr.Defs = defs - } - return arr - case ast.TypeKindNonNull: - panic("Should not be able to have multiple levels of non-null") - case ast.TypeKindNamed: - name := operation.Input.ByteSliceString(t.Name) - if schema, ok := r.overrides[name]; ok { - return schema - } - typeDefinitionNode, ok := definition.Index.FirstNodeByNameStr(name) - if !ok { - return NewAny() - } - if typeDefinitionNode.Kind == ast.NodeKindEnumTypeDefinition { - return NewString(nonNull) - } - if typeDefinitionNode.Kind == ast.NodeKindScalarTypeDefinition { - switch name { - case "Boolean": - return NewBoolean(nonNull) - case "String": - return NewString(nonNull) - case "ID": - return NewID(nonNull) - case "Int": - return NewInteger(nonNull) - case "Float": - return NewNumber(nonNull) - case "_Any": - return NewObjectAny(nonNull) - default: - return NewAny() - } - } - object := NewObject(nonNull) - isRootObject := false - if r.defs == nil { - isRootObject = true - object.Defs = make(map[string]JsonSchema, 48) - r.defs = &object.Defs - } - if !isRootObject { - if _, exists := (*r.defs)[name]; exists { - return NewRef(name) - } - (*r.defs)[name] = object - } - if node, ok := definition.Index.FirstNodeByNameStr(name); ok { - switch node.Kind { - case ast.NodeKindInputObjectTypeDefinition: - for _, ref := range definition.InputObjectTypeDefinitions[node.Ref].InputFieldsDefinition.Refs { - fieldName := definition.Input.ByteSliceString(definition.InputValueDefinitions[ref].Name) - fieldType := definition.InputValueDefinitions[ref].Type - fieldSchema := r.fromTypeRef(definition, definition, fieldType) - object.Properties[fieldName] = fieldSchema - if definition.TypeIsNonNull(fieldType) { - object.Required = append(object.Required, fieldName) - } - } - case ast.NodeKindObjectTypeDefinition: - for _, ref := range definition.ObjectTypeDefinitions[node.Ref].FieldsDefinition.Refs { - fieldName := definition.Input.ByteSliceString(definition.FieldDefinitions[ref].Name) - fieldType := definition.FieldDefinitions[ref].Type - fieldSchema := r.fromTypeRef(definition, definition, fieldType) - object.Properties[fieldName] = fieldSchema - if definition.TypeIsNonNull(fieldType) { - object.Required = append(object.Required, fieldName) - } - } - } - } - if !isRootObject { - (*r.defs)[name] = object - return NewRef(name) - } - return object - } - return NewObject(nonNull) -} - -type Validator struct { - schema *jsonschema.Schema -} - -func NewValidatorFromSchema(schema JsonSchema) (*Validator, error) { - s, err := json.Marshal(schema) - if err != nil { - return nil, err - } - return NewValidatorFromString(string(s)) -} - -func MustNewValidatorFromSchema(schema JsonSchema) *Validator { - s, err := json.Marshal(schema) - if err != nil { - panic(err) - } - return MustNewValidatorFromString(string(s)) -} - -func NewValidatorFromString(schema string) (*Validator, error) { - sch, err := jsonschema.CompileString("schema.json", schema) - if err != nil { - return nil, err - } - return &Validator{ - schema: sch, - }, nil -} - -func MustNewValidatorFromString(schema string) *Validator { - validator, err := NewValidatorFromString(schema) - if err != nil { - panic(err) - } - return validator -} - -func (v *Validator) Validate(ctx context.Context, inputJSON []byte) error { - var value interface{} - if err := json.Unmarshal(inputJSON, &value); err != nil { - return err - } - if err := v.schema.Validate(value); err != nil { - return err - } - return nil -} - -func TopLevelType(schema string) (jsonparser.ValueType, error) { - sch, err := jsonschema.CompileString("schema.json", schema) - if err != nil { - return jsonparser.Unknown, err - } - switch sch.Types[0] { - case "boolean": - return jsonparser.Boolean, nil - case "string": - return jsonparser.String, nil - case "object": - return jsonparser.Object, nil - case "number": - return jsonparser.Number, nil - case "integer": - return jsonparser.Number, nil - case "null": - return jsonparser.Null, nil - case "array": - return jsonparser.Array, nil - default: - return jsonparser.NotExist, nil - } -} - -type Kind int - -const ( - StringKind Kind = iota + 1 - NumberKind - BooleanKind - IntegerKind - ObjectKind - ArrayKind - AnyKind - IDKind - RefKind -) - -func maybeAppendNull(nonNull bool, types ...string) []string { - if nonNull { - return types - } - return append(types, "null") -} - -type JsonSchema interface { - Kind() Kind -} - -type Any struct{} - -func NewAny() Any { - return Any{} -} - -func (a Any) Kind() Kind { - return AnyKind -} - -type String struct { - Type []string `json:"type"` -} - -func (String) Kind() Kind { - return StringKind -} - -func NewString(nonNull bool) String { - return String{ - Type: maybeAppendNull(nonNull, "string"), - } -} - -type ID struct { - Type []string `json:"type"` -} - -func (ID) Kind() Kind { - return IDKind -} - -func NewID(nonNull bool) ID { - return ID{ - Type: maybeAppendNull(nonNull, "string", "integer"), - } -} - -type Boolean struct { - Type []string `json:"type"` -} - -func (Boolean) Kind() Kind { - return BooleanKind -} - -func NewBoolean(nonNull bool) Boolean { - return Boolean{ - Type: maybeAppendNull(nonNull, "boolean"), - } -} - -type Number struct { - Type []string `json:"type"` -} - -func NewNumber(nonNull bool) Number { - return Number{ - Type: maybeAppendNull(nonNull, "number"), - } -} - -func (Number) Kind() Kind { - return NumberKind -} - -type Integer struct { - Type []string `json:"type"` -} - -func (Integer) Kind() Kind { - return IntegerKind -} - -func NewInteger(nonNull bool) Integer { - return Integer{ - Type: maybeAppendNull(nonNull, "integer"), - } -} - -type Ref struct { - Ref string `json:"$ref"` -} - -func (Ref) Kind() Kind { - return RefKind -} - -func NewRef(definitionName string) Ref { - return Ref{ - Ref: fmt.Sprintf("#/$defs/%s", definitionName), - } -} - -type Object struct { - Type []string `json:"type"` - Properties map[string]JsonSchema `json:"properties,omitempty"` - Required []string `json:"required,omitempty"` - AdditionalProperties bool `json:"additionalProperties"` - Defs map[string]JsonSchema `json:"$defs,omitempty"` -} - -func (Object) Kind() Kind { - return ObjectKind -} - -func NewObject(nonNull bool) Object { - return Object{ - Type: maybeAppendNull(nonNull, "object"), - Properties: map[string]JsonSchema{}, - AdditionalProperties: false, - } -} - -func NewObjectAny(nonNull bool) Object { - return Object{ - Type: maybeAppendNull(nonNull, "object"), - Properties: map[string]JsonSchema{}, - AdditionalProperties: true, - } -} - -type Array struct { - Type []string `json:"type"` - Items JsonSchema `json:"items"` - MinItems *int `json:"minItems,omitempty"` - Defs map[string]JsonSchema `json:"$defs,omitempty"` -} - -func (Array) Kind() Kind { - return ArrayKind -} - -func NewArray(itemSchema JsonSchema, nonNull bool) Array { - return Array{ - Type: maybeAppendNull(nonNull, "array"), - Items: itemSchema, - } -} diff --git a/pkg/graphqljsonschema/jsonschema_test.go b/pkg/graphqljsonschema/jsonschema_test.go deleted file mode 100644 index 1dc654dd8..000000000 --- a/pkg/graphqljsonschema/jsonschema_test.go +++ /dev/null @@ -1,1641 +0,0 @@ -package graphqljsonschema - -import ( - "context" - "encoding/json" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func prettyPrint(s string) string { - var v interface{} - if err := json.Unmarshal([]byte(s), &v); err != nil { - panic(err) - } - pretty, err := json.MarshalIndent(v, " ", " ") - if err != nil { - panic(err) - } - return string(pretty) -} - -func runTest(schema, operation, expectedJsonSchema string, valid []string, invalid []string, opts ...Option) func(t *testing.T) { - return func(t *testing.T) { - definition := unsafeparser.ParseGraphqlDocumentString(schema) - operationDoc := unsafeparser.ParseGraphqlDocumentString(operation) - - variableDefinition := operationDoc.OperationDefinitions[0].VariableDefinitions.Refs[0] - varType := operationDoc.VariableDefinitions[variableDefinition].Type - - jsonSchemaDefinition := FromTypeRef(&operationDoc, &definition, varType, opts...) - actualSchema, err := json.Marshal(jsonSchemaDefinition) - assert.NoError(t, err) - assert.Equal(t, prettyPrint(expectedJsonSchema), prettyPrint(string(actualSchema))) - - validator, err := NewValidatorFromString(string(actualSchema)) - assert.NoError(t, err) - - for _, input := range valid { - assert.NoError(t, validator.Validate(context.Background(), []byte(input)), "Incorrectly judged invalid: %v", input) - } - - for _, input := range invalid { - assert.Error(t, validator.Validate(context.Background(), []byte(input)), "Incorrectly judged valid: %v", input) - } - } -} - -func TestJsonSchema(t *testing.T) { - t.Run("object", runTest( - `scalar String input Test { str: String }`, - `query ($input: Test){}`, - `{"type":["object","null"],"properties":{"str":{"type":["string","null"]}},"additionalProperties":false}`, - []string{ - `{"str":"validString"}`, - `{"str":null}`, - }, - []string{ - `{"str":true}`, - }, - )) - t.Run("string", runTest( - `scalar String input Test { str: String }`, - `query ($input: String){}`, - `{"type":["string","null"]}`, - []string{ - `"validString"`, - `null`, - }, - []string{ - `false`, - `true`, - `nope`, - }, - )) - t.Run("string (required)", runTest( - `scalar String type Query { rootField(str: String!): String! }`, - `query ($input: String!){ rootField(str: $input) }`, - `{"type":["string"]}`, - []string{ - `"validString"`, - }, - []string{ - `false`, - `true`, - `nope`, - `null`, - }, - )) - t.Run("id", runTest( - `scalar ID input Test { str: String }`, - `query ($input: ID){}`, - `{"type":["string","integer","null"]}`, - []string{ - `"validString"`, - `null`, - }, - []string{ - `false`, - `true`, - `nope`, - }, - )) - t.Run("array", runTest( - `scalar String`, - `query ($input: [String]){}`, - `{"type":["array","null"],"items":{"type":["string","null"]}}`, - []string{ - `null`, - `[]`, - `["validString1"]`, - `["validString1", "validString2"]`, - `["validString1", "validString2", null]`, - }, - []string{ - `"validString"`, - `false`, - }, - )) - t.Run("input object array", runTest( - `scalar String input StringInput { str: String }`, - `query ($input: [StringInput]){}`, - `{"type":["array","null"],"items":{"$ref":"#/$defs/StringInput"},"$defs":{"StringInput":{"type":["object","null"],"properties":{"str":{"type":["string","null"]}},"additionalProperties":false}}}`, - []string{ - `null`, - `[]`, - `[{"str":"validString1"}]`, - `[{"str":"validString1"}, {"str":"validString2"}]`, - `[{"str":"validString1"}, {"str":"validString2"}, null]`, - }, - []string{ - `"validString"`, - `false`, - }, - )) - t.Run("required array", runTest( - `scalar String`, - `query ($input: [String]!){}`, - `{"type":["array"],"items":{"type":["string","null"]}}`, - []string{ - `[]`, - `["validString1"]`, - `["validString1", "validString2"]`, - `["validString1", "validString2", null]`, - }, - []string{ - `"validString"`, - `false`, - `null`, - }, - )) - t.Run("required array element", runTest( - `scalar String`, - `query ($input: [String!]){}`, - `{"type":["array","null"],"items":{"type":["string"]}}`, - []string{ - `null`, - `[]`, - `["validString1"]`, - `["validString1", "validString2"]`, - }, - []string{ - `[null]`, - `["validString1", "validString2", null]`, - `"validString"`, - `false`, - }, - )) - t.Run("nested object", runTest( - `scalar String scalar Boolean input Test { str: String! nested: Nested } input Nested { boo: Boolean }`, - `query ($input: Test){}`, - `{"type":["object","null"],"properties":{"nested":{"$ref":"#/$defs/Nested"},"str":{"type":["string"]}},"required":["str"],"additionalProperties":false,"$defs":{"Nested":{"type":["object","null"],"properties":{"boo":{"type":["boolean","null"]}},"additionalProperties":false}}}`, - []string{ - `null`, - `{"str":"validString"}`, - `{"str":"validString","nested":null}`, - `{"str":"validString","nested":{"boo":true}}`, - `{"str":"validString","nested":{"boo":null}}`, - `{"str":"validString","nested":{}}`, - }, - []string{ - `{"str":true}`, - `{"str":null}`, - `{"nested":{"boo":true}}`, - `{"str":"validString","nested":{"boo":123}}`, - }, - )) - t.Run("nested object with override", runTest( - `scalar String scalar Boolean input Test { str: String! override: Override } input Override { boo: Boolean }`, - `query ($input: Test){}`, - `{"type":["object","null"],"properties":{"override":{"type":["string","null"]},"str":{"type":["string"]}},"required":["str"],"additionalProperties":false}`, - []string{ - `null`, - `{"str":"validString"}`, - `{"str":"validString","override":"{\"boo\":true}"}`, - `{"str":"validString","override":null}`, - }, - []string{ - `{"str":true}`, - `{"str":null}`, - `{"override":{"boo":true}}`, - `{"str":"validString","override":{"boo":123}}`, - }, - WithOverrides(map[string]JsonSchema{ - "Override": NewString(false), - }), - )) - t.Run("recursive object", runTest( - `scalar String scalar Boolean input Test { str: String! nested: Nested } input Nested { boo: Boolean recursive: Test }`, - `query ($input: Test){}`, - `{"type":["object","null"],"properties":{"nested":{"$ref":"#/$defs/Nested"},"str":{"type":["string"]}},"required":["str"],"additionalProperties":false,"$defs":{"Nested":{"type":["object","null"],"properties":{"boo":{"type":["boolean","null"]},"recursive":{"$ref":"#/$defs/Test"}},"additionalProperties":false},"Test":{"type":["object","null"],"properties":{"nested":{"$ref":"#/$defs/Nested"},"str":{"type":["string"]}},"required":["str"],"additionalProperties":false}}}`, - []string{ - `{"str":"validString"}`, - `{"str":"validString","nested":{"boo":true}}`, - `{"str":"validString","nested":{"boo":null}}`, - `{"str":"validString","nested":null}`, - }, - []string{ - `{"str":true}`, - `{"nested":{"boo":true}}`, - `{"str":"validString","nested":{"boo":123}}`, - }, - )) - t.Run("recursive object with multiple branches", runTest( - `scalar String scalar Boolean input Root { test: Test another: Another } input Test { str: String! nested: Nested } input Nested { boo: Boolean recursive: Test another: Another } input Another { boo: Boolean }`, - `query ($input: Root){}`, - `{"type":["object","null"],"properties":{"another":{"$ref":"#/$defs/Another"},"test":{"$ref":"#/$defs/Test"}},"additionalProperties":false,"$defs":{"Another":{"type":["object","null"],"properties":{"boo":{"type":["boolean","null"]}},"additionalProperties":false},"Nested":{"type":["object","null"],"properties":{"another":{"$ref":"#/$defs/Another"},"boo":{"type":["boolean","null"]},"recursive":{"$ref":"#/$defs/Test"}},"additionalProperties":false},"Test":{"type":["object","null"],"properties":{"nested":{"$ref":"#/$defs/Nested"},"str":{"type":["string"]}},"required":["str"],"additionalProperties":false}}}`, - []string{ - `{"test":{"str":"validString"}}`, - `{"test":{"str":"validString","nested":{"boo":true}}}`, - }, - []string{ - `{"test":{"str":true}}`, - `{"test":{"nested":{"boo":true}}}`, - `{"test":{"str":"validString","nested":{"boo":123}}}`, - }, - )) - t.Run("complex recursive schema", runTest( - complexRecursiveSchema, - `query ($input: db_messagesWhereInput){}`, - complexRecursiveSchemaResult, - []string{}, - []string{}, - )) - t.Run("one level deep sub path", runTest( - "input Human { name: String! } scalar String", - "query ($human: Human!) { }", - `{"type":["string"]}`, - []string{ - `"John Doe"`, - }, - []string{ - `{"name":"John Doe"}`, - }, - WithPath([]string{"name"}), - )) - t.Run("multi level deep sub path", runTest( - "input Human { name: String! pet: Animal } scalar String type Animal { name: String! }", - "query ($human: Human!) { }", - `{"type":["string"]}`, - []string{ - `"Doggie"`, - }, - []string{ - `{"name":"Doggie"}`, - `{"pet":{"name":"Doggie"}}`, - }, - WithPath([]string{"pet", "name"}), - )) - t.Run("not defined scalar", runTest( - `input Container { name: MyScalar }`, - `query ($input: Container){}`, - `{"type":["object", "null"], "properties": {"name": {}}, "additionalProperties": false}`, - []string{}, - []string{}, - )) -} - -const complexRecursiveSchema = ` -scalar Int scalar String - -input db_NestedIntFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: db_NestedIntFilter -} - -input db_IntFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: db_NestedIntFilter -} - -enum db_QueryMode { - default - insensitive -} - -input db_NestedStringFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: db_NestedStringFilter -} - -input db_StringFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - mode: db_QueryMode - not: db_NestedStringFilter -} - -enum db_JsonNullValueFilter { - DbNull - JsonNull - AnyNull -} - -input db_JsonFilter { - equals: db_JsonNullValueFilter - not: db_JsonNullValueFilter -} - -input db_NestedDateTimeFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: db_NestedDateTimeFilter -} - -input db_DateTimeFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: db_NestedDateTimeFilter -} - -input db_MessagesListRelationFilter { - every: db_messagesWhereInput - some: db_messagesWhereInput - none: db_messagesWhereInput -} - -input db_usersWhereInput { - AND: db_usersWhereInput - OR: [db_usersWhereInput] - NOT: db_usersWhereInput - id: db_IntFilter - email: db_StringFilter - name: db_StringFilter - updatedat: db_DateTimeFilter - lastlogin: db_DateTimeFilter - pet: db_StringFilter - messages: db_MessagesListRelationFilter -} - -input db_UsersRelationFilter { - is: db_usersWhereInput - isNot: db_usersWhereInput -} - -input db_messagesWhereInput { - AND: db_messagesWhereInput - OR: [db_messagesWhereInput] - NOT: db_messagesWhereInput - id: db_IntFilter - user_id: db_IntFilter - message: db_StringFilter - payload: db_JsonFilter - users: db_UsersRelationFilter -} - -enum db_SortOrder { - asc - desc -} - -input db_messagesOrderByRelationAggregateInput { - _count: db_SortOrder -} - -input db_usersOrderByWithRelationInput { - id: db_SortOrder - email: db_SortOrder - name: db_SortOrder - updatedat: db_SortOrder - lastlogin: db_SortOrder - pet: db_SortOrder - messages: db_messagesOrderByRelationAggregateInput -} - -input db_messagesOrderByWithRelationInput { - id: db_SortOrder - user_id: db_SortOrder - message: db_SortOrder - payload: db_SortOrder - users: db_usersOrderByWithRelationInput -} - -input db_messagesWhereUniqueInput { - id: Int -} - -enum db_MessagesScalarFieldEnum { - id - user_id - message - payload -} - -type db_UsersCountOutputType { - messages: Int! - _join: Query! -} - -type db_users { - id: Int! - email: String! - name: String! - updatedat: DateTime! - lastlogin: DateTime! - pet: String! - messages(where: db_messagesWhereInput, orderBy: [db_messagesOrderByWithRelationInput], cursor: db_messagesWhereUniqueInput, take: Int, skip: Int, distinct: [db_MessagesScalarFieldEnum]): [db_messages] - _count: db_UsersCountOutputType - _join: Query! -} - -type db_messages { - id: Int! - user_id: Int! - message: String! - payload: db_Widgets! - users: db_users! - _join: Query! -} - -type db_MessagesCountAggregateOutputType { - id: Int! - user_id: Int! - message: Int! - payload: Int! - _all: Int! - _join: Query! -} - -type db_MessagesAvgAggregateOutputType { - id: Float - user_id: Float - _join: Query! -} - -type db_MessagesSumAggregateOutputType { - id: Int - user_id: Int - _join: Query! -} - -type db_MessagesMinAggregateOutputType { - id: Int - user_id: Int - message: String - _join: Query! -} - -type db_MessagesMaxAggregateOutputType { - id: Int - user_id: Int - message: String - _join: Query! -} - -type db_AggregateMessages { - _count: db_MessagesCountAggregateOutputType - _avg: db_MessagesAvgAggregateOutputType - _sum: db_MessagesSumAggregateOutputType - _min: db_MessagesMinAggregateOutputType - _max: db_MessagesMaxAggregateOutputType - _join: Query! -} - -input db_messagesCountOrderByAggregateInput { - id: db_SortOrder - user_id: db_SortOrder - message: db_SortOrder - payload: db_SortOrder -} - -input db_messagesAvgOrderByAggregateInput { - id: db_SortOrder - user_id: db_SortOrder -} - -input db_messagesMaxOrderByAggregateInput { - id: db_SortOrder - user_id: db_SortOrder - message: db_SortOrder -} - -input db_messagesMinOrderByAggregateInput { - id: db_SortOrder - user_id: db_SortOrder - message: db_SortOrder -} - -input db_messagesSumOrderByAggregateInput { - id: db_SortOrder - user_id: db_SortOrder -} - -input db_messagesOrderByWithAggregationInput { - id: db_SortOrder - user_id: db_SortOrder - message: db_SortOrder - payload: db_SortOrder - _count: db_messagesCountOrderByAggregateInput - _avg: db_messagesAvgOrderByAggregateInput - _max: db_messagesMaxOrderByAggregateInput - _min: db_messagesMinOrderByAggregateInput - _sum: db_messagesSumOrderByAggregateInput -} - -input db_NestedFloatFilter { - equals: Float - in: [Float] - notIn: [Float] - lt: Float - lte: Float - gt: Float - gte: Float - not: db_NestedFloatFilter -} - -input db_NestedIntWithAggregatesFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: db_NestedIntWithAggregatesFilter - _count: db_NestedIntFilter - _avg: db_NestedFloatFilter - _sum: db_NestedIntFilter - _min: db_NestedIntFilter - _max: db_NestedIntFilter -} - -input db_IntWithAggregatesFilter { - equals: Int - in: [Int] - notIn: [Int] - lt: Int - lte: Int - gt: Int - gte: Int - not: db_NestedIntWithAggregatesFilter - _count: db_NestedIntFilter - _avg: db_NestedFloatFilter - _sum: db_NestedIntFilter - _min: db_NestedIntFilter - _max: db_NestedIntFilter -} - -input db_NestedStringWithAggregatesFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - not: db_NestedStringWithAggregatesFilter - _count: db_NestedIntFilter - _min: db_NestedStringFilter - _max: db_NestedStringFilter -} - -input db_StringWithAggregatesFilter { - equals: String - in: [String] - notIn: [String] - lt: String - lte: String - gt: String - gte: String - contains: String - startsWith: String - endsWith: String - mode: db_QueryMode - not: db_NestedStringWithAggregatesFilter - _count: db_NestedIntFilter - _min: db_NestedStringFilter - _max: db_NestedStringFilter -} - -input db_NestedJsonFilter { - equals: db_JsonNullValueFilter - not: db_JsonNullValueFilter -} - -input db_JsonWithAggregatesFilter { - equals: db_JsonNullValueFilter - not: db_JsonNullValueFilter - _count: db_NestedIntFilter - _min: db_NestedJsonFilter - _max: db_NestedJsonFilter -} - -input db_messagesScalarWhereWithAggregatesInput { - AND: db_messagesScalarWhereWithAggregatesInput - OR: [db_messagesScalarWhereWithAggregatesInput] - NOT: db_messagesScalarWhereWithAggregatesInput - id: db_IntWithAggregatesFilter - user_id: db_IntWithAggregatesFilter - message: db_StringWithAggregatesFilter - payload: db_JsonWithAggregatesFilter -} - -type db_MessagesGroupByOutputType { - id: Int! - user_id: Int! - message: String! - payload: JSON! - _count: db_MessagesCountAggregateOutputType - _avg: db_MessagesAvgAggregateOutputType - _sum: db_MessagesSumAggregateOutputType - _min: db_MessagesMinAggregateOutputType - _max: db_MessagesMaxAggregateOutputType - _join: Query! -} - -input db_usersWhereUniqueInput { - id: Int - email: String -} - -enum db_UsersScalarFieldEnum { - id - email - name - updatedat - lastlogin - pet -} - -type db_UsersCountAggregateOutputType { - id: Int! - email: Int! - name: Int! - updatedat: Int! - lastlogin: Int! - pet: Int! - _all: Int! - _join: Query! -} - -type db_UsersAvgAggregateOutputType { - id: Float - _join: Query! -} - -type db_UsersSumAggregateOutputType { - id: Int - _join: Query! -} - -type db_UsersMinAggregateOutputType { - id: Int - email: String - name: String - updatedat: DateTime - lastlogin: DateTime - pet: String - _join: Query! -} - -type db_UsersMaxAggregateOutputType { - id: Int - email: String - name: String - updatedat: DateTime - lastlogin: DateTime - pet: String - _join: Query! -} - -type db_AggregateUsers { - _count: db_UsersCountAggregateOutputType - _avg: db_UsersAvgAggregateOutputType - _sum: db_UsersSumAggregateOutputType - _min: db_UsersMinAggregateOutputType - _max: db_UsersMaxAggregateOutputType - _join: Query! -} - -input db_usersCountOrderByAggregateInput { - id: db_SortOrder - email: db_SortOrder - name: db_SortOrder - updatedat: db_SortOrder - lastlogin: db_SortOrder - pet: db_SortOrder -} - -input db_usersAvgOrderByAggregateInput { - id: db_SortOrder -} - -input db_usersMaxOrderByAggregateInput { - id: db_SortOrder - email: db_SortOrder - name: db_SortOrder - updatedat: db_SortOrder - lastlogin: db_SortOrder - pet: db_SortOrder -} - -input db_usersMinOrderByAggregateInput { - id: db_SortOrder - email: db_SortOrder - name: db_SortOrder - updatedat: db_SortOrder - lastlogin: db_SortOrder - pet: db_SortOrder -} - -input db_usersSumOrderByAggregateInput { - id: db_SortOrder -} - -input db_usersOrderByWithAggregationInput { - id: db_SortOrder - email: db_SortOrder - name: db_SortOrder - updatedat: db_SortOrder - lastlogin: db_SortOrder - pet: db_SortOrder - _count: db_usersCountOrderByAggregateInput - _avg: db_usersAvgOrderByAggregateInput - _max: db_usersMaxOrderByAggregateInput - _min: db_usersMinOrderByAggregateInput - _sum: db_usersSumOrderByAggregateInput -} - -input db_NestedDateTimeWithAggregatesFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: db_NestedDateTimeWithAggregatesFilter - _count: db_NestedIntFilter - _min: db_NestedDateTimeFilter - _max: db_NestedDateTimeFilter -} - -input db_DateTimeWithAggregatesFilter { - equals: DateTime - in: [DateTime] - notIn: [DateTime] - lt: DateTime - lte: DateTime - gt: DateTime - gte: DateTime - not: db_NestedDateTimeWithAggregatesFilter - _count: db_NestedIntFilter - _min: db_NestedDateTimeFilter - _max: db_NestedDateTimeFilter -} - -input db_usersScalarWhereWithAggregatesInput { - AND: db_usersScalarWhereWithAggregatesInput - OR: [db_usersScalarWhereWithAggregatesInput] - NOT: db_usersScalarWhereWithAggregatesInput - id: db_IntWithAggregatesFilter - email: db_StringWithAggregatesFilter - name: db_StringWithAggregatesFilter - updatedat: db_DateTimeWithAggregatesFilter - lastlogin: db_DateTimeWithAggregatesFilter - pet: db_StringWithAggregatesFilter -} - -type db_UsersGroupByOutputType { - id: Int! - email: String! - name: String! - updatedat: DateTime! - lastlogin: DateTime! - pet: String! - _count: db_UsersCountAggregateOutputType - _avg: db_UsersAvgAggregateOutputType - _sum: db_UsersSumAggregateOutputType - _min: db_UsersMinAggregateOutputType - _max: db_UsersMaxAggregateOutputType - _join: Query! -} - -type Query { - db_findFirstmessages(where: db_messagesWhereInput, orderBy: [db_messagesOrderByWithRelationInput], cursor: db_messagesWhereUniqueInput, take: Int, skip: Int, distinct: [db_MessagesScalarFieldEnum]): db_messages - db_findManymessages(where: db_messagesWhereInput, orderBy: [db_messagesOrderByWithRelationInput], cursor: db_messagesWhereUniqueInput, take: Int, skip: Int, distinct: [db_MessagesScalarFieldEnum]): [db_messages]! - db_aggregatemessages(where: db_messagesWhereInput, orderBy: [db_messagesOrderByWithRelationInput], cursor: db_messagesWhereUniqueInput, take: Int, skip: Int): db_AggregateMessages! - db_groupBymessages(where: db_messagesWhereInput, orderBy: [db_messagesOrderByWithAggregationInput], by: [db_MessagesScalarFieldEnum]!, having: db_messagesScalarWhereWithAggregatesInput, take: Int, skip: Int): [db_MessagesGroupByOutputType]! - db_findUniquemessages(where: db_messagesWhereUniqueInput!): db_messages - db_findFirstusers(where: db_usersWhereInput, orderBy: [db_usersOrderByWithRelationInput], cursor: db_usersWhereUniqueInput, take: Int, skip: Int, distinct: [db_UsersScalarFieldEnum]): db_users - db_findManyusers(where: db_usersWhereInput, orderBy: [db_usersOrderByWithRelationInput], cursor: db_usersWhereUniqueInput, take: Int, skip: Int, distinct: [db_UsersScalarFieldEnum]): [db_users]! - db_aggregateusers(where: db_usersWhereInput, orderBy: [db_usersOrderByWithRelationInput], cursor: db_usersWhereUniqueInput, take: Int, skip: Int): db_AggregateUsers! - db_groupByusers(where: db_usersWhereInput, orderBy: [db_usersOrderByWithAggregationInput], by: [db_UsersScalarFieldEnum]!, having: db_usersScalarWhereWithAggregatesInput, take: Int, skip: Int): [db_UsersGroupByOutputType]! - db_findUniqueusers(where: db_usersWhereUniqueInput!): db_users -} - -input db_usersCreateWithoutMessagesInput { - email: String! - name: String! - updatedat: DateTime - lastlogin: DateTime - pet: String -} - -input db_usersCreateOrConnectWithoutMessagesInput { - where: db_usersWhereUniqueInput! - create: db_usersCreateWithoutMessagesInput! -} - -input db_usersCreateNestedOneWithoutMessagesInput { - create: db_usersCreateWithoutMessagesInput - connectOrCreate: db_usersCreateOrConnectWithoutMessagesInput - connect: db_usersWhereUniqueInput -} - -input db_messagesCreateInput { - message: String! - payload: db_WidgetsInput - users: db_usersCreateNestedOneWithoutMessagesInput! -} - -input db_StringFieldUpdateOperationsInput { - set: String -} - -input db_DateTimeFieldUpdateOperationsInput { - set: DateTime -} - -input db_usersUpdateWithoutMessagesInput { - email: db_StringFieldUpdateOperationsInput - name: db_StringFieldUpdateOperationsInput - updatedat: db_DateTimeFieldUpdateOperationsInput - lastlogin: db_DateTimeFieldUpdateOperationsInput - pet: db_StringFieldUpdateOperationsInput -} - -input db_usersUpsertWithoutMessagesInput { - update: db_usersUpdateWithoutMessagesInput! - create: db_usersCreateWithoutMessagesInput! -} - -input db_usersUpdateOneRequiredWithoutMessagesInput { - create: db_usersCreateWithoutMessagesInput - connectOrCreate: db_usersCreateOrConnectWithoutMessagesInput - upsert: db_usersUpsertWithoutMessagesInput - connect: db_usersWhereUniqueInput - update: db_usersUpdateWithoutMessagesInput -} - -input db_messagesUpdateInput { - message: db_StringFieldUpdateOperationsInput - payload: db_WidgetsInput - users: db_usersUpdateOneRequiredWithoutMessagesInput -} - -input db_messagesCreateManyInput { - id: Int - user_id: Int! - message: String! - payload: db_WidgetsInput -} - -type db_AffectedRowsOutput { - count: Int! - _join: Query! -} - -input db_messagesUpdateManyMutationInput { - message: db_StringFieldUpdateOperationsInput - payload: db_WidgetsInput -} - -input db_messagesCreateWithoutUsersInput { - message: String! - payload: db_WidgetsInput -} - -input db_messagesCreateOrConnectWithoutUsersInput { - where: db_messagesWhereUniqueInput! - create: db_messagesCreateWithoutUsersInput! -} - -input db_messagesCreateManyUsersInput { - id: Int - message: String! - payload: db_WidgetsInput -} - -input db_messagesCreateManyUsersInputEnvelope { - data: [db_messagesCreateManyUsersInput]! - skipDuplicates: Boolean -} - -input db_messagesCreateNestedManyWithoutUsersInput { - create: db_messagesCreateWithoutUsersInput - connectOrCreate: db_messagesCreateOrConnectWithoutUsersInput - createMany: db_messagesCreateManyUsersInputEnvelope - connect: db_messagesWhereUniqueInput -} - -input db_usersCreateInput { - email: String! - name: String! - updatedat: DateTime - lastlogin: DateTime - pet: String - messages: db_messagesCreateNestedManyWithoutUsersInput -} - -input db_messagesUpdateWithoutUsersInput { - message: db_StringFieldUpdateOperationsInput - payload: db_WidgetsInput -} - -input db_messagesUpsertWithWhereUniqueWithoutUsersInput { - where: db_messagesWhereUniqueInput! - update: db_messagesUpdateWithoutUsersInput! - create: db_messagesCreateWithoutUsersInput! -} - -input db_messagesUpdateWithWhereUniqueWithoutUsersInput { - where: db_messagesWhereUniqueInput! - data: db_messagesUpdateWithoutUsersInput! -} - -input db_messagesScalarWhereInput { - AND: db_messagesScalarWhereInput - OR: [db_messagesScalarWhereInput] - NOT: db_messagesScalarWhereInput - id: db_IntFilter - user_id: db_IntFilter - message: db_StringFilter - payload: db_JsonFilter -} - -input db_messagesUpdateManyWithWhereWithoutUsersInput { - where: db_messagesScalarWhereInput! - data: db_messagesUpdateManyMutationInput! -} - -input db_messagesUpdateManyWithoutUsersInput { - create: db_messagesCreateWithoutUsersInput - connectOrCreate: db_messagesCreateOrConnectWithoutUsersInput - upsert: db_messagesUpsertWithWhereUniqueWithoutUsersInput - createMany: db_messagesCreateManyUsersInputEnvelope - connect: db_messagesWhereUniqueInput - set: db_messagesWhereUniqueInput - disconnect: db_messagesWhereUniqueInput - delete: db_messagesWhereUniqueInput - update: db_messagesUpdateWithWhereUniqueWithoutUsersInput - updateMany: db_messagesUpdateManyWithWhereWithoutUsersInput - deleteMany: db_messagesScalarWhereInput -} - -input db_usersUpdateInput { - email: db_StringFieldUpdateOperationsInput - name: db_StringFieldUpdateOperationsInput - updatedat: db_DateTimeFieldUpdateOperationsInput - lastlogin: db_DateTimeFieldUpdateOperationsInput - pet: db_StringFieldUpdateOperationsInput - messages: db_messagesUpdateManyWithoutUsersInput -} - -input db_usersCreateManyInput { - id: Int - email: String! - name: String! - updatedat: DateTime - lastlogin: DateTime - pet: String -} - -input db_usersUpdateManyMutationInput { - email: db_StringFieldUpdateOperationsInput - name: db_StringFieldUpdateOperationsInput - updatedat: db_DateTimeFieldUpdateOperationsInput - lastlogin: db_DateTimeFieldUpdateOperationsInput - pet: db_StringFieldUpdateOperationsInput -} - -type Mutation { - db_createOnemessages(data: db_messagesCreateInput!): db_messages - db_upsertOnemessages(where: db_messagesWhereUniqueInput!, create: db_messagesCreateInput!, update: db_messagesUpdateInput!): db_messages - db_createManymessages(data: [db_messagesCreateManyInput]!, skipDuplicates: Boolean): db_AffectedRowsOutput - db_deleteOnemessages(where: db_messagesWhereUniqueInput!): db_messages - db_updateOnemessages(data: db_messagesUpdateInput!, where: db_messagesWhereUniqueInput!): db_messages - db_updateManymessages(data: db_messagesUpdateManyMutationInput!, where: db_messagesWhereInput): db_AffectedRowsOutput - db_deleteManymessages(where: db_messagesWhereInput): db_AffectedRowsOutput - db_createOneusers(data: db_usersCreateInput!): db_users - db_upsertOneusers(where: db_usersWhereUniqueInput!, create: db_usersCreateInput!, update: db_usersUpdateInput!): db_users - db_createManyusers(data: [db_usersCreateManyInput]!, skipDuplicates: Boolean): db_AffectedRowsOutput - db_deleteOneusers(where: db_usersWhereUniqueInput!): db_users - db_updateOneusers(data: db_usersUpdateInput!, where: db_usersWhereUniqueInput!): db_users - db_updateManyusers(data: db_usersUpdateManyMutationInput!, where: db_usersWhereInput): db_AffectedRowsOutput - db_deleteManyusers(where: db_usersWhereInput): db_AffectedRowsOutput -} - -scalar DateTime - -scalar JSON - -scalar UUID - -type db_Widget { - id: ID! - type: String! - name: String - options: JSON - x: Int! - y: Int! - width: Int! - height: Int! - _join: Query! -} - -type db_Widgets { - items: [db_Widget]! - _join: Query! -} - -input db_WidgetInput { - id: ID! - type: String! - name: String - options: JSON - x: Int! - y: Int! - width: Int! - height: Int! -} - -input db_WidgetsInput { - items: [db_WidgetInput]! -} -` - -const complexRecursiveSchemaResult = ` -{ - "type": [ - "object", - "null" - ], - "properties": { - "AND": { - "$ref": "#/$defs/db_messagesWhereInput" - }, - "NOT": { - "$ref": "#/$defs/db_messagesWhereInput" - }, - "OR": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/$defs/db_messagesWhereInput" - } - }, - "id": { - "$ref": "#/$defs/db_IntFilter" - }, - "message": { - "$ref": "#/$defs/db_StringFilter" - }, - "payload": { - "$ref": "#/$defs/db_JsonFilter" - }, - "user_id": { - "$ref": "#/$defs/db_IntFilter" - }, - "users": { - "$ref": "#/$defs/db_UsersRelationFilter" - } - }, - "additionalProperties": false, - "$defs": { - "db_DateTimeFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "equals": {}, - "gt": {}, - "gte": {}, - "in": { - "type": [ - "array", - "null" - ], - "items": {} - }, - "lt": {}, - "lte": {}, - "not": { - "$ref": "#/$defs/db_NestedDateTimeFilter" - }, - "notIn": { - "type": [ - "array", - "null" - ], - "items": {} - } - }, - "additionalProperties": false - }, - "db_IntFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "equals": { - "type": [ - "integer", - "null" - ] - }, - "gt": { - "type": [ - "integer", - "null" - ] - }, - "gte": { - "type": [ - "integer", - "null" - ] - }, - "in": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "integer", - "null" - ] - } - }, - "lt": { - "type": [ - "integer", - "null" - ] - }, - "lte": { - "type": [ - "integer", - "null" - ] - }, - "not": { - "$ref": "#/$defs/db_NestedIntFilter" - }, - "notIn": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "integer", - "null" - ] - } - } - }, - "additionalProperties": false - }, - "db_JsonFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "equals": { - "type": [ - "string", - "null" - ] - }, - "not": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, - "db_MessagesListRelationFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "every": { - "$ref": "#/$defs/db_messagesWhereInput" - }, - "none": { - "$ref": "#/$defs/db_messagesWhereInput" - }, - "some": { - "$ref": "#/$defs/db_messagesWhereInput" - } - }, - "additionalProperties": false - }, - "db_NestedDateTimeFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "equals": {}, - "gt": {}, - "gte": {}, - "in": { - "type": [ - "array", - "null" - ], - "items": {} - }, - "lt": {}, - "lte": {}, - "not": { - "$ref": "#/$defs/db_NestedDateTimeFilter" - }, - "notIn": { - "type": [ - "array", - "null" - ], - "items": {} - } - }, - "additionalProperties": false - }, - "db_NestedIntFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "equals": { - "type": [ - "integer", - "null" - ] - }, - "gt": { - "type": [ - "integer", - "null" - ] - }, - "gte": { - "type": [ - "integer", - "null" - ] - }, - "in": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "integer", - "null" - ] - } - }, - "lt": { - "type": [ - "integer", - "null" - ] - }, - "lte": { - "type": [ - "integer", - "null" - ] - }, - "not": { - "$ref": "#/$defs/db_NestedIntFilter" - }, - "notIn": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "integer", - "null" - ] - } - } - }, - "additionalProperties": false - }, - "db_NestedStringFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "contains": { - "type": [ - "string", - "null" - ] - }, - "endsWith": { - "type": [ - "string", - "null" - ] - }, - "equals": { - "type": [ - "string", - "null" - ] - }, - "gt": { - "type": [ - "string", - "null" - ] - }, - "gte": { - "type": [ - "string", - "null" - ] - }, - "in": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "string", - "null" - ] - } - }, - "lt": { - "type": [ - "string", - "null" - ] - }, - "lte": { - "type": [ - "string", - "null" - ] - }, - "not": { - "$ref": "#/$defs/db_NestedStringFilter" - }, - "notIn": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "string", - "null" - ] - } - }, - "startsWith": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, - "db_StringFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "contains": { - "type": [ - "string", - "null" - ] - }, - "endsWith": { - "type": [ - "string", - "null" - ] - }, - "equals": { - "type": [ - "string", - "null" - ] - }, - "gt": { - "type": [ - "string", - "null" - ] - }, - "gte": { - "type": [ - "string", - "null" - ] - }, - "in": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "string", - "null" - ] - } - }, - "lt": { - "type": [ - "string", - "null" - ] - }, - "lte": { - "type": [ - "string", - "null" - ] - }, - "mode": { - "type": [ - "string", - "null" - ] - }, - "not": { - "$ref": "#/$defs/db_NestedStringFilter" - }, - "notIn": { - "type": [ - "array", - "null" - ], - "items": { - "type": [ - "string", - "null" - ] - } - }, - "startsWith": { - "type": [ - "string", - "null" - ] - } - }, - "additionalProperties": false - }, - "db_UsersRelationFilter": { - "type": [ - "object", - "null" - ], - "properties": { - "is": { - "$ref": "#/$defs/db_usersWhereInput" - }, - "isNot": { - "$ref": "#/$defs/db_usersWhereInput" - } - }, - "additionalProperties": false - }, - "db_messagesWhereInput": { - "type": [ - "object", - "null" - ], - "properties": { - "AND": { - "$ref": "#/$defs/db_messagesWhereInput" - }, - "NOT": { - "$ref": "#/$defs/db_messagesWhereInput" - }, - "OR": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/$defs/db_messagesWhereInput" - } - }, - "id": { - "$ref": "#/$defs/db_IntFilter" - }, - "message": { - "$ref": "#/$defs/db_StringFilter" - }, - "payload": { - "$ref": "#/$defs/db_JsonFilter" - }, - "user_id": { - "$ref": "#/$defs/db_IntFilter" - }, - "users": { - "$ref": "#/$defs/db_UsersRelationFilter" - } - }, - "additionalProperties": false - }, - "db_usersWhereInput": { - "type": [ - "object", - "null" - ], - "properties": { - "AND": { - "$ref": "#/$defs/db_usersWhereInput" - }, - "NOT": { - "$ref": "#/$defs/db_usersWhereInput" - }, - "OR": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/$defs/db_usersWhereInput" - } - }, - "email": { - "$ref": "#/$defs/db_StringFilter" - }, - "id": { - "$ref": "#/$defs/db_IntFilter" - }, - "lastlogin": { - "$ref": "#/$defs/db_DateTimeFilter" - }, - "messages": { - "$ref": "#/$defs/db_MessagesListRelationFilter" - }, - "name": { - "$ref": "#/$defs/db_StringFilter" - }, - "pet": { - "$ref": "#/$defs/db_StringFilter" - }, - "updatedat": { - "$ref": "#/$defs/db_DateTimeFilter" - } - }, - "additionalProperties": false - } - } -} -` diff --git a/pkg/http/handler.go b/pkg/http/handler.go deleted file mode 100644 index ff2a60766..000000000 --- a/pkg/http/handler.go +++ /dev/null @@ -1,87 +0,0 @@ -package http - -import ( - "encoding/json" - "io" - "net/http" - - "github.com/gobwas/ws" - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/execution" -) - -const ( - httpHeaderUpgrade string = "Upgrade" -) - -func NewGraphqlHTTPHandlerFunc(executionHandler *execution.Handler, logger log.Logger, upgrader *ws.HTTPUpgrader) http.Handler { - return &GraphQLHTTPRequestHandler{ - log: logger, - executionHandler: executionHandler, - wsUpgrader: upgrader, - } -} - -type GraphQLHTTPRequestHandler struct { - log log.Logger - executionHandler *execution.Handler - wsUpgrader *ws.HTTPUpgrader -} - -func (g *GraphQLHTTPRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - isUpgrade := g.isWebsocketUpgrade(r) - if isUpgrade { - err := g.upgradeWithNewGoroutine(w, r) - if err != nil { - g.log.Error("GraphQLHTTPRequestHandler.ServeHTTP", - log.Error(err), - ) - w.WriteHeader(http.StatusBadRequest) - } - return - } - g.handleHTTP(w, r) -} - -func (g *GraphQLHTTPRequestHandler) upgradeWithNewGoroutine(w http.ResponseWriter, r *http.Request) error { - conn, _, _, err := g.wsUpgrader.Upgrade(r, w) - if err != nil { - return err - } - g.handleWebsocket(conn) - return nil -} - -func (g *GraphQLHTTPRequestHandler) isWebsocketUpgrade(r *http.Request) bool { - for _, header := range r.Header[httpHeaderUpgrade] { - if header == "websocket" { - return true - } - } - return false -} - -func (g *GraphQLHTTPRequestHandler) extraVariables(r *http.Request, out io.Writer) error { - headers := map[string]string{} - for key := range r.Header { - headers[key] = r.Header.Get(key) - } - - cookies := map[string]string{} - for _, cookie := range r.Cookies() { - cookies[cookie.Name] = cookie.Value - } - - extra := map[string]interface{}{ - "request": map[string]interface{}{ - "uri": r.RequestURI, - "method": r.Method, - "host": r.Host, - "headers": headers, - "cookies": cookies, - }, - } - - return json.NewEncoder(out).Encode(extra) -} diff --git a/pkg/http/handler_test.go b/pkg/http/handler_test.go deleted file mode 100644 index 631e543bb..000000000 --- a/pkg/http/handler_test.go +++ /dev/null @@ -1,230 +0,0 @@ -package http - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "net" - "net/http" - "net/http/httptest" - "testing" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/starwars" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -func TestGraphQLHTTPRequestHandler_ServeHTTP(t *testing.T) { - starwars.SetRelativePathToStarWarsPackage("../starwars") - - handler := NewGraphqlHTTPHandlerFunc(starwars.NewExecutionHandler(t), abstractlogger.NoopLogger, &ws.DefaultHTTPUpgrader) - server := httptest.NewServer(handler) - defer server.Close() - - addr := server.Listener.Addr().String() - httpAddr := fmt.Sprintf("http://%s", addr) - wsAddr := fmt.Sprintf("ws://%s", addr) - - t.Run("http", func(t *testing.T) { - t.Run("should return 400 Bad Request when query does not fit to schema", func(t *testing.T) { - requestBodyBytes := starwars.InvalidQueryRequestBody(t) - req, err := http.NewRequest(http.MethodPost, httpAddr, bytes.NewBuffer(requestBodyBytes)) - require.NoError(t, err) - - client := http.Client{} - resp, err := client.Do(req) - require.NoError(t, err) - - assert.Equal(t, http.StatusBadRequest, resp.StatusCode) - }) - - t.Run("should successfully handle query and return 200 OK", func(t *testing.T) { - starWarsCases := []starwars.TestCase{ - { - Name: "simple hero query", - RequestBody: starwars.LoadQuery(t, starwars.FileSimpleHeroQuery, nil), - }, - { - Name: "droid query with argument and variable", - RequestBody: starwars.LoadQuery(t, starwars.FileDroidWithArgAndVarQuery, starwars.QueryVariables{"droidID": "2000"}), - }, - { - Name: "hero with aliases query", - RequestBody: starwars.LoadQuery(t, starwars.FileHeroWithAliasesQuery, nil), - }, - { - Name: "fragments query", - RequestBody: starwars.LoadQuery(t, starwars.FileFragmentsQuery, starwars.QueryVariables{"droidID": "2000"}), - }, - { - Name: "hero with operation name query", - RequestBody: starwars.LoadQuery(t, starwars.FileHeroWithOperationNameQuery, nil), - }, - { - Name: "directives include query", - RequestBody: starwars.LoadQuery(t, starwars.FileDirectivesIncludeQuery, starwars.QueryVariables{"withFriends": true}), - }, - { - Name: "directives skip query", - RequestBody: starwars.LoadQuery(t, starwars.FileDirectivesSkipQuery, starwars.QueryVariables{"skipFriends": true}), - }, - { - Name: "create review mutation", - RequestBody: starwars.LoadQuery(t, starwars.FileCreateReviewMutation, starwars.QueryVariables{"ep": "JEDI", "review": starwars.ReviewInput()}), - }, - { - Name: "inline fragments query", - RequestBody: starwars.LoadQuery(t, starwars.FileInlineFragmentsQuery, nil), - }, - { - Name: "union query", - RequestBody: starwars.LoadQuery(t, starwars.FileUnionQuery, starwars.QueryVariables{"name": "Han Solo"}), - }, - } - - for _, testCase := range starWarsCases { - testCase := testCase - - t.Run(testCase.Name, func(t *testing.T) { - requestBodyBytes := testCase.RequestBody - req, err := http.NewRequest(http.MethodPost, httpAddr, bytes.NewBuffer(requestBodyBytes)) - require.NoError(t, err) - - client := http.Client{} - resp, err := client.Do(req) - require.NoError(t, err) - - responseBodyBytes, err := io.ReadAll(resp.Body) - require.NoError(t, err) - - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Contains(t, resp.Header.Get(httpHeaderContentType), httpContentTypeApplicationJson) - assert.Equal(t, `{"data":null}`, string(responseBodyBytes)) - }) - } - - }) - }) - - t.Run("websockets", func(t *testing.T) { - var clientConn net.Conn - defer func() { - err := clientConn.Close() - require.NoError(t, err) - }() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - t.Run("should upgrade to websocket and establish connection successfully", func(t *testing.T) { - var err error - clientConn, _, _, err = ws.Dial(ctx, wsAddr) - assert.NoError(t, err) - - initialClientMessage := subscription.Message{ - Id: "", - Type: subscription.MessageTypeConnectionInit, - Payload: nil, - } - sendMessageToServer(t, clientConn, initialClientMessage) - - serverMessage := readMessageFromServer(t, clientConn) - assert.Equal(t, `{"id":"","type":"connection_ack","payload":null}`, string(serverMessage)) - }) - - t.Run("should successfully start a subscription", func(t *testing.T) { - startSubscriptionMessage := subscription.Message{ - Id: "1", - Type: subscription.MessageTypeStart, - Payload: starwars.LoadQuery(t, starwars.FileRemainingJedisSubscription, nil), - } - sendMessageToServer(t, clientConn, startSubscriptionMessage) - - serverMessage := readMessageFromServer(t, clientConn) - assert.Equal(t, `{"id":"1","type":"data","payload":{"data":null}}`, string(serverMessage)) - }) - - cancelFunc() - }) - -} - -func TestGraphQLHTTPRequestHandler_IsWebsocketUpgrade(t *testing.T) { - handler := NewGraphqlHTTPHandlerFunc(nil, nil, nil).(*GraphQLHTTPRequestHandler) - - t.Run("should return false if upgrade header does not exist", func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, "/", nil) - require.NoError(t, err) - - isWebsocketUpgrade := handler.isWebsocketUpgrade(req) - assert.False(t, isWebsocketUpgrade) - }) - - t.Run("should return false if upgrade header does not contain websocket", func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, "/", nil) - require.NoError(t, err) - - req.Header = map[string][]string{ - httpHeaderUpgrade: {"any"}, - } - - isWebsocketUpgrade := handler.isWebsocketUpgrade(req) - assert.False(t, isWebsocketUpgrade) - }) - - t.Run("should return true if upgrade header contains websocket", func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, "/", nil) - require.NoError(t, err) - - req.Header = map[string][]string{ - httpHeaderUpgrade: {"any", "websocket"}, - } - - isWebsocketUpgrade := handler.isWebsocketUpgrade(req) - assert.True(t, isWebsocketUpgrade) - }) -} - -func TestGraphQLHTTPRequestHandler_ExtraVariables(t *testing.T) { - handler := NewGraphqlHTTPHandlerFunc(nil, nil, nil).(*GraphQLHTTPRequestHandler) - - t.Run("should create extra variables successfully", func(t *testing.T) { - req, err := http.NewRequest(http.MethodGet, "http://localhost:8080/path", nil) - require.NoError(t, err) - - req.Header = map[string][]string{ - httpHeaderUpgrade: {"websocket"}, - } - - req.AddCookie(&http.Cookie{}) - - extraVariablesBytes := &bytes.Buffer{} - err = handler.extraVariables(req, extraVariablesBytes) - - assert.NoError(t, err) - - expectedJson := fmt.Sprintf("%s\n", `{"request":{"cookies":{},"headers":{"Cookie":"=","Upgrade":"websocket"},"host":"localhost:8080","method":"GET","uri":""}}`) - assert.Equal(t, expectedJson, extraVariablesBytes.String()) - }) -} - -func sendMessageToServer(t *testing.T, clientConn net.Conn, message subscription.Message) { - messageBytes, err := json.Marshal(message) - require.NoError(t, err) - - err = wsutil.WriteClientText(clientConn, messageBytes) - require.NoError(t, err) -} - -func readMessageFromServer(t *testing.T, clientConn net.Conn) []byte { - msgBytes, _, err := wsutil.ReadServerData(clientConn) - require.NoError(t, err) - - return msgBytes -} diff --git a/pkg/http/http.go b/pkg/http/http.go deleted file mode 100644 index a4ce9a3bb..000000000 --- a/pkg/http/http.go +++ /dev/null @@ -1,65 +0,0 @@ -// Package http handles GraphQL HTTP Requests including WebSocket Upgrades. -package http - -import ( - "bytes" - "io" - "net/http" - - log "github.com/jensneuse/abstractlogger" - "github.com/wundergraph/graphql-go-tools/pkg/pool" -) - -const ( - httpHeaderContentType string = "Content-Type" - - httpContentTypeApplicationJson string = "application/json" -) - -func (g *GraphQLHTTPRequestHandler) handleHTTP(w http.ResponseWriter, r *http.Request) { - data, err := io.ReadAll(r.Body) - if err != nil { - g.log.Error("GraphQLHTTPRequestHandler.handleHTTP", - log.Error(err), - ) - w.WriteHeader(http.StatusBadRequest) - return - } - - extra := &bytes.Buffer{} - err = g.extraVariables(r, extra) - if err != nil { - g.log.Error("executionHandler.Handle.json.Marshal(extra)", - log.Error(err), - ) - w.WriteHeader(http.StatusBadRequest) - return - } - - executor, rootNode, ctx, err := g.executionHandler.Handle(data, extra.Bytes()) - if err != nil { - g.log.Error("executionHandler.Handle", - log.Error(err), - ) - w.WriteHeader(http.StatusBadRequest) - return - } - - ctx.Context = r.Context() - - buf := pool.BytesBuffer.Get() - defer pool.BytesBuffer.Put(buf) - - err = executor.Execute(ctx, rootNode, buf) - if err != nil { - g.log.Error("executor.Execute", - log.Error(err), - ) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Add(httpHeaderContentType, "application/json") - w.WriteHeader(http.StatusOK) - _, _ = buf.WriteTo(w) -} diff --git a/pkg/http/ws.go b/pkg/http/ws.go deleted file mode 100644 index 431b3f9dc..000000000 --- a/pkg/http/ws.go +++ /dev/null @@ -1,185 +0,0 @@ -package http - -import ( - "context" - "encoding/json" - "net" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -// WebsocketSubscriptionClient is an actual implementation of the subscription client interface. -// -// Deprecated: This WebsocketSubscriptionClient is deprecated. -// Use github.com/wundergraph/graphql-go-tools/pkg/subscription/websocket instead. -type WebsocketSubscriptionClient struct { - logger abstractlogger.Logger - // clientConn holds the actual connection to the client. - clientConn net.Conn - // isClosedConnection indicates if the websocket connection is closed. - isClosedConnection bool -} - -// NewWebsocketSubscriptionClient will create a new websocket subscription client. -// -// Deprecated: This NewWebsocketSubscriptionClient is deprecated. -// Use github.com/wundergraph/graphql-go-tools/pkg/subscription/websocket instead. -func NewWebsocketSubscriptionClient(logger abstractlogger.Logger, clientConn net.Conn) *WebsocketSubscriptionClient { - return &WebsocketSubscriptionClient{ - logger: logger, - clientConn: clientConn, - } -} - -// ReadFromClient will read a subscription message from the websocket client. -func (w *WebsocketSubscriptionClient) ReadFromClient() (message *subscription.Message, err error) { - var data []byte - var opCode ws.OpCode - - data, opCode, err = wsutil.ReadClientData(w.clientConn) - if err != nil { - if w.isClosedConnectionError(err) { - return message, nil - } - - w.logger.Error("http.WebsocketSubscriptionClient.ReadFromClient()", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - abstractlogger.Any("opCode", opCode), - ) - - w.isClosedConnectionError(err) - - return nil, err - } - - err = json.Unmarshal(data, &message) - if err != nil { - w.logger.Error("http.WebsocketSubscriptionClient.ReadFromClient()", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - abstractlogger.Any("opCode", opCode), - ) - - return nil, err - } - - return message, nil -} - -// WriteToClient will write a subscription message to the websocket client. -func (w *WebsocketSubscriptionClient) WriteToClient(message subscription.Message) error { - if w.isClosedConnection { - return nil - } - - messageBytes, err := json.Marshal(message) - if err != nil { - w.logger.Error("http.WebsocketSubscriptionClient.WriteToClient()", - abstractlogger.Error(err), - abstractlogger.Any("message", message), - ) - - return err - } - - err = wsutil.WriteServerMessage(w.clientConn, ws.OpText, messageBytes) - if err != nil { - w.logger.Error("http.WebsocketSubscriptionClient.WriteToClient()", - abstractlogger.Error(err), - abstractlogger.ByteString("messageBytes", messageBytes), - ) - - return err - } - - return nil -} - -// IsConnected will indicate if the websocket connection is still established. -func (w *WebsocketSubscriptionClient) IsConnected() bool { - return !w.isClosedConnection -} - -// Disconnect will close the websocket connection. -func (w *WebsocketSubscriptionClient) Disconnect() error { - w.logger.Debug("http.GraphQLHTTPRequestHandler.Disconnect()", - abstractlogger.String("message", "disconnecting client"), - ) - w.isClosedConnection = true - return w.clientConn.Close() -} - -// isClosedConnectionError will indicate if the given error is a connection closed error. -func (w *WebsocketSubscriptionClient) isClosedConnectionError(err error) bool { - if _, ok := err.(wsutil.ClosedError); ok { - w.isClosedConnection = true - } - - return w.isClosedConnection -} - -// HandleWebsocketWithInitFunc will handle a websocket connection with the ability to provide an InitFunc. -// -// Deprecated: This HandleWebsocketWithInitFunc is deprecated. -// Use github.com/wundergraph/graphql-go-tools/pkg/subscription/websocket instead. -func HandleWebsocketWithInitFunc( - done chan bool, - errChan chan error, - conn net.Conn, - executorPool subscription.ExecutorPool, - logger abstractlogger.Logger, - initFunc subscription.WebsocketInitFunc, -) { - defer func() { - if err := conn.Close(); err != nil { - logger.Error("http.HandleWebsocket()", - abstractlogger.String("message", "could not close connection to client"), - abstractlogger.Error(err), - ) - } - }() - - websocketClient := NewWebsocketSubscriptionClient(logger, conn) - subscriptionHandler, err := subscription.NewHandlerWithInitFunc(logger, websocketClient, executorPool, initFunc) - if err != nil { - logger.Error("http.HandleWebsocket()", - abstractlogger.String("message", "could not create subscriptionHandler"), - abstractlogger.Error(err), - ) - - errChan <- err - return - } - - close(done) - subscriptionHandler.Handle(context.Background()) // Blocking -} - -// HandleWebsocket will handle a websocket connection. -// -// Deprecated: This HandleWebsocket is deprecated. -// Use github.com/wundergraph/graphql-go-tools/pkg/subscription/websocket instead. -func HandleWebsocket(done chan bool, errChan chan error, conn net.Conn, executorPool subscription.ExecutorPool, logger abstractlogger.Logger) { - HandleWebsocketWithInitFunc(done, errChan, conn, executorPool, logger, nil) -} - -// handleWebsocket will handle the websocket connection. -func (g *GraphQLHTTPRequestHandler) handleWebsocket(conn net.Conn) { - done := make(chan bool) - errChan := make(chan error) - - executorPool := subscription.NewExecutorV1Pool(g.executionHandler) - go HandleWebsocket(done, errChan, conn, executorPool, g.log) - select { - case err := <-errChan: - g.log.Error("http.GraphQLHTTPRequestHandler.handleWebsocket()", - abstractlogger.Error(err), - ) - case <-done: - } -} diff --git a/pkg/http/ws_connection_init.json b/pkg/http/ws_connection_init.json deleted file mode 100644 index b2ddf343c..000000000 --- a/pkg/http/ws_connection_init.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "type": "connection_init", - "payload": {} -} \ No newline at end of file diff --git a/pkg/http/ws_start.json b/pkg/http/ws_start.json deleted file mode 100644 index de8fc2456..000000000 --- a/pkg/http/ws_start.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "1", - "type": "start", - "payload": { - "variables": {}, - "extensions": {}, - "operationName": "stream", - "query": "subscription stream {n stream {n datetimen timezonen abbreviationn }n}n" - } -} \ No newline at end of file diff --git a/pkg/http/ws_test.go b/pkg/http/ws_test.go deleted file mode 100644 index 09292a838..000000000 --- a/pkg/http/ws_test.go +++ /dev/null @@ -1,131 +0,0 @@ -package http - -import ( - "encoding/json" - "errors" - "net" - "testing" - "time" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -func TestWebsocketSubscriptionClient_WriteToClient(t *testing.T) { - connToServer, connToClient := net.Pipe() - - websocketClient := NewWebsocketSubscriptionClient(abstractlogger.NoopLogger, connToClient) - - t.Run("should write successfully to client", func(t *testing.T) { - messageToClient := subscription.Message{ - Id: "1", - Type: subscription.MessageTypeData, - Payload: []byte(`{"data":null}`), - } - - go func() { - err := websocketClient.WriteToClient(messageToClient) - assert.NoError(t, err) - }() - - data, opCode, err := wsutil.ReadServerData(connToServer) - require.NoError(t, err) - require.Equal(t, ws.OpText, opCode) - - time.Sleep(10 * time.Millisecond) - - var messageFromServer subscription.Message - err = json.Unmarshal(data, &messageFromServer) - require.NoError(t, err) - - assert.Equal(t, messageToClient, messageFromServer) - }) - - t.Run("should not write to client when connection is closed", func(t *testing.T) { - err := connToServer.Close() - require.NoError(t, err) - - websocketClient.isClosedConnection = true - - err = websocketClient.WriteToClient(subscription.Message{}) - assert.NoError(t, err) - }) -} - -func TestWebsocketSubscriptionClient_ReadFromClient(t *testing.T) { - t.Run("should successfully read from client", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewWebsocketSubscriptionClient(abstractlogger.NoopLogger, connToClient) - - messageToServer := &subscription.Message{ - Id: "1", - Type: subscription.MessageTypeData, - Payload: []byte(`{"data":null}`), - } - - go func() { - data, err := json.Marshal(messageToServer) - require.NoError(t, err) - - err = wsutil.WriteClientText(connToServer, data) - require.NoError(t, err) - }() - - time.Sleep(10 * time.Millisecond) - - messageFromClient, err := websocketClient.ReadFromClient() - assert.NoError(t, err) - assert.Equal(t, messageToServer, messageFromClient) - }) -} - -func TestWebsocketSubscriptionClient_IsConnected(t *testing.T) { - _, connToClient := net.Pipe() - websocketClient := NewWebsocketSubscriptionClient(abstractlogger.NoopLogger, connToClient) - - t.Run("should return true when a connection is established", func(t *testing.T) { - isConnected := websocketClient.IsConnected() - assert.True(t, isConnected) - }) - - t.Run("should return false when a connection is closed", func(t *testing.T) { - err := connToClient.Close() - require.NoError(t, err) - - websocketClient.isClosedConnection = true - - isConnected := websocketClient.IsConnected() - assert.False(t, isConnected) - }) -} - -func TestWebsocketSubscriptionClient_Disconnect(t *testing.T) { - _, connToClient := net.Pipe() - websocketClient := NewWebsocketSubscriptionClient(abstractlogger.NoopLogger, connToClient) - - t.Run("should disconnect and indicate a closed connection", func(t *testing.T) { - err := websocketClient.Disconnect() - assert.NoError(t, err) - assert.Equal(t, true, websocketClient.isClosedConnection) - }) -} - -func TestWebsocketSubscriptionClient_isClosedConnectionError(t *testing.T) { - _, connToClient := net.Pipe() - websocketClient := NewWebsocketSubscriptionClient(abstractlogger.NoopLogger, connToClient) - - t.Run("should not close connection when it is not a closed connection error", func(t *testing.T) { - isClosedConnectionError := websocketClient.isClosedConnectionError(errors.New("no closed connection err")) - assert.False(t, isClosedConnectionError) - }) - - t.Run("should close connection when it is a closed connection error", func(t *testing.T) { - isClosedConnectionError := websocketClient.isClosedConnectionError(wsutil.ClosedError{}) - assert.True(t, isClosedConnectionError) - }) -} diff --git a/pkg/imports/fixtures/render_result.golden b/pkg/imports/fixtures/render_result.golden deleted file mode 100644 index 25826a444..000000000 --- a/pkg/imports/fixtures/render_result.golden +++ /dev/null @@ -1,41 +0,0 @@ -#file: testdata/schema.graphql - - -schema { - query: Query - mutation: Mutation -} - - -#file: testdata/scalars/json.graphql - -scalar JSON - - -#file: testdata/types/query.graphql - -type Query { - foo: Foo -} - - -#file: testdata/nested/nested.graphql - - -type Bar { - baz: Int -} - - -#file: testdata/nested2/nested2.graphql - -type Bat { - bar: String -} - - -#file: testdata/deep/deeper/custom_types.graphql - -type Foo { - field: String -} diff --git a/pkg/imports/fixtures/render_result_windows.golden b/pkg/imports/fixtures/render_result_windows.golden deleted file mode 100644 index a5a9fb8c0..000000000 --- a/pkg/imports/fixtures/render_result_windows.golden +++ /dev/null @@ -1,41 +0,0 @@ -#file: testdata\schema.graphql - - -schema { - query: Query - mutation: Mutation -} - - -#file: testdata\scalars\json.graphql - -scalar JSON - - -#file: testdata\types\query.graphql - -type Query { - foo: Foo -} - - -#file: testdata\nested\nested.graphql - - -type Bar { - baz: Int -} - - -#file: testdata\nested2\nested2.graphql - -type Bat { - bar: String -} - - -#file: testdata\deep\deeper\custom_types.graphql - -type Foo { - field: String -} diff --git a/pkg/imports/fixtures/scanner_regex.golden b/pkg/imports/fixtures/scanner_regex.golden deleted file mode 100644 index 1575eb7ac..000000000 --- a/pkg/imports/fixtures/scanner_regex.golden +++ /dev/null @@ -1,17 +0,0 @@ -{ - "RelativePath": "", - "Imports": [ - { - "RelativePath": "testdata/regexonly/flat.graphql", - "Imports": null - }, - { - "RelativePath": "testdata/regexonly/mutation.graphql", - "Imports": null - }, - { - "RelativePath": "testdata/regexonly/query.graphql", - "Imports": null - } - ] -} \ No newline at end of file diff --git a/pkg/imports/fixtures/scanner_regex_render.golden b/pkg/imports/fixtures/scanner_regex_render.golden deleted file mode 100644 index 8c620b886..000000000 --- a/pkg/imports/fixtures/scanner_regex_render.golden +++ /dev/null @@ -1,10 +0,0 @@ -schema { - query: Query - mutation: Mutation -} -type Mutation { - bar: String -} -type Query { - foo: String -} diff --git a/pkg/imports/fixtures/scanner_regex_windows.golden b/pkg/imports/fixtures/scanner_regex_windows.golden deleted file mode 100644 index ab35588e9..000000000 --- a/pkg/imports/fixtures/scanner_regex_windows.golden +++ /dev/null @@ -1,17 +0,0 @@ -{ - "RelativePath": "", - "Imports": [ - { - "RelativePath": "testdata\\regexonly\\flat.graphql", - "Imports": null - }, - { - "RelativePath": "testdata\\regexonly\\mutation.graphql", - "Imports": null - }, - { - "RelativePath": "testdata\\regexonly\\query.graphql", - "Imports": null - } - ] -} \ No newline at end of file diff --git a/pkg/imports/fixtures/scanner_result.golden b/pkg/imports/fixtures/scanner_result.golden deleted file mode 100644 index a71140cc7..000000000 --- a/pkg/imports/fixtures/scanner_result.golden +++ /dev/null @@ -1,26 +0,0 @@ -{ - "RelativePath": "testdata/schema.graphql", - "Imports": [ - { - "RelativePath": "testdata/scalars/json.graphql", - "Imports": null - }, - { - "RelativePath": "testdata/types/query.graphql", - "Imports": null - }, - { - "RelativePath": "testdata/nested/nested.graphql", - "Imports": [ - { - "RelativePath": "testdata/nested2/nested2.graphql", - "Imports": null - } - ] - }, - { - "RelativePath": "testdata/deep/deeper/custom_types.graphql", - "Imports": null - } - ] -} \ No newline at end of file diff --git a/pkg/imports/fixtures/scanner_result_windows.golden b/pkg/imports/fixtures/scanner_result_windows.golden deleted file mode 100644 index cf0e264fd..000000000 --- a/pkg/imports/fixtures/scanner_result_windows.golden +++ /dev/null @@ -1,26 +0,0 @@ -{ - "RelativePath": "testdata\\schema.graphql", - "Imports": [ - { - "RelativePath": "testdata\\scalars\\json.graphql", - "Imports": null - }, - { - "RelativePath": "testdata\\types\\query.graphql", - "Imports": null - }, - { - "RelativePath": "testdata\\nested\\nested.graphql", - "Imports": [ - { - "RelativePath": "testdata\\nested2\\nested2.graphql", - "Imports": null - } - ] - }, - { - "RelativePath": "testdata\\deep\\deeper\\custom_types.graphql", - "Imports": null - } - ] -} \ No newline at end of file diff --git a/pkg/imports/graphql_file.go b/pkg/imports/graphql_file.go deleted file mode 100644 index c30710892..000000000 --- a/pkg/imports/graphql_file.go +++ /dev/null @@ -1,92 +0,0 @@ -package imports - -import ( - "bufio" - "io" - "os" - - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type GraphQLFile struct { - RelativePath string - Imports []GraphQLFile -} - -func (g GraphQLFile) Render(printFilePath bool, out io.Writer) error { - return g.render(printFilePath, out) -} - -func (g GraphQLFile) render(printFilePath bool, out io.Writer) error { - - var err error - if g.RelativePath != "" { - err = g.renderSelf(printFilePath, out) - if err != nil { - return err - } - } - - for _, importFile := range g.Imports { - if printFilePath { - _, err = out.Write(literal.LINETERMINATOR) - if err != nil { - return err - } - _, err = out.Write(literal.LINETERMINATOR) - if err != nil { - return err - } - } - err = importFile.render(printFilePath, out) - if err != nil { - return err - } - } - - return nil -} - -func (g GraphQLFile) renderSelf(printFilePath bool, out io.Writer) error { - file, err := os.Open(g.RelativePath) - if err != nil { - return err - } - defer file.Close() - - if printFilePath { - err = g.renderFilePath(out) - if err != nil { - return err - } - } - - reader := bufio.NewReader(file) - for { - line, _, err := reader.ReadLine() - if err != nil { - break - } - - if importStatementRegex.Match(line) { - continue - } - - _, err = out.Write(line) - if err != nil { - return err - } - - _, err = out.Write(literal.LINETERMINATOR) - if err != nil { - return err - } - } - - return nil -} - -func (g GraphQLFile) renderFilePath(out io.Writer) error { - _, err := out.Write([]byte("#file: " + g.RelativePath + "\n\n")) - return err -} diff --git a/pkg/imports/graphql_file_test.go b/pkg/imports/graphql_file_test.go deleted file mode 100644 index bf3cf5fa6..000000000 --- a/pkg/imports/graphql_file_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package imports - -import ( - "bytes" - "os" - "testing" - - "github.com/jensneuse/diffview" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestGraphQLFile_Render(t *testing.T) { - scanner := Scanner{} - file, err := scanner.ScanFile("testdata/schema.graphql") - if err != nil { - t.Fatal(err) - } - - out := bytes.Buffer{} - err = file.Render(true, &out) - if err != nil { - t.Fatal(err) - } - - dump := out.Bytes() - - goldie.Assert(t, "render_result", dump, true) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/render_result.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("render_result", fixture, dump) - } -} diff --git a/pkg/imports/imports.go b/pkg/imports/imports.go deleted file mode 100644 index 4f513c351..000000000 --- a/pkg/imports/imports.go +++ /dev/null @@ -1,109 +0,0 @@ -// Package imports helps combining multiple GraphQL documents into one document using import comments. -package imports - -import ( - "fmt" - "os" - "path/filepath" - "regexp" - "strings" -) - -var ( - importStatementRegex, _ = regexp.Compile(`(#import "[^";]+")`) - pathStatementRegex, _ = regexp.Compile(`"(.*?)"`) -) - -type Scanner struct { - knownFiles map[string]struct{} -} - -func (s *Scanner) ScanFile(inputFilePath string) (*GraphQLFile, error) { - s.knownFiles = map[string]struct{}{} - return s.scanFile(inputFilePath) -} - -func (s *Scanner) ScanRegex(filesRegex string) (*GraphQLFile, error) { - s.knownFiles = map[string]struct{}{} - file := &GraphQLFile{} - var err error - file.Imports, err = s.fileImportsForPattern(filesRegex) - return file, err -} - -func (s *Scanner) scanFile(inputFilePath string) (*GraphQLFile, error) { - - basePath, err := os.Getwd() - if err != nil { - return nil, err - } - - absoluteFilePath, err := filepath.Abs(inputFilePath) - if err != nil { - return nil, err - } - - relativeFilePath, err := filepath.Rel(basePath, absoluteFilePath) - if err != nil { - return nil, err - } - - if _, exists := s.knownFiles[relativeFilePath]; exists { - return nil, fmt.Errorf("file forms import cycle: %s", relativeFilePath) - } - - s.knownFiles[relativeFilePath] = struct{}{} - - fileDir := filepath.Dir(relativeFilePath) - - content, err := os.ReadFile(inputFilePath) - if err != nil { - return nil, err - } - - file := &GraphQLFile{ - RelativePath: relativeFilePath, - } - - importStatements := importStatementRegex.FindAll(content, -1) - for i := 0; i < len(importStatements); i++ { - importFilePath := s.importFilePath(string(importStatements[i])) - filePathPattern := filepath.Join(fileDir, importFilePath) - if importFilePath != "" { - imports, err := s.fileImportsForPattern(filePathPattern) - if err != nil { - return nil, err - } - file.Imports = append(file.Imports, imports...) - } - } - - return file, nil -} - -func (s *Scanner) importFilePath(importStatement string) string { - out := pathStatementRegex.FindString(importStatement) - out = strings.TrimLeft(out, "\"") - out = strings.TrimRight(out, "\"") - return out -} - -func (s *Scanner) fileImportsForPattern(pattern string) ([]GraphQLFile, error) { - matches, err := filepath.Glob(pattern) - if err != nil { - return nil, err - } - - out := make([]GraphQLFile, 0, len(matches)) - for _, match := range matches { - importFile, err := s.scanFile(match) - if err != nil { - return nil, err - } - if importFile == nil { - continue - } - out = append(out, *importFile) - } - return out, nil -} diff --git a/pkg/imports/imports_test.go b/pkg/imports/imports_test.go deleted file mode 100644 index 6f380eb48..000000000 --- a/pkg/imports/imports_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package imports - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/jensneuse/diffview" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestScanner(t *testing.T) { - scanner := Scanner{} - file, err := scanner.ScanFile("./testdata/schema.graphql") - if err != nil { - t.Fatal(err) - } - - dump, err := json.MarshalIndent(file, "", " ") - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "scanner_result", dump, true) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/scanner_result.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("scanner_result", fixture, dump) - } -} - -func TestScanner_ScanRegex(t *testing.T) { - scanner := Scanner{} - file, err := scanner.ScanRegex("./testdata/regexonly/*.graphql") - if err != nil { - t.Fatal(err) - } - - dump, err := json.MarshalIndent(file, "", " ") - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "scanner_regex", dump, true) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/scanner_regex.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("scanner_regex", fixture, dump) - } - - buf := bytes.Buffer{} - err = file.render(false, &buf) - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "scanner_regex_render", buf.Bytes()) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/scanner_regex_render.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("scanner_regex_render", fixture, buf.Bytes()) - } -} - -func TestScannerImportCycle(t *testing.T) { - scanner := Scanner{} - file, err := scanner.ScanFile("./testdata/import_cycle.graphql") - _ = file - require.Error(t, err) - - cycleFilePath := filepath.Join("testdata", "/cycle/a/a.graphql") - assert.Equal(t, fmt.Sprintf("file forms import cycle: %s", cycleFilePath), err.Error()) -} diff --git a/pkg/imports/testdata/cycle/a/a.graphql b/pkg/imports/testdata/cycle/a/a.graphql deleted file mode 100644 index c6b098c83..000000000 --- a/pkg/imports/testdata/cycle/a/a.graphql +++ /dev/null @@ -1 +0,0 @@ -#import "../b/b.graphql" \ No newline at end of file diff --git a/pkg/imports/testdata/cycle/b/b.graphql b/pkg/imports/testdata/cycle/b/b.graphql deleted file mode 100644 index 6d587f01e..000000000 --- a/pkg/imports/testdata/cycle/b/b.graphql +++ /dev/null @@ -1 +0,0 @@ -#import "../a/a.graphql" \ No newline at end of file diff --git a/pkg/imports/testdata/deep/deeper/custom_types.graphql b/pkg/imports/testdata/deep/deeper/custom_types.graphql deleted file mode 100644 index d8738959e..000000000 --- a/pkg/imports/testdata/deep/deeper/custom_types.graphql +++ /dev/null @@ -1,3 +0,0 @@ -type Foo { - field: String -} \ No newline at end of file diff --git a/pkg/imports/testdata/deep/deeper/non_graphql.txt b/pkg/imports/testdata/deep/deeper/non_graphql.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/pkg/imports/testdata/import_cycle.graphql b/pkg/imports/testdata/import_cycle.graphql deleted file mode 100644 index 4b5406cce..000000000 --- a/pkg/imports/testdata/import_cycle.graphql +++ /dev/null @@ -1 +0,0 @@ -#import "cycle/a/a.graphql" \ No newline at end of file diff --git a/pkg/imports/testdata/nested/nested.graphql b/pkg/imports/testdata/nested/nested.graphql deleted file mode 100644 index 603402f1f..000000000 --- a/pkg/imports/testdata/nested/nested.graphql +++ /dev/null @@ -1,5 +0,0 @@ -#import "../nested2/nested2.graphql" - -type Bar { - baz: Int -} \ No newline at end of file diff --git a/pkg/imports/testdata/nested2/nested2.graphql b/pkg/imports/testdata/nested2/nested2.graphql deleted file mode 100644 index e65eac679..000000000 --- a/pkg/imports/testdata/nested2/nested2.graphql +++ /dev/null @@ -1,3 +0,0 @@ -type Bat { - bar: String -} \ No newline at end of file diff --git a/pkg/imports/testdata/regexonly/flat.graphql b/pkg/imports/testdata/regexonly/flat.graphql deleted file mode 100644 index 3ab0c31d2..000000000 --- a/pkg/imports/testdata/regexonly/flat.graphql +++ /dev/null @@ -1,4 +0,0 @@ -schema { - query: Query - mutation: Mutation -} \ No newline at end of file diff --git a/pkg/imports/testdata/regexonly/mutation.graphql b/pkg/imports/testdata/regexonly/mutation.graphql deleted file mode 100644 index 974991ce5..000000000 --- a/pkg/imports/testdata/regexonly/mutation.graphql +++ /dev/null @@ -1,3 +0,0 @@ -type Mutation { - bar: String -} \ No newline at end of file diff --git a/pkg/imports/testdata/regexonly/query.graphql b/pkg/imports/testdata/regexonly/query.graphql deleted file mode 100644 index 948838ad5..000000000 --- a/pkg/imports/testdata/regexonly/query.graphql +++ /dev/null @@ -1,3 +0,0 @@ -type Query { - foo: String -} \ No newline at end of file diff --git a/pkg/imports/testdata/scalars/json.graphql b/pkg/imports/testdata/scalars/json.graphql deleted file mode 100644 index e706f01c0..000000000 --- a/pkg/imports/testdata/scalars/json.graphql +++ /dev/null @@ -1 +0,0 @@ -scalar JSON \ No newline at end of file diff --git a/pkg/imports/testdata/schema.graphql b/pkg/imports/testdata/schema.graphql deleted file mode 100644 index ee7d63155..000000000 --- a/pkg/imports/testdata/schema.graphql +++ /dev/null @@ -1,9 +0,0 @@ -#import "scalars/*.graphql" -#import "types/query.graphql" -#import "nested/nested.graphql" -#import "deep/**/*.graphql" - -schema { - query: Query - mutation: Mutation -} \ No newline at end of file diff --git a/pkg/imports/testdata/types/mutation.graphql b/pkg/imports/testdata/types/mutation.graphql deleted file mode 100644 index bd659efbf..000000000 --- a/pkg/imports/testdata/types/mutation.graphql +++ /dev/null @@ -1,3 +0,0 @@ -type Mutation { - mutateFoo: Foo -} \ No newline at end of file diff --git a/pkg/imports/testdata/types/query.graphql b/pkg/imports/testdata/types/query.graphql deleted file mode 100644 index 21e1521d0..000000000 --- a/pkg/imports/testdata/types/query.graphql +++ /dev/null @@ -1,3 +0,0 @@ -type Query { - foo: Foo -} \ No newline at end of file diff --git a/pkg/internal/quotes/quotes.go b/pkg/internal/quotes/quotes.go deleted file mode 100644 index b4a2f5e7d..000000000 --- a/pkg/internal/quotes/quotes.go +++ /dev/null @@ -1,20 +0,0 @@ -package quotes - -const ( - quoteByte = '"' - quoteStr = string(quoteByte) -) - -// WrapBytes returns a new slice wrapping the given s -// in quotes (") by making a copy. -func WrapBytes(s []byte) []byte { - cp := make([]byte, len(s)+2) - cp[0] = quoteByte - copy(cp[1:], s) - cp[len(s)+1] = quoteByte - return cp -} - -func WrapString(str string) string { - return quoteStr + str + quoteStr -} diff --git a/pkg/internal/quotes/quotes_test.go b/pkg/internal/quotes/quotes_test.go deleted file mode 100644 index 5575dc5a2..000000000 --- a/pkg/internal/quotes/quotes_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package quotes - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestWrapBytes(t *testing.T) { - testCases := []struct { - s []byte - want []byte - }{ - {nil, []byte(`""`)}, - {[]byte("foo"), []byte(`"foo"`)}, - } - for _, tc := range testCases { - tc := tc - t.Run(string(tc.s), func(t *testing.T) { - r := WrapBytes(tc.s) - assert.Equal(t, tc.want, r) - }) - } -} diff --git a/pkg/internal/unsafebytes/unsafebytes.go b/pkg/internal/unsafebytes/unsafebytes.go deleted file mode 100644 index 63751ba95..000000000 --- a/pkg/internal/unsafebytes/unsafebytes.go +++ /dev/null @@ -1,62 +0,0 @@ -package unsafebytes - -import ( - "reflect" - "strconv" - "unsafe" -) - -func BytesToInt64(byteSlice []byte) int64 { - out, _ := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 64) - return out -} - -func BytesToInt32(byteSlice []byte) int32 { - out, _ := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 32) - return int32(out) -} - -func BytesToFloat32(byteSlice []byte) float32 { - out, _ := strconv.ParseFloat(*(*string)(unsafe.Pointer(&byteSlice)), 64) - return float32(out) -} - -func BytesToString(bytes []byte) string { - sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&bytes)) - stringHeader := reflect.StringHeader{Data: sliceHeader.Data, Len: sliceHeader.Len} - return *(*string)(unsafe.Pointer(&stringHeader)) // nolint: govet -} - -func BytesToBool(byteSlice []byte) bool { - out, _ := strconv.ParseBool(*(*string)(unsafe.Pointer(&byteSlice))) - return out -} - -func StringToBytes(str string) []byte { - hdr := *(*reflect.StringHeader)(unsafe.Pointer(&str)) // nolint: govet - return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ // nolint: govet - Data: hdr.Data, - Len: hdr.Len, - Cap: hdr.Len, - })) -} - -func BytesIsValidFloat32(byteSlice []byte) bool { - _, err := strconv.ParseFloat(*(*string)(unsafe.Pointer(&byteSlice)), 64) - return err == nil -} - -func BytesIsValidInt64(byteSlice []byte) bool { - _, err := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 64) - return err == nil -} - -func BytesIsValidInt32(byteSlice []byte) bool { - _, err := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 32) - return err == nil -} - -func BytesIsValidBool(byteSlice []byte) bool { - _, err := strconv.ParseBool(*(*string)(unsafe.Pointer(&byteSlice))) - return err == nil -} diff --git a/pkg/internal/unsafebytes/unsafebytes_test.go b/pkg/internal/unsafebytes/unsafebytes_test.go deleted file mode 100644 index ca4e8c911..000000000 --- a/pkg/internal/unsafebytes/unsafebytes_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package unsafebytes - -import "testing" - -func TestByteSliceToInt(t *testing.T) { - got := BytesToInt64([]byte("10")) - if got != 10 { - t.Fatalf("want 10, got: %d", got) - } - got = BytesToInt64([]byte("01")) - if got != 1 { - t.Fatalf("want 1, got: %d", got) - } - got = BytesToInt64([]byte("0")) - if got != 0 { - t.Fatalf("want 0, got: %d", got) - } - got = BytesToInt64([]byte("-10")) - if got != -10 { - t.Fatalf("want -10, got: %d", got) - } -} - -func TestByteSliceToFloat(t *testing.T) { - got := BytesToFloat32([]byte("10.24")) - if got != 10.24 { - t.Fatalf("want 10.24, got: %f", got) - } - got = BytesToFloat32([]byte("0")) - if got != 0 { - t.Fatalf("want 0, got: %f", got) - } - got = BytesToFloat32([]byte("001")) - if got != 1 { - t.Fatalf("want 1, got: %f", got) - } -} - -func TestBytesToString(t *testing.T) { - got := BytesToString([]byte("foo")) - if got != "foo" { - t.Fatalf("want foo, got: %s", got) - } -} - -func TestBytesToBool(t *testing.T) { - if !BytesToBool([]byte("true")) { - t.Fatal("want true") - } - if BytesToBool([]byte("false")) { - t.Fatal("want false") - } - if !BytesToBool([]byte("1")) { - t.Fatal("want true") - } - if BytesToBool([]byte("0")) { - t.Fatal("want false") - } - if BytesToBool([]byte("2")) { - t.Fatal("want false") - } -} - -func testValidation(validationFunc func([]byte) bool, value []byte, expectation bool) func(t *testing.T) { - return func(t *testing.T) { - if expectation != validationFunc(value) { - t.Fatalf("want: %t, got: %t", expectation, !expectation) - } - } -} - -func TestBytesIsValidFloat32(t *testing.T) { - t.Run("valid float", testValidation(BytesIsValidFloat32, []byte("1.23"), true)) - t.Run("valid float", testValidation(BytesIsValidFloat32, []byte("123"), true)) - t.Run("invalid float", testValidation(BytesIsValidFloat32, []byte("1.2.3"), false)) - t.Run("invalid float", testValidation(BytesIsValidFloat32, []byte("true"), false)) - t.Run("invalid float", testValidation(BytesIsValidFloat32, []byte("\"1.23\""), false)) -} - -func TestBytesIsValidInt64(t *testing.T) { - t.Run("valid int", testValidation(BytesIsValidInt64, []byte("123"), true)) - t.Run("valid big int", testValidation(BytesIsValidInt64, []byte("8293842938492834982"), true)) - t.Run("invalid very big int", testValidation(BytesIsValidInt64, []byte("8293842938492834982394"), false)) - t.Run("invalid float", testValidation(BytesIsValidInt64, []byte("1.23"), false)) - t.Run("invalid bool", testValidation(BytesIsValidInt64, []byte("true"), false)) - t.Run("invalid quoted int", testValidation(BytesIsValidInt64, []byte("\"123\""), false)) -} - -func TestBytesIsValidInt32(t *testing.T) { - t.Run("valid int", testValidation(BytesIsValidInt32, []byte("123"), true)) - t.Run("invalid valid big int", testValidation(BytesIsValidInt32, []byte("8293842938492834982"), false)) - t.Run("invalid very big int", testValidation(BytesIsValidInt32, []byte("829384293849283498239482938"), false)) - t.Run("invalid float", testValidation(BytesIsValidInt32, []byte("1.23"), false)) - t.Run("invalid bool", testValidation(BytesIsValidInt32, []byte("true"), false)) - t.Run("invalid quoted int", testValidation(BytesIsValidInt32, []byte("\"123\""), false)) -} - -func TestBytesIsValidBool(t *testing.T) { - t.Run("valid bool", testValidation(BytesIsValidBool, []byte("true"), true)) - t.Run("valid bool", testValidation(BytesIsValidBool, []byte("false"), true)) - t.Run("invalid bool", testValidation(BytesIsValidBool, []byte("0"), true)) - t.Run("invalid bool", testValidation(BytesIsValidBool, []byte("1"), true)) - t.Run("invalid bool", testValidation(BytesIsValidBool, []byte("\"false\""), false)) - t.Run("invalid bool", testValidation(BytesIsValidBool, []byte("2"), false)) -} - -func BenchmarkByteSliceToInt(b *testing.B) { - - in := []byte("1024") - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - out := BytesToInt64(in) - if out != 1024 { - b.Fatalf("want 1024, got: %d", out) - } - } -} - -func BenchmarkByteSliceToFloat(b *testing.B) { - - in := []byte("10.24") - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - out := BytesToFloat32(in) - if out != 10.24 { - b.Fatalf("want 1024, got: %f", out) - } - } -} - -func BenchmarkByteSliceToString(b *testing.B) { - - in := []byte("foo") - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - out := BytesToString(in) - if out != "foo" { - b.Fatalf("want 1024, got: %s", out) - } - } -} diff --git a/pkg/internal/unsafeparser/unsafeparser.go b/pkg/internal/unsafeparser/unsafeparser.go deleted file mode 100644 index a1b0fa3a1..000000000 --- a/pkg/internal/unsafeparser/unsafeparser.go +++ /dev/null @@ -1,33 +0,0 @@ -// package unsafeparser is for testing purposes only when error handling is overhead and panics are ok -package unsafeparser - -import ( - "os" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" -) - -func ParseGraphqlDocumentString(input string) ast.Document { - doc, report := astparser.ParseGraphqlDocumentString(input) - if report.HasErrors() { - panic(report.Error()) - } - return doc -} - -func ParseGraphqlDocumentBytes(input []byte) ast.Document { - doc, report := astparser.ParseGraphqlDocumentBytes(input) - if report.HasErrors() { - panic(report.Error()) - } - return doc -} - -func ParseGraphqlDocumentFile(filePath string) ast.Document { - fileBytes, err := os.ReadFile(filePath) - if err != nil { - panic(err) - } - return ParseGraphqlDocumentBytes(fileBytes) -} diff --git a/pkg/internal/unsafeprinter/unsafeprinter.go b/pkg/internal/unsafeprinter/unsafeprinter.go deleted file mode 100644 index 4c9aedc8b..000000000 --- a/pkg/internal/unsafeprinter/unsafeprinter.go +++ /dev/null @@ -1,28 +0,0 @@ -package unsafeprinter - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" -) - -func Print(document, definition *ast.Document) string { - str, err := astprinter.PrintString(document, definition) - if err != nil { - panic(err) - } - return str -} - -func PrettyPrint(document, definition *ast.Document) string { - str, err := astprinter.PrintStringIndent(document, definition, " ") - if err != nil { - panic(err) - } - return str -} - -func Prettify(document string) string { - doc := unsafeparser.ParseGraphqlDocumentString(document) - return PrettyPrint(&doc, nil) -} diff --git a/pkg/introspection/converter.go b/pkg/introspection/converter.go deleted file mode 100644 index bea54b70c..000000000 --- a/pkg/introspection/converter.go +++ /dev/null @@ -1,275 +0,0 @@ -package introspection - -import ( - "encoding/json" - "fmt" - "io" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astimport" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type JsonConverter struct { - schema *Schema - doc *ast.Document - parser *astparser.Parser -} - -func (j *JsonConverter) GraphQLDocument(introspectionJSON io.Reader) (*ast.Document, error) { - var data Data - if err := json.NewDecoder(introspectionJSON).Decode(&data); err != nil { - return nil, fmt.Errorf("failed to parse inrospection json: %v", err) - } - - j.schema = &data.Schema - j.doc = ast.NewDocument() - j.parser = astparser.NewParser() - - if err := j.importSchema(); err != nil { - return nil, fmt.Errorf("failed to convert graphql schema: %v", err) - } - - return j.doc, nil -} - -func (j *JsonConverter) importSchema() error { - j.doc.ImportSchemaDefinition(j.schema.TypeNames()) - - for i := 0; i < len(j.schema.Types); i++ { - if err := j.importFullType(j.schema.Types[i]); err != nil { - return err - } - } - - for i := 0; i < len(j.schema.Directives); i++ { - if err := j.importDirective(j.schema.Directives[i]); err != nil { - return err - } - } - - return nil -} - -func (j *JsonConverter) importFullType(fullType FullType) (err error) { - switch fullType.Kind { - case SCALAR: - j.doc.ImportScalarTypeDefinition(fullType.Name, fullType.Description) - case OBJECT: - err = j.importObject(fullType) - case ENUM: - j.importEnum(fullType) - case INTERFACE: - err = j.importInterface(fullType) - case UNION: - err = j.importUnion(fullType) - case INPUTOBJECT: - err = j.importInputObject(fullType) - } - return -} - -func (j *JsonConverter) importObject(fullType FullType) error { - fieldRefs, err := j.importFields(fullType.Fields) - if err != nil { - return err - } - - iRefs := make([]int, len(fullType.Interfaces)) - for i := 0; i < len(iRefs); i++ { - iRefs[i] = j.importType(fullType.Interfaces[i]) - } - - j.doc.ImportObjectTypeDefinition( - fullType.Name, - fullType.Description, - fieldRefs, - iRefs) - - return nil -} - -func (j *JsonConverter) importInterface(fullType FullType) error { - fieldRefs, err := j.importFields(fullType.Fields) - if err != nil { - return err - } - - j.doc.ImportInterfaceTypeDefinition( - fullType.Name, - fullType.Description, - fieldRefs) - - return nil -} - -func (j *JsonConverter) importDirective(directive Directive) error { - argRefs, err := j.importInputFields(directive.Args) - if err != nil { - return err - } - - j.doc.ImportDirectiveDefinition( - directive.Name, - directive.Description, - argRefs, - directive.Locations) - - return nil -} - -func (j *JsonConverter) importInputObject(fullType FullType) error { - argRefs, err := j.importInputFields(fullType.InputFields) - if err != nil { - return err - } - - j.doc.ImportInputObjectTypeDefinition( - fullType.Name, - fullType.Description, - argRefs) - - return nil -} - -func (j *JsonConverter) importEnum(fullType FullType) { - valueRefs := make([]int, len(fullType.EnumValues)) - for i := 0; i < len(valueRefs); i++ { - var directiveRefs []int - if fullType.EnumValues[i].IsDeprecated { - directiveRefs = append(directiveRefs, j.importDeprecatedDirective(fullType.EnumValues[i].DeprecationReason)) - } - - valueRefs[i] = j.doc.ImportEnumValueDefinition( - fullType.EnumValues[i].Name, - fullType.EnumValues[i].Description, - directiveRefs, - ) - } - - j.doc.ImportEnumTypeDefinition( - fullType.Name, - fullType.Description, - valueRefs) -} - -func (j *JsonConverter) importUnion(fullType FullType) error { - typeRefs := make([]int, len(fullType.PossibleTypes)) - for i := 0; i < len(typeRefs); i++ { - typeRefs[i] = j.importType(fullType.PossibleTypes[i]) - } - - j.doc.ImportUnionTypeDefinition( - fullType.Name, - fullType.Description, - typeRefs) - - return nil -} - -func (j *JsonConverter) importFields(fields []Field) (refs []int, err error) { - refs = make([]int, len(fields)) - for i := 0; i < len(refs); i++ { - fieldRef, err := j.importField(fields[i]) - if err != nil { - return nil, err - } - refs[i] = fieldRef - } - - return -} - -func (j *JsonConverter) importField(field Field) (ref int, err error) { - typeRef := j.importType(field.Type) - - argRefs, err := j.importInputFields(field.Args) - if err != nil { - return -1, err - } - - var directiveRefs []int - if field.IsDeprecated { - directiveRefs = append(directiveRefs, j.importDeprecatedDirective(field.DeprecationReason)) - } - - return j.doc.ImportFieldDefinition( - field.Name, field.Description, typeRef, argRefs, directiveRefs), nil -} - -func (j *JsonConverter) importInputFields(fields []InputValue) (refs []int, err error) { - refs = make([]int, len(fields)) - for i := 0; i < len(refs); i++ { - argRef, err := j.importInputField(fields[i]) - if err != nil { - return nil, err - } - refs[i] = argRef - } - return -} - -func (j *JsonConverter) importInputField(field InputValue) (ref int, err error) { - typeRef := j.importType(field.Type) - - defaultValue, err := j.importDefaultValue(field.DefaultValue) - if err != nil { - return -1, err - } - - return j.doc.ImportInputValueDefinition( - field.Name, field.Description, typeRef, defaultValue), nil -} - -func (j *JsonConverter) importType(typeRef TypeRef) (ref int) { - switch typeRef.Kind { - case LIST: - return j.doc.AddListType(j.importType(*typeRef.OfType)) - case NONNULL: - return j.doc.AddNonNullType(j.importType(*typeRef.OfType)) - } - - return j.doc.AddNamedType([]byte(*typeRef.Name)) -} - -func (j *JsonConverter) importDefaultValue(defaultValue *string) (out ast.DefaultValue, err error) { - if defaultValue == nil { - return - } - - from := ast.NewDocument() - from.Input.AppendInputString(*defaultValue) - - report := &operationreport.Report{} - - j.parser.PrepareImport(from, report) - value := j.parser.ParseValue() - - if report.HasErrors() { - err = report - return - } - - importer := &astimport.Importer{} - return ast.DefaultValue{ - IsDefined: true, - Value: importer.ImportValue(value, from, j.doc), - }, nil -} - -func (j *JsonConverter) importDeprecatedDirective(reason *string) (ref int) { - var args []int - if reason != nil { - valueRef := j.doc.ImportStringValue([]byte(*reason), strings.Contains(*reason, "\n")) - value := ast.Value{ - Kind: ast.ValueKindString, - Ref: valueRef, - } - j.doc.AddValue(value) - args = append(args, j.doc.ImportArgument(DeprecationReasonArgName, value)) - } - - return j.doc.ImportDirective(DeprecatedDirectiveName, args) -} diff --git a/pkg/introspection/converter_test.go b/pkg/introspection/converter_test.go deleted file mode 100644 index fed1c20e0..000000000 --- a/pkg/introspection/converter_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package introspection - -import ( - "bytes" - "encoding/json" - "os" - "testing" - - "github.com/jensneuse/diffview" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestJSONConverter_GraphQLDocument(t *testing.T) { - starwarsSchemaBytes, err := os.ReadFile("./fixtures/starwars.golden") - require.NoError(t, err) - - definition, report := astparser.ParseGraphqlDocumentBytes(starwarsSchemaBytes) - if report.HasErrors() { - t.Fatal(report) - } - - gen := NewGenerator() - var data Data - gen.Generate(&definition, &report, &data) - if report.HasErrors() { - t.Fatal(report) - } - - outputPretty, err := json.MarshalIndent(data, "", " ") - require.NoError(t, err) - - converter := JsonConverter{} - buf := bytes.NewBuffer(outputPretty) - doc, err := converter.GraphQLDocument(buf) - assert.NoError(t, err) - - outWriter := &bytes.Buffer{} - err = astprinter.PrintIndent(doc, nil, []byte(" "), outWriter) - require.NoError(t, err) - - schemaOutputPretty := outWriter.Bytes() - // fmt.Println(string(schemaOutputPretty)) - // ioutil.WriteFile("./fixtures/starwars_generated.graphql", schemaOutputPretty, os.ModePerm) - - // Ensure that recreated sdl is valid - definition, report = astparser.ParseGraphqlDocumentBytes(schemaOutputPretty) - if report.HasErrors() { - t.Fatal(report) - } - - // Check that recreated sdl is the same as original - goldie.Assert(t, "starwars", schemaOutputPretty) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/starwars.golden") - require.NoError(t, err) - - diffview.NewGoland().DiffViewBytes("startwars", fixture, schemaOutputPretty) - } -} - -func BenchmarkJsonConverter_GraphQLDocument(b *testing.B) { - introspectedBytes, err := os.ReadFile("./testdata/swapi_introspection_response.json") - require.NoError(b, err) - b.ResetTimer() - - for i := 0; i < b.N; i++ { - buf := bytes.NewBuffer(introspectedBytes) - converter := JsonConverter{} - _, _ = converter.GraphQLDocument(buf) - } -} diff --git a/pkg/introspection/fixtures/interfaces_implementing_interfaces.golden b/pkg/introspection/fixtures/interfaces_implementing_interfaces.golden deleted file mode 100644 index 42dd3ec03..000000000 --- a/pkg/introspection/fixtures/interfaces_implementing_interfaces.golden +++ /dev/null @@ -1,254 +0,0 @@ -{ - "__schema": { - "queryType": null, - "mutationType": null, - "subscriptionType": null, - "types": [ - { - "kind": "INTERFACE", - "name": "BaseInterface", - "description": "", - "fields": [ - { - "name": "fieldOne", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INTERFACE", - "name": "SecondInterface", - "description": "", - "fields": [ - { - "name": "fieldOne", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fieldTwo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [ - { - "kind": "INTERFACE", - "name": "BaseInterface", - "ofType": null - } - ], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INTERFACE", - "name": "ThirdInterface", - "description": "", - "fields": [ - { - "name": "fieldOne", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fieldTwo", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fieldThree", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [ - { - "kind": "INTERFACE", - "name": "SecondInterface", - "ofType": null - }, - { - "kind": "INTERFACE", - "name": "BaseInterface", - "ofType": null - } - ], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INTERFACE", - "name": "IDType", - "description": "", - "fields": [ - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INTERFACE", - "name": "SoftDelete", - "description": "", - "fields": [ - { - "name": "deleted", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [ - { - "kind": "INTERFACE", - "name": "IDType", - "ofType": null - } - ], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INTERFACE", - "name": "Record", - "description": "", - "fields": [ - { - "name": "data", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": null, - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [ - { - "kind": "INTERFACE", - "name": "SoftDelete", - "ofType": null - }, - { - "kind": "INTERFACE", - "name": "IDType", - "ofType": null - } - ], - "enumValues": [], - "possibleTypes": [] - } - ], - "directives": [] - } -} \ No newline at end of file diff --git a/pkg/introspection/fixtures/starwars.golden b/pkg/introspection/fixtures/starwars.golden deleted file mode 100644 index ff2beb570..000000000 --- a/pkg/introspection/fixtures/starwars.golden +++ /dev/null @@ -1,203 +0,0 @@ -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -"The query type, represents all of the entry points into our object graph" -type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human @deprecated(reason: "skynet wins!") - starship(id: ID!): Starship -} - -"The mutation type, represents all updates we can make to our data" -type Mutation { - createReview(episode: Episode, review: ReviewInput!): Review -} - -"The subscription type, represents all subscriptions we can make to our data" -type Subscription { - reviewAdded(episode: Episode): Review -} - -"The episodes in the Star Wars trilogy" -enum Episode { - "Star Wars Episode IV: A New Hope, released in 1977." - NEWHOPE @deprecated(reason: "No longer supported") - "Star Wars Episode V: The Empire Strikes Back, released in 1980." - EMPIRE - "Star Wars Episode VI: Return of the Jedi, released in 1983." - JEDI -} - -"A character from the Star Wars universe" -interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -"Units of height" -enum LengthUnit { - "The standard unit around the world" - METER - "Primarily used in the United States" - FOOT -} - -"A humanoid creature from the Star Wars universe" -type Human implements Character { - "The ID of the human" - id: ID! - "What this human calls themselves" - name: String! - "The home planet of the human, or null if unknown" - homePlanet: String - "Height in the preferred unit, default is meters" - height(unit: LengthUnit = METER): Float - "Mass in kilograms, or null if unknown" - mass: Float - "This human's friends, or an empty list if they have none" - friends: [Character] - "The friends of the human exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this human appears in" - appearsIn: [Episode]! - "A list of starships this person has piloted, or an empty list if none" - starships: [Starship] -} - -"An autonomous mechanical character in the Star Wars universe" -type Droid implements Character { - "The ID of the droid" - id: ID! - "What others call this droid" - name: String! - "This droid's friends, or an empty list if they have none" - friends: [Character] - "The friends of the droid exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this droid appears in" - appearsIn: [Episode]! - "This droid's primary function" - primaryFunction: String -} - -"A connection object for a character's friends" -type FriendsConnection { - "The total number of friends" - totalCount: Int - "The edges for each of the character's friends." - edges: [FriendsEdge] - "A list of the friends, as a convenience when edges are not needed." - friends: [Character] - "Information for paginating this connection" - pageInfo: PageInfo! -} - -"An edge object for a character's friends" -type FriendsEdge { - "A cursor used for pagination" - cursor: ID! - "The character represented by this friendship edge" - node: Character -} - -"Information for paginating this connection" -type PageInfo { - startCursor: ID - endCursor: ID - hasNextPage: Boolean! -} - -"Represents a review for a movie" -type Review { - "The movie" - episode: Episode - "The number of stars this review gave, 1-5" - stars: Int! - "Comment about the movie" - commentary: String -} - -"The input object sent when someone is creating a new review" -input ReviewInput { - "0-5 stars" - stars: Int! - "Comment about the movie, optional" - commentary: String - "Favorite color, optional" - favorite_color: ColorInput -} - -"The input object sent when passing in a color" -input ColorInput { - red: Int! - green: Int! - blue: Int! -} - -type Starship { - "The ID of the starship" - id: ID! - "The name of the starship" - name: String! - "The old name of starship" - oldName: String @deprecated(reason: "why not?") - "Length of the starship, along the longest axis" - length(unit: LengthUnit = METER): Float -} - -"The union represents combined return result which could be on of the types: Human, Droid, Starship" -union SearchResult = Human | Droid | Starship - -"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int - -"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float - -"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String - -"The `Boolean` scalar type represents `true` or `false` ." -scalar Boolean - -""" -The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as "4") or integer (such as 4) input value will be accepted as an ID. -""" -scalar ID - -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - "Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT - -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE \ No newline at end of file diff --git a/pkg/introspection/fixtures/starwars_introspected.golden b/pkg/introspection/fixtures/starwars_introspected.golden deleted file mode 100644 index b2118a9b5..000000000 --- a/pkg/introspection/fixtures/starwars_introspected.golden +++ /dev/null @@ -1,1359 +0,0 @@ -{ - "__schema": { - "queryType": { - "name": "Query" - }, - "mutationType": { - "name": "Mutation" - }, - "subscriptionType": { - "name": "Subscription" - }, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": "The query type, represents all of the entry points into our object graph", - "fields": [ - { - "name": "hero", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "reviews", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Review", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "search", - "description": "", - "args": [ - { - "name": "text", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "UNION", - "name": "SearchResult", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "character", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "droid", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "human", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Human", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "skynet wins!" - }, - { - "name": "starship", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": "The mutation type, represents all updates we can make to our data", - "fields": [ - { - "name": "createReview", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "review", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "ReviewInput", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Review", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Subscription", - "description": "The subscription type, represents all subscriptions we can make to our data", - "fields": [ - { - "name": "reviewAdded", - "description": "", - "args": [ - { - "name": "episode", - "description": "", - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Review", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "ENUM", - "name": "Episode", - "description": "The episodes in the Star Wars trilogy", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [ - { - "name": "NEWHOPE", - "description": "Star Wars Episode IV: A New Hope, released in 1977.", - "isDeprecated": true, - "deprecationReason": "No longer supported" - }, - { - "name": "EMPIRE", - "description": "Star Wars Episode V: The Empire Strikes Back, released in 1980.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "JEDI", - "description": "Star Wars Episode VI: Return of the Jedi, released in 1983.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": [] - }, - { - "kind": "INTERFACE", - "name": "Character", - "description": "A character from the Star Wars universe", - "fields": [ - { - "name": "id", - "description": "The ID of the character", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the character", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "The friends of the character, or an empty list if they have none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friendsConnection", - "description": "The friends of the character exposed as a connection with edges", - "args": [ - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsConnection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "appearsIn", - "description": "The movies this character appears in", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Human", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - } - ] - }, - { - "kind": "ENUM", - "name": "LengthUnit", - "description": "Units of height", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [ - { - "name": "METER", - "description": "The standard unit around the world", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FOOT", - "description": "Primarily used in the United States", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Human", - "description": "A humanoid creature from the Star Wars universe", - "fields": [ - { - "name": "id", - "description": "The ID of the human", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "What this human calls themselves", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "homePlanet", - "description": "The home planet of the human, or null if unknown", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height", - "description": "Height in the preferred unit, default is meters", - "args": [ - { - "name": "unit", - "description": "", - "type": { - "kind": "ENUM", - "name": "LengthUnit", - "ofType": null - }, - "defaultValue": "METER" - } - ], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass", - "description": "Mass in kilograms, or null if unknown", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "This human's friends, or an empty list if they have none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friendsConnection", - "description": "The friends of the human exposed as a connection with edges", - "args": [ - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsConnection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "appearsIn", - "description": "The movies this human appears in", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starships", - "description": "A list of starships this person has piloted, or an empty list if none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - ], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Droid", - "description": "An autonomous mechanical character in the Star Wars universe", - "fields": [ - { - "name": "id", - "description": "The ID of the droid", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "What others call this droid", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "This droid's friends, or an empty list if they have none", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friendsConnection", - "description": "The friends of the droid exposed as a connection with edges", - "args": [ - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsConnection", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "appearsIn", - "description": "The movies this droid appears in", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "primaryFunction", - "description": "This droid's primary function", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - ], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "FriendsConnection", - "description": "A connection object for a character's friends", - "fields": [ - { - "name": "totalCount", - "description": "The total number of friends", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "The edges for each of the character's friends.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "FriendsEdge", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "friends", - "description": "A list of the friends, as a convenience when edges are not needed.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pageInfo", - "description": "Information for paginating this connection", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "PageInfo", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "FriendsEdge", - "description": "An edge object for a character's friends", - "fields": [ - { - "name": "cursor", - "description": "A cursor used for pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "The character represented by this friendship edge", - "args": [], - "type": { - "kind": "INTERFACE", - "name": "Character", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "PageInfo", - "description": "Information for paginating this connection", - "fields": [ - { - "name": "startCursor", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endCursor", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hasNextPage", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Review", - "description": "Represents a review for a movie", - "fields": [ - { - "name": "episode", - "description": "The movie", - "args": [], - "type": { - "kind": "ENUM", - "name": "Episode", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "stars", - "description": "The number of stars this review gave, 1-5", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "commentary", - "description": "Comment about the movie", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INPUT_OBJECT", - "name": "ReviewInput", - "description": "The input object sent when someone is creating a new review", - "fields": [], - "inputFields": [ - { - "name": "stars", - "description": "0-5 stars", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "commentary", - "description": "Comment about the movie, optional", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "favorite_color", - "description": "Favorite color, optional", - "type": { - "kind": "INPUT_OBJECT", - "name": "ColorInput", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "INPUT_OBJECT", - "name": "ColorInput", - "description": "The input object sent when passing in a color", - "fields": [], - "inputFields": [ - { - "name": "red", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "green", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "blue", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - } - ], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "OBJECT", - "name": "Starship", - "description": "", - "fields": [ - { - "name": "id", - "description": "The ID of the starship", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the starship", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "oldName", - "description": "The old name of starship", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": true, - "deprecationReason": "why not?" - }, - { - "name": "length", - "description": "Length of the starship, along the longest axis", - "args": [ - { - "name": "unit", - "description": "", - "type": { - "kind": "ENUM", - "name": "LengthUnit", - "ofType": null - }, - "defaultValue": "METER" - } - ], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "UNION", - "name": "SearchResult", - "description": "The union represents combined return result which could be on of the types: Human, Droid, Starship", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Human", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Droid", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - ] - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false` .", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `4`) or integer (such as 4) input value will be accepted as an ID.", - "fields": [], - "inputFields": [], - "interfaces": [], - "enumValues": [], - "possibleTypes": [] - } - ], - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "FIELD_DEFINITION", - "ENUM_VALUE" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion\n for how to access supported similar data. Formatted in\n [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ], - "isRepeatable": false - }, - { - "name": "delegateField", - "description": "", - "locations": [ - "OBJECT", - "INTERFACE" - ], - "args": [ - { - "name": "name", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": true - } - ] - } -} \ No newline at end of file diff --git a/pkg/introspection/generator.go b/pkg/introspection/generator.go deleted file mode 100644 index 4f8c10f33..000000000 --- a/pkg/introspection/generator.go +++ /dev/null @@ -1,352 +0,0 @@ -package introspection - -import ( - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafebytes" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -const ( - DeprecatedDirectiveName = "deprecated" - DeprecationReasonArgName = "reason" -) - -type Generator struct { - Data *Data - walker *astvisitor.Walker - visitor *introspectionVisitor -} - -func NewGenerator() *Generator { - walker := astvisitor.NewWalker(48) - visitor := introspectionVisitor{ - Walker: &walker, - } - - walker.RegisterEnterDocumentVisitor(&visitor) - walker.RegisterEnterDirectiveLocationVisitor(&visitor) - walker.RegisterEnterInputValueDefinitionVisitor(&visitor) - walker.RegisterEnterRootOperationTypeDefinitionVisitor(&visitor) - walker.RegisterEnterScalarTypeDefinitionVisitor(&visitor) - walker.RegisterEnterUnionMemberTypeVisitor(&visitor) - - walker.RegisterDirectiveDefinitionVisitor(&visitor) - walker.RegisterEnumTypeDefinitionVisitor(&visitor) - walker.RegisterFieldDefinitionVisitor(&visitor) - walker.RegisterInputObjectTypeDefinitionVisitor(&visitor) - walker.RegisterInterfaceTypeDefinitionVisitor(&visitor) - walker.RegisterObjectTypeDefinitionVisitor(&visitor) - walker.RegisterUnionTypeDefinitionVisitor(&visitor) - - walker.RegisterLeaveEnumValueDefinitionVisitor(&visitor) - - return &Generator{ - walker: &walker, - visitor: &visitor, - } -} - -func (g *Generator) Generate(definition *ast.Document, report *operationreport.Report, data *Data) { - g.visitor.data = data - g.visitor.definition = definition - g.walker.Walk(definition, nil, report) -} - -type introspectionVisitor struct { - *astvisitor.Walker - definition *ast.Document - data *Data - currentType FullType - currentField Field - currentDirective Directive -} - -func (i *introspectionVisitor) EnterDocument(operation, definition *ast.Document) { - i.data.Schema = NewSchema() -} - -func (i *introspectionVisitor) EnterObjectTypeDefinition(ref int) { - i.currentType = NewFullType() - i.currentType.Name = i.definition.ObjectTypeDefinitionNameString(ref) - i.currentType.Kind = OBJECT - i.currentType.Description = i.definition.ObjectTypeDescriptionNameString(ref) - for _, typeRef := range i.definition.ObjectTypeDefinitions[ref].ImplementsInterfaces.Refs { - name := i.definition.TypeNameString(typeRef) - i.currentType.Interfaces = append(i.currentType.Interfaces, TypeRef{ - Kind: INTERFACE, - Name: &name, - }) - } -} - -func (i *introspectionVisitor) LeaveObjectTypeDefinition(ref int) { - if strings.HasPrefix(i.currentType.Name, "__") { - return - } - i.data.Schema.Types = append(i.data.Schema.Types, i.currentType) -} - -func (i *introspectionVisitor) EnterFieldDefinition(ref int) { - i.currentField = NewField() - i.currentField.Name = i.definition.FieldDefinitionNameString(ref) - i.currentField.Description = i.definition.FieldDefinitionDescriptionString(ref) - i.currentField.Type = i.TypeRef(i.definition.FieldDefinitionType(ref)) - - if i.definition.FieldDefinitionHasDirectives(ref) { - directiveRef, exists := i.definition.FieldDefinitionDirectiveByName(ref, []byte(DeprecatedDirectiveName)) - if exists { - i.currentField.IsDeprecated = true - i.currentField.DeprecationReason = i.deprecationReason(directiveRef) - } - } -} - -func (i *introspectionVisitor) LeaveFieldDefinition(ref int) { - if strings.HasPrefix(i.currentField.Name, "__") { - return - } - i.currentType.Fields = append(i.currentType.Fields, i.currentField) -} - -func (i *introspectionVisitor) EnterInputValueDefinition(ref int) { - var defaultValue *string - if i.definition.InputValueDefinitionHasDefaultValue(ref) { - value := i.definition.InputValueDefinitionDefaultValue(ref) - printedValue, err := i.definition.PrintValueBytes(value, nil) - if err != nil { - i.StopWithInternalErr(err) - return - } - printedStr := unsafebytes.BytesToString(printedValue) - defaultValue = &printedStr - } - - inputValue := InputValue{ - Name: i.definition.InputValueDefinitionNameString(ref), - Description: i.definition.InputValueDefinitionDescriptionString(ref), - Type: i.TypeRef(i.definition.InputValueDefinitionType(ref)), - DefaultValue: defaultValue, - } - - switch i.Ancestors[len(i.Ancestors)-1].Kind { - case ast.NodeKindInputObjectTypeDefinition: - i.currentType.InputFields = append(i.currentType.InputFields, inputValue) - case ast.NodeKindFieldDefinition: - i.currentField.Args = append(i.currentField.Args, inputValue) - case ast.NodeKindDirectiveDefinition: - i.currentDirective.Args = append(i.currentDirective.Args, inputValue) - } -} - -func (i *introspectionVisitor) EnterInterfaceTypeDefinition(ref int) { - i.currentType = NewFullType() - i.currentType.Kind = INTERFACE - i.currentType.Name = i.definition.InterfaceTypeDefinitionNameString(ref) - i.currentType.Description = i.definition.InterfaceTypeDefinitionDescriptionString(ref) - - interfaceNameBytes := i.definition.InterfaceTypeDefinitionNameBytes(ref) - for objectTypeDefRef := range i.definition.ObjectTypeDefinitions { - if i.definition.ObjectTypeDefinitionImplementsInterface(objectTypeDefRef, interfaceNameBytes) { - objectName := i.definition.ObjectTypeDefinitionNameString(objectTypeDefRef) - i.currentType.PossibleTypes = append(i.currentType.PossibleTypes, TypeRef{ - Kind: OBJECT, - Name: &objectName, - }) - } - } - - for _, interfaceTypeExtension := range i.definition.InterfaceTypeExtensions { - interfaceTypeExtensionName := i.definition.Input.ByteSliceString(interfaceTypeExtension.Name) - for _, implementedInterfaceRef := range interfaceTypeExtension.ImplementsInterfaces.Refs { - if i.currentType.Name == interfaceTypeExtensionName { - implementedInterfaceName := i.definition.TypeNameString(implementedInterfaceRef) - i.currentType.Interfaces = append(i.currentType.Interfaces, TypeRef{ - Kind: INTERFACE, - Name: &implementedInterfaceName, - }) - } - } - } - - for _, implementedInterfaceRef := range i.definition.InterfaceTypeDefinitions[ref].ImplementsInterfaces.Refs { - implementedInterfaceName := i.definition.TypeNameString(implementedInterfaceRef) - i.currentType.Interfaces = append(i.currentType.Interfaces, TypeRef{ - Kind: INTERFACE, - Name: &implementedInterfaceName, - }) - } -} - -func (i *introspectionVisitor) LeaveInterfaceTypeDefinition(ref int) { - if strings.HasPrefix(i.currentType.Name, "__") { - return - } - i.data.Schema.Types = append(i.data.Schema.Types, i.currentType) -} - -func (i *introspectionVisitor) EnterScalarTypeDefinition(ref int) { - typeDefinition := NewFullType() - typeDefinition.Kind = SCALAR - typeDefinition.Name = i.definition.ScalarTypeDefinitionNameString(ref) - typeDefinition.Description = i.definition.ScalarTypeDefinitionDescriptionString(ref) - i.data.Schema.Types = append(i.data.Schema.Types, typeDefinition) -} - -func (i *introspectionVisitor) EnterUnionTypeDefinition(ref int) { - i.currentType = NewFullType() - i.currentType.Kind = UNION - i.currentType.Name = i.definition.UnionTypeDefinitionNameString(ref) - i.currentType.Description = i.definition.UnionTypeDefinitionDescriptionString(ref) -} - -func (i *introspectionVisitor) LeaveUnionTypeDefinition(ref int) { - if strings.HasPrefix(i.currentType.Name, "__") { - return - } - i.data.Schema.Types = append(i.data.Schema.Types, i.currentType) -} - -func (i *introspectionVisitor) EnterUnionMemberType(ref int) { - name := i.definition.TypeNameString(ref) - i.currentType.PossibleTypes = append(i.currentType.PossibleTypes, TypeRef{ - Kind: OBJECT, - Name: &name, - }) -} - -func (i *introspectionVisitor) EnterEnumTypeDefinition(ref int) { - i.currentType = NewFullType() - i.currentType.Kind = ENUM - i.currentType.Name = i.definition.EnumTypeDefinitionNameString(ref) - i.currentType.Description = i.definition.EnumTypeDefinitionDescriptionString(ref) -} - -func (i *introspectionVisitor) LeaveEnumTypeDefinition(ref int) { - if strings.HasPrefix(i.currentType.Name, "__") { - return - } - i.data.Schema.Types = append(i.data.Schema.Types, i.currentType) -} - -func (i *introspectionVisitor) LeaveEnumValueDefinition(ref int) { - enumValue := EnumValue{ - Name: i.definition.EnumValueDefinitionNameString(ref), - Description: i.definition.EnumValueDefinitionDescriptionString(ref), - } - - if i.definition.EnumValueDefinitionHasDirectives(ref) { - directiveRef, exists := i.definition.EnumValueDefinitionDirectiveByName(ref, []byte(DeprecatedDirectiveName)) - if exists { - enumValue.IsDeprecated = true - enumValue.DeprecationReason = i.deprecationReason(directiveRef) - } - } - - i.currentType.EnumValues = append(i.currentType.EnumValues, enumValue) -} - -func (i *introspectionVisitor) EnterInputObjectTypeDefinition(ref int) { - i.currentType = NewFullType() - i.currentType.Kind = INPUTOBJECT - i.currentType.Name = i.definition.InputObjectTypeDefinitionNameString(ref) - i.currentType.Description = i.definition.InputObjectTypeDefinitionDescriptionString(ref) -} - -func (i *introspectionVisitor) LeaveInputObjectTypeDefinition(ref int) { - i.data.Schema.Types = append(i.data.Schema.Types, i.currentType) -} - -func (i *introspectionVisitor) EnterDirectiveDefinition(ref int) { - i.currentDirective = NewDirective() - i.currentDirective.Name = i.definition.DirectiveDefinitionNameString(ref) - i.currentDirective.Description = i.definition.DirectiveDefinitionDescriptionString(ref) - i.currentDirective.IsRepeatable = i.definition.DirectiveDefinitions[ref].Repeatable.IsRepeatable -} - -func (i *introspectionVisitor) LeaveDirectiveDefinition(ref int) { - i.data.Schema.Directives = append(i.data.Schema.Directives, i.currentDirective) -} - -func (i *introspectionVisitor) EnterDirectiveLocation(location ast.DirectiveLocation) { - i.currentDirective.Locations = append(i.currentDirective.Locations, location.LiteralString()) -} - -func (i *introspectionVisitor) EnterRootOperationTypeDefinition(ref int) { - switch i.definition.RootOperationTypeDefinitions[ref].OperationType { - case ast.OperationTypeQuery: - i.data.Schema.QueryType = &TypeName{ - Name: i.definition.Input.ByteSliceString(i.definition.RootOperationTypeDefinitions[ref].NamedType.Name), - } - case ast.OperationTypeMutation: - i.data.Schema.MutationType = &TypeName{ - Name: i.definition.Input.ByteSliceString(i.definition.RootOperationTypeDefinitions[ref].NamedType.Name), - } - case ast.OperationTypeSubscription: - i.data.Schema.SubscriptionType = &TypeName{ - Name: i.definition.Input.ByteSliceString(i.definition.RootOperationTypeDefinitions[ref].NamedType.Name), - } - } -} - -func (i *introspectionVisitor) TypeRef(typeRef int) TypeRef { - switch i.definition.Types[typeRef].TypeKind { - case ast.TypeKindNamed: - name := i.definition.TypeNameBytes(typeRef) - node, exists := i.definition.Index.FirstNodeByNameBytes(name) - if !exists { - return TypeRef{} - } - var typeKind __TypeKind - switch node.Kind { - case ast.NodeKindScalarTypeDefinition: - typeKind = SCALAR - case ast.NodeKindObjectTypeDefinition: - typeKind = OBJECT - case ast.NodeKindEnumTypeDefinition: - typeKind = ENUM - case ast.NodeKindInterfaceTypeDefinition: - typeKind = INTERFACE - case ast.NodeKindUnionTypeDefinition: - typeKind = UNION - case ast.NodeKindInputObjectTypeDefinition: - typeKind = INPUTOBJECT - } - nameStr := unsafebytes.BytesToString(name) - return TypeRef{ - Kind: typeKind, - Name: &nameStr, - } - case ast.TypeKindNonNull: - ofType := i.TypeRef(i.definition.Types[typeRef].OfType) - return TypeRef{ - Kind: NONNULL, - OfType: &ofType, - } - case ast.TypeKindList: - ofType := i.TypeRef(i.definition.Types[typeRef].OfType) - return TypeRef{ - Kind: LIST, - OfType: &ofType, - } - default: - return TypeRef{} - } -} - -func (i *introspectionVisitor) deprecationReason(directiveRef int) (reason *string) { - argValue, exists := i.definition.DirectiveArgumentValueByName(directiveRef, []byte(DeprecationReasonArgName)) - if exists { - reasonContent := i.definition.ValueContentString(argValue) - return &reasonContent - } - - defaultValue := i.definition.DirectiveDefinitionArgumentDefaultValueString(DeprecatedDirectiveName, DeprecationReasonArgName) - if defaultValue != "" { - return &defaultValue - } - - return -} diff --git a/pkg/introspection/generator_test.go b/pkg/introspection/generator_test.go deleted file mode 100644 index 5e8abd638..000000000 --- a/pkg/introspection/generator_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package introspection - -import ( - "encoding/json" - "os" - "testing" - - "github.com/jensneuse/diffview" - - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestGenerator_Generate(t *testing.T) { - starwarsSchemaBytes, err := os.ReadFile("./testdata/starwars.schema.graphql") - if err != nil { - panic(err) - } - - definition, report := astparser.ParseGraphqlDocumentBytes(starwarsSchemaBytes) - if report.HasErrors() { - t.Fatal(report) - } - - gen := NewGenerator() - var data Data - gen.Generate(&definition, &report, &data) - if report.HasErrors() { - t.Fatal(report) - } - - outputPretty, err := json.MarshalIndent(data, "", " ") - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "starwars_introspected", outputPretty) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/starwars_introspected.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("startwars_introspected", fixture, outputPretty) - } -} - -func TestGenerator_Generate_Interfaces_Implementing_Interfaces(t *testing.T) { - interfacesSchemaBytes, err := os.ReadFile("./testdata/interfaces_implementing_interfaces.graphql") - if err != nil { - panic(err) - } - - definition, report := astparser.ParseGraphqlDocumentBytes(interfacesSchemaBytes) - if report.HasErrors() { - t.Fatal(report) - } - - gen := NewGenerator() - var data Data - gen.Generate(&definition, &report, &data) - if report.HasErrors() { - t.Fatal(report) - } - - outputPretty, err := json.MarshalIndent(data, "", " ") - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "interfaces_implementing_interfaces", outputPretty) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/interfaces_implementing_interfaces.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("interfaces_implements_interfaces", fixture, outputPretty) - } -} diff --git a/pkg/introspection/introspection.go b/pkg/introspection/introspection.go deleted file mode 100644 index 586585516..000000000 --- a/pkg/introspection/introspection.go +++ /dev/null @@ -1,155 +0,0 @@ -//go:generate go-enum -f=$GOFILE --noprefix --marshal - -// Package introspection takes a GraphQL Schema and provides the introspection JSON to fulfill introspection queries. -package introspection - -import ( - "bytes" -) - -type Data struct { - Schema Schema `json:"__schema"` -} - -type Schema struct { - QueryType *TypeName `json:"queryType"` - MutationType *TypeName `json:"mutationType"` - SubscriptionType *TypeName `json:"subscriptionType"` - Types []FullType `json:"types"` - Directives []Directive `json:"directives"` -} - -func (s *Schema) TypeNames() (query, mutation, subscription string) { - if s.QueryType != nil { - query = s.QueryType.Name - } - if s.MutationType != nil { - mutation = s.MutationType.Name - } - if s.SubscriptionType != nil { - subscription = s.SubscriptionType.Name - } - return -} - -func NewSchema() Schema { - return Schema{ - Types: make([]FullType, 0), - Directives: make([]Directive, 0), - } -} - -type TypeName struct { - Name string `json:"name"` -} - -type FullType struct { - Kind __TypeKind `json:"kind"` - Name string `json:"name"` - Description string `json:"description"` - // not empty for __TypeKind OBJECT and INTERFACE only - Fields []Field `json:"fields"` - // not empty for __TypeKind INPUT_OBJECT only - InputFields []InputValue `json:"inputFields"` - // not empty for __TypeKind OBJECT only - Interfaces []TypeRef `json:"interfaces"` - // not empty for __TypeKind ENUM only - EnumValues []EnumValue `json:"enumValues"` - // not empty for __TypeKind INTERFACE and UNION only - PossibleTypes []TypeRef `json:"possibleTypes"` -} - -func NewFullType() FullType { - return FullType{ - Fields: make([]Field, 0), - InputFields: make([]InputValue, 0), - Interfaces: make([]TypeRef, 0), - EnumValues: make([]EnumValue, 0), - PossibleTypes: make([]TypeRef, 0), - } -} - -/* -ENUM( -SCALAR -LIST -NON_NULL -OBJECT -ENUM -INTERFACE -UNION -INPUT_OBJECT -) -*/ -type __TypeKind int - -func (x __TypeKind) MarshalJSON() ([]byte, error) { - - text, err := x.MarshalText() - if err != nil { - return nil, err - } - - var buff bytes.Buffer - _, err = buff.WriteRune('"') - if err != nil { - return nil, err - } - _, err = buff.Write(text) - if err != nil { - return nil, err - } - _, err = buff.WriteRune('"') - - return buff.Bytes(), err -} - -type TypeRef struct { - Kind __TypeKind `json:"kind"` - Name *string `json:"name"` - OfType *TypeRef `json:"ofType"` -} - -type Field struct { - Name string `json:"name"` - Description string `json:"description"` - Args []InputValue `json:"args"` - Type TypeRef `json:"type"` - IsDeprecated bool `json:"isDeprecated"` - DeprecationReason *string `json:"deprecationReason"` -} - -func NewField() Field { - return Field{ - Args: make([]InputValue, 0), - } -} - -type EnumValue struct { - Name string `json:"name"` - Description string `json:"description"` - IsDeprecated bool `json:"isDeprecated"` - DeprecationReason *string `json:"deprecationReason"` -} - -type InputValue struct { - Name string `json:"name"` - Description string `json:"description"` - Type TypeRef `json:"type"` - DefaultValue *string `json:"defaultValue"` -} - -type Directive struct { - Name string `json:"name"` - Description string `json:"description"` - Locations []string `json:"locations"` - Args []InputValue `json:"args"` - IsRepeatable bool `json:"isRepeatable"` -} - -func NewDirective() Directive { - return Directive{ - Locations: make([]string, 0), - Args: make([]InputValue, 0), - } -} diff --git a/pkg/introspection/introspection_enum.go b/pkg/introspection/introspection_enum.go deleted file mode 100644 index f66b96bcc..000000000 --- a/pkg/introspection/introspection_enum.go +++ /dev/null @@ -1,83 +0,0 @@ -// Code generated by go-enum -// DO NOT EDIT! - -package introspection - -import ( - "fmt" -) - -const ( - // SCALAR is a __TypeKind of type SCALAR - SCALAR __TypeKind = iota - // LIST is a __TypeKind of type LIST - LIST - // NONNULL is a __TypeKind of type NON_NULL - NONNULL - // OBJECT is a __TypeKind of type OBJECT - OBJECT - // ENUM is a __TypeKind of type ENUM - ENUM - // INTERFACE is a __TypeKind of type INTERFACE - INTERFACE - // UNION is a __TypeKind of type UNION - UNION - // INPUTOBJECT is a __TypeKind of type INPUT_OBJECT - INPUTOBJECT -) - -const ___TypeKindName = "SCALARLISTNON_NULLOBJECTENUMINTERFACEUNIONINPUT_OBJECT" - -var ___TypeKindMap = map[__TypeKind]string{ - 0: ___TypeKindName[0:6], - 1: ___TypeKindName[6:10], - 2: ___TypeKindName[10:18], - 3: ___TypeKindName[18:24], - 4: ___TypeKindName[24:28], - 5: ___TypeKindName[28:37], - 6: ___TypeKindName[37:42], - 7: ___TypeKindName[42:54], -} - -// String implements the Stringer interface. -func (x __TypeKind) String() string { - if str, ok := ___TypeKindMap[x]; ok { - return str - } - return fmt.Sprintf("__TypeKind(%d)", x) -} - -var ___TypeKindValue = map[string]__TypeKind{ - ___TypeKindName[0:6]: 0, - ___TypeKindName[6:10]: 1, - ___TypeKindName[10:18]: 2, - ___TypeKindName[18:24]: 3, - ___TypeKindName[24:28]: 4, - ___TypeKindName[28:37]: 5, - ___TypeKindName[37:42]: 6, - ___TypeKindName[42:54]: 7, -} - -// Parse__TypeKind attempts to convert a string to a __TypeKind -func Parse__TypeKind(name string) (__TypeKind, error) { - if x, ok := ___TypeKindValue[name]; ok { - return x, nil - } - return __TypeKind(0), fmt.Errorf("%s is not a valid __TypeKind", name) -} - -// MarshalText implements the text marshaller method -func (x *__TypeKind) MarshalText() ([]byte, error) { - return []byte(x.String()), nil -} - -// UnmarshalText implements the text unmarshaller method -func (x *__TypeKind) UnmarshalText(text []byte) error { - name := string(text) - tmp, err := Parse__TypeKind(name) - if err != nil { - return err - } - *x = tmp - return nil -} diff --git a/pkg/introspection/introspection_test.go b/pkg/introspection/introspection_test.go deleted file mode 100644 index 5754cb6f7..000000000 --- a/pkg/introspection/introspection_test.go +++ /dev/null @@ -1,31 +0,0 @@ -package introspection - -import ( - "encoding/json" - "os" - "testing" -) - -func TestIntrospectionSerialization(t *testing.T) { - inputData, err := os.ReadFile("./testdata/swapi_introspection_response.json") - if err != nil { - panic(err) - } - - var data Data - - err = json.Unmarshal(inputData, &data) - if err != nil { - panic(err) - } - - outputData, err := json.MarshalIndent(data, "", " ") - if err != nil { - panic(err) - } - - err = os.WriteFile("./testdata/out_swapi_introspection_response.json", outputData, os.ModePerm) - if err != nil { - panic(err) - } -} diff --git a/pkg/introspection/testdata/interfaces_implementing_interfaces.graphql b/pkg/introspection/testdata/interfaces_implementing_interfaces.graphql deleted file mode 100644 index 4da54e5b2..000000000 --- a/pkg/introspection/testdata/interfaces_implementing_interfaces.graphql +++ /dev/null @@ -1,35 +0,0 @@ -interface BaseInterface { - fieldOne: String! -} - -interface SecondInterface implements BaseInterface { - fieldOne: String! - fieldTwo: String! -} - -interface ThirdInterface implements SecondInterface & BaseInterface { - fieldOne: String! - fieldTwo: String! - fieldThree: String! -} - -interface IDType { - id: ID! -} - -interface SoftDelete { - deleted: Boolean! -} - -extend interface SoftDelete implements IDType { - id: ID! -} - -interface Record { - data: String! -} - -extend interface Record implements SoftDelete & IDType { - id: ID! - deleted: Boolean! -} diff --git a/pkg/introspection/testdata/out_swapi_introspection_response.json b/pkg/introspection/testdata/out_swapi_introspection_response.json deleted file mode 100755 index 85511c259..000000000 --- a/pkg/introspection/testdata/out_swapi_introspection_response.json +++ /dev/null @@ -1,43273 +0,0 @@ -{ - "__schema": { - "queryType": { - "name": "Query" - }, - "mutationType": { - "name": "Mutation" - }, - "subscriptionType": { - "name": "Subscription" - }, - "types": [ - { - "kind": "OBJECT", - "name": "AddToFilmPlanetsPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "planetsPlanet", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToFilmSpeciesPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "speciesSpecies", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToFilmStarshipsPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starshipsStarship", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToFilmVehiclesPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "vehiclesVehicle", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToPeopleFilmPayload", - "description": "", - "fields": [ - { - "name": "charactersPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToPeoplePlanetPayload", - "description": "", - "fields": [ - { - "name": "residentsPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "homeworldPlanet", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToPeopleSpeciesPayload", - "description": "", - "fields": [ - { - "name": "peoplePerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "speciesSpecies", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToPeopleStarshipsPayload", - "description": "", - "fields": [ - { - "name": "pilotsPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starshipsStarship", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AddToPeopleVehiclesPayload", - "description": "", - "fields": [ - { - "name": "pilotsPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "vehiclesVehicle", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AssetPreviousValues", - "description": "", - "fields": [ - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fileName", - "description": "Original File Name", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "handle", - "description": "The File Handle", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size", - "description": "The Size Of The File", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "AssetSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "AssetPreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreateAsset", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreateFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreatePerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreatePlanet", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreateSpecies", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreateStarship", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "CreateVehicle", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FilmPreviousValues", - "description": "", - "fields": [ - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "director", - "description": "The name of the director of this film.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title", - "description": "The title of this film", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FilmSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "FilmPreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "InvokeFunctionInput", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "name", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "input", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "clientMutationId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "InvokeFunctionPayload", - "description": "", - "fields": [ - { - "name": "result", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "clientMutationId", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": "", - "fields": [ - { - "name": "createAsset", - "description": "", - "args": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createFilm", - "description": "", - "args": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createPerson", - "description": "", - "args": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createPlanet", - "description": "", - "args": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createSpecies", - "description": "", - "args": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createStarship", - "description": "", - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createVehicle", - "description": "", - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateAsset", - "description": "", - "args": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateFilm", - "description": "", - "args": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatePerson", - "description": "", - "args": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatePlanet", - "description": "", - "args": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateSpecies", - "description": "", - "args": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateStarship", - "description": "", - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateVehicle", - "description": "", - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreateAsset", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateAsset", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateAsset", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreateFilm", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateFilm", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateFilm", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreatePerson", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdatePerson", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreatePerson", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreatePlanet", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdatePlanet", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreatePlanet", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreateSpecies", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateSpecies", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateSpecies", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreateStarship", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateStarship", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateStarship", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updateOrCreateVehicle", - "description": "", - "args": [ - { - "name": "update", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateVehicle", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateVehicle", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteAsset", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteFilm", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deletePerson", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deletePlanet", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteSpecies", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteStarship", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deleteVehicle", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToFilmPlanets", - "description": "", - "args": [ - { - "name": "planetsPlanetId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmPlanetsPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToFilmSpecies", - "description": "", - "args": [ - { - "name": "speciesSpeciesId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmSpeciesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToFilmStarships", - "description": "", - "args": [ - { - "name": "starshipsStarshipId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmStarshipsPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToFilmVehicles", - "description": "", - "args": [ - { - "name": "vehiclesVehicleId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmVehiclesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToPeopleFilm", - "description": "", - "args": [ - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleFilmPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToPeoplePlanet", - "description": "", - "args": [ - { - "name": "homeworldPlanetId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "residentsPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeoplePlanetPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToPeopleSpecies", - "description": "", - "args": [ - { - "name": "speciesSpeciesId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "peoplePersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleSpeciesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToPeopleStarships", - "description": "", - "args": [ - { - "name": "starshipsStarshipId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleStarshipsPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "addToPeopleVehicles", - "description": "", - "args": [ - { - "name": "vehiclesVehicleId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleVehiclesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromFilmPlanets", - "description": "", - "args": [ - { - "name": "planetsPlanetId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmPlanetsPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromFilmSpecies", - "description": "", - "args": [ - { - "name": "speciesSpeciesId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmSpeciesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromFilmStarships", - "description": "", - "args": [ - { - "name": "starshipsStarshipId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmStarshipsPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromFilmVehicles", - "description": "", - "args": [ - { - "name": "vehiclesVehicleId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmVehiclesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromPeopleFilm", - "description": "", - "args": [ - { - "name": "filmsFilmId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleFilmPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromPeoplePlanet", - "description": "", - "args": [ - { - "name": "homeworldPlanetId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "residentsPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeoplePlanetPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromPeopleSpecies", - "description": "", - "args": [ - { - "name": "speciesSpeciesId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "peoplePersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleSpeciesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromPeopleStarships", - "description": "", - "args": [ - { - "name": "starshipsStarshipId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleStarshipsPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeFromPeopleVehicles", - "description": "", - "args": [ - { - "name": "vehiclesVehicleId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleVehiclesPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "invokeFunction", - "description": "", - "args": [ - { - "name": "input", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "InvokeFunctionInput", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "InvokeFunctionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PersonPreviousValues", - "description": "", - "fields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "args": [], - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this person.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender", - "description": "", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PersonSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "PersonPreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PlanetPreviousValues", - "description": "", - "fields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the planet", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PlanetSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "PlanetPreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromFilmPlanetsPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "planetsPlanet", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromFilmSpeciesPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "speciesSpecies", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromFilmStarshipsPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starshipsStarship", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromFilmVehiclesPayload", - "description": "", - "fields": [ - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "vehiclesVehicle", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromPeopleFilmPayload", - "description": "", - "fields": [ - { - "name": "charactersPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "filmsFilm", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromPeoplePlanetPayload", - "description": "", - "fields": [ - { - "name": "residentsPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "homeworldPlanet", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromPeopleSpeciesPayload", - "description": "", - "fields": [ - { - "name": "peoplePerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "speciesSpecies", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromPeopleStarshipsPayload", - "description": "", - "fields": [ - { - "name": "pilotsPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starshipsStarship", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveFromPeopleVehiclesPayload", - "description": "", - "fields": [ - { - "name": "pilotsPerson", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "vehiclesVehicle", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SpeciesPreviousValues", - "description": "", - "fields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this species.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "averageHeight", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SpeciesSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "SpeciesPreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "StarshipPreviousValues", - "description": "", - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "StarshipSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "StarshipPreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Subscription", - "description": "", - "fields": [ - { - "name": "Asset", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AssetSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Film", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "FilmSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Person", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "PersonSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Planet", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "PlanetSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Species", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "SpeciesSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Starship", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "StarshipSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Vehicle", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "VehicleSubscriptionPayload", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateAsset", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdatePerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdatePlanet", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateSpecies", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateStarship", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "UpdateVehicle", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "VehiclePreviousValues", - "description": "", - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilterNode", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "VehicleSubscriptionPayload", - "description": "", - "fields": [ - { - "name": "mutation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "previousValues", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "VehiclePreviousValues", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "_ModelMutationType", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "CREATED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UPDATED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DELETED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Asset", - "description": "System model for Assets", - "fields": [ - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fileName", - "description": "Original File Name", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "handle", - "description": "The File Handle", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size", - "description": "The Size Of The File", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "AssetOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fileName_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fileName_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "handle_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "handle_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimeType_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimeType_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "width_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "width_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "DateTime", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Film", - "description": "A Film is a single film.", - "fields": [ - { - "name": "characters", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "director", - "description": "The name of the director of this film.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "planets", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "species", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starships", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title", - "description": "The title of this film", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "vehicles", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_charactersMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_planetsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_speciesMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_starshipsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_vehiclesMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "FilmOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "director_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "director_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodeId_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodeId_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openingCrawl_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openingCrawl_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "releaseDate_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "releaseDate_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "INTERFACE", - "name": "Node", - "description": "An object with an ID", - "fields": [ - { - "name": "id", - "description": "The id of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - ] - }, - { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUEGREY", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HAZEL", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PINK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLD", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DARK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "PERSON_GENDER", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MALE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FEMALE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HERMAPHRODITE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "AUBURN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLONDE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "description": "The skin color of this person.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FAIR", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLD", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIGHT", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREENTAN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PALE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "METAL", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DARK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWNMOTTLE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MOTTLEDGREEN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "TAN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SILVER", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Person", - "description": "A Person is an individual person or character within the Star Wars universe", - "fields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "films", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "args": [], - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "homeworld", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this person.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "species", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "starships", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "vehicles", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_speciesMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_starshipsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_vehiclesMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender", - "description": "", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "PersonOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "birthYear_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "birthYear_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gender_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gender_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Planet", - "description": "A Planet is a large mass, planet or planetoid in the Star Wars Universe, at the time of 0 ABY.", - "fields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "films", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of the planet", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "residents", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_residentsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "PlanetOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diameter_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diameter_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gravity_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gravity_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orbitalPeriod_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orbitalPeriod_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "population_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "population_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rotationPeriod_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rotationPeriod_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "surfaceWater_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "surfaceWater_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Query", - "description": "", - "fields": [ - { - "name": "allAssets", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "AssetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allFilms", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allPersons", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allPlanets", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allSpecies", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allStarships", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allVehicles", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allAssetsMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "AssetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allFilmsMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allPersonsMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allPlanetsMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allSpeciesMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allStarshipsMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_allVehiclesMeta", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Asset", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Film", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Person", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Planet", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Species", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Starship", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "Vehicle", - "description": "", - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "node", - "description": "Fetches an object given its ID", - "args": [ - { - "name": "id", - "description": "The ID of an object", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "AMBER", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLD", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HAZEL", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INDIGO", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PINK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SILVER", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLDEN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLONDE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "BLUE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "CAUCASIAN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DARK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MAGENTA", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PALE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PALEPINK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PEACH", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PINK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PURPLE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "TAN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNKNOWN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ASIAN", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HISPANIC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Species", - "description": "A Species is a type of person or character within the Star Wars Universe.", - "fields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "films", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this species.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "people", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_peopleMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "averageHeight_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageHeight_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageLifespan_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageLifespan_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "classification_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "classification_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "designation_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "designation_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Starship", - "description": "A Starship is a single transport craft that has hyperdrive capability.", - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "films", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pilots", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_pilotsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "StarshipOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "cargoCapacity_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cargoCapacity_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hyperdriveRating_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hyperdriveRating_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mglt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mglt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Vehicle", - "description": "A Vehicle is a single transport craft that does not have hyperdrive capability.", - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "films", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "pilots", - "description": "", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "_pilotsMeta", - "description": "Meta information about the query.", - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": "", - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "description": "", - "fields": null, - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "VehicleOrderBy", - "description": "", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "cargoCapacity_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cargoCapacity_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": "", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "_QueryMeta", - "description": "Meta information about the query.", - "fields": [ - { - "name": "count", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL’s execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locations", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__DirectiveLocation", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "onOperation", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onFragment", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - }, - { - "name": "onField", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": true, - "deprecationReason": "Use `locations`." - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "INPUT_OBJECT", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "fields": [ - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Directive", - "ofType": null - } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "fields": [ - { - "name": "kind", - "description": "", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__TypeKind", - "ofType": null - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": "", - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": "", - "args": [ - { - "name": "includeDeprecated", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Field", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interfaces", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "possibleTypes", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": "", - "args": [ - { - "name": "includeDeprecated", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__EnumValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inputFields", - "description": "", - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ofType", - "description": "", - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - } - ], - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ], - "isRepeatable": false - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "ENUM_VALUE", - "FIELD_DEFINITION" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ], - "isRepeatable": false - } - ] - } -} \ No newline at end of file diff --git a/pkg/introspection/testdata/starwars.schema.graphql b/pkg/introspection/testdata/starwars.schema.graphql deleted file mode 100644 index 1e80760d5..000000000 --- a/pkg/introspection/testdata/starwars.schema.graphql +++ /dev/null @@ -1,351 +0,0 @@ -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -"The query type, represents all of the entry points into our object graph" -type Query { - hero(episode: Episode): Character - reviews(episode: Episode!): [Review] - search(text: String): [SearchResult] - character(id: ID!): Character - droid(id: ID!): Droid - human(id: ID!): Human @deprecated(reason: "skynet wins!") - starship(id: ID!): Starship -} - -"The mutation type, represents all updates we can make to our data" -type Mutation { - createReview(episode: Episode, review: ReviewInput!): Review -} - -"The subscription type, represents all subscriptions we can make to our data" -type Subscription { - reviewAdded(episode: Episode): Review -} - -"The episodes in the Star Wars trilogy" -enum Episode { - "Star Wars Episode IV: A New Hope, released in 1977." - NEWHOPE @deprecated(reason: "No longer supported") - "Star Wars Episode V: The Empire Strikes Back, released in 1980." - EMPIRE - "Star Wars Episode VI: Return of the Jedi, released in 1983." - JEDI -} - -"A character from the Star Wars universe" -interface Character { - "The ID of the character" - id: ID! - "The name of the character" - name: String! - "The friends of the character, or an empty list if they have none" - friends: [Character] - "The friends of the character exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this character appears in" - appearsIn: [Episode]! -} - -"Units of height" -enum LengthUnit { - "The standard unit around the world" - METER - "Primarily used in the United States" - FOOT -} - -"A humanoid creature from the Star Wars universe" -type Human implements Character { - "The ID of the human" - id: ID! - "What this human calls themselves" - name: String! - "The home planet of the human, or null if unknown" - homePlanet: String - "Height in the preferred unit, default is meters" - height(unit: LengthUnit = METER): Float - "Mass in kilograms, or null if unknown" - mass: Float - "This human's friends, or an empty list if they have none" - friends: [Character] - "The friends of the human exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this human appears in" - appearsIn: [Episode]! - "A list of starships this person has piloted, or an empty list if none" - starships: [Starship] -} - -"An autonomous mechanical character in the Star Wars universe" -type Droid implements Character { - "The ID of the droid" - id: ID! - "What others call this droid" - name: String! - "This droid's friends, or an empty list if they have none" - friends: [Character] - "The friends of the droid exposed as a connection with edges" - friendsConnection(first: Int, after: ID): FriendsConnection! - "The movies this droid appears in" - appearsIn: [Episode]! - "This droid's primary function" - primaryFunction: String -} - -"A connection object for a character's friends" -type FriendsConnection { - "The total number of friends" - totalCount: Int - "The edges for each of the character's friends." - edges: [FriendsEdge] - "A list of the friends, as a convenience when edges are not needed." - friends: [Character] - "Information for paginating this connection" - pageInfo: PageInfo! -} - -"An edge object for a character's friends" -type FriendsEdge { - "A cursor used for pagination" - cursor: ID! - "The character represented by this friendship edge" - node: Character -} - -"Information for paginating this connection" -type PageInfo { - startCursor: ID - endCursor: ID - hasNextPage: Boolean! -} - -"Represents a review for a movie" -type Review { - "The movie" - episode: Episode - "The number of stars this review gave, 1-5" - stars: Int! - "Comment about the movie" - commentary: String -} - -"The input object sent when someone is creating a new review" -input ReviewInput { - "0-5 stars" - stars: Int! - "Comment about the movie, optional" - commentary: String - "Favorite color, optional" - favorite_color: ColorInput -} - -"The input object sent when passing in a color" -input ColorInput { - red: Int! - green: Int! - blue: Int! -} - -type Starship { - "The ID of the starship" - id: ID! - "The name of the starship" - name: String! - "The old name of starship" - oldName: String @deprecated(reason: "why not?") - "Length of the starship, along the longest axis" - length(unit: LengthUnit = METER): Float -} - -"The union represents combined return result which could be on of the types: Human, Droid, Starship" -union SearchResult = Human | Droid | Starship - -"The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The `Boolean` scalar type represents `true` or `false` ." -scalar Boolean -"The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `4`) or integer (such as 4) input value will be accepted as an ID." -scalar ID -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE -directive @delegateField( - name: String! -) repeatable on OBJECT | INTERFACE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! - isRepeatable: Boolean! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the `__TypeKind` enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given `__Type` is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. `fields` and `interfaces` are valid fields." - OBJECT - "Indicates this type is an interface. `fields` ` and ` `possibleTypes` are valid fields." - INTERFACE - "Indicates this type is a union. `possibleTypes` is a valid field." - UNION - "Indicates this type is an enum. `enumValues` is a valid field." - ENUM - "Indicates this type is an input object. `inputFields` is a valid field." - INPUT_OBJECT - "Indicates this type is a list. `ofType` is a valid field." - LIST - "Indicates this type is a non-null. `ofType` is a valid field." - NON_NULL -} diff --git a/pkg/introspection/testdata/swapi_introspection_response.json b/pkg/introspection/testdata/swapi_introspection_response.json deleted file mode 100644 index 84759999b..000000000 --- a/pkg/introspection/testdata/swapi_introspection_response.json +++ /dev/null @@ -1,43270 +0,0 @@ -{ - "__schema": { - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "locations": [ - "FIELD", - "FRAGMENT_SPREAD", - "INLINE_FRAGMENT" - ], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - }, - "defaultValue": null - } - ] - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "locations": [ - "ENUM_VALUE", - "FIELD_DEFINITION" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": "\"No longer supported\"" - } - ] - } - ], - "mutationType": { - "name": "Mutation" - }, - "subscriptionType": { - "name": "Subscription" - }, - "queryType": { - "name": "Query" - }, - "types": [ - { - "inputFields": null, - "name": "AddToFilmPlanetsPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "planetsPlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToFilmSpeciesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "speciesSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToFilmStarshipsPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "starshipsStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToFilmVehiclesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "vehiclesVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToPeopleFilmPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "charactersPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToPeoplePlanetPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "residentsPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "homeworldPlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToPeopleSpeciesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "peoplePerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "speciesSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToPeopleStarshipsPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "pilotsPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "starshipsStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AddToPeopleVehiclesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "pilotsPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "vehiclesVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AssetPreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "fileName", - "description": "Original File Name", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "handle", - "description": "The File Handle", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "mimeType", - "description": "The Mime Type", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "size", - "description": "The Size Of The File", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "url", - "description": "The Url Of The Asset", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "AssetSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "AssetSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AssetSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "AssetPreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "CreateAsset", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "CreateFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "CreatePerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "CreatePlanet", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "CreateSpecies", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "CreateStarship", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "CreateVehicle", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "FilmPreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "director", - "description": "The name of the director of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - { - "name": "title", - "description": "The title of this film", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "FilmSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "FilmSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "FilmSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "FilmPreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "FilmcharactersPerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "FilmplanetsPlanet", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "FilmspeciesSpecies", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "FilmstarshipsStarship", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "FilmvehiclesVehicle", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "name", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "input", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "clientMutationId", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "InvokeFunctionInput", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "InvokeFunctionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "result", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "clientMutationId", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Mutation", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "createAsset", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - }, - { - "name": "createFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "createPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "createPlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "createSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - }, - { - "name": "createStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - { - "name": "createVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - }, - { - "name": "updateAsset", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - }, - { - "name": "updateFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "updatePerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": null, - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "updatePlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "updateSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - }, - { - "name": "updateStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - { - "name": "updateVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - }, - { - "name": "updateOrCreateAsset", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateAsset", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateAsset", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - }, - { - "name": "updateOrCreateFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateFilm", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateFilm", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "updateOrCreatePerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdatePerson", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreatePerson", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "updateOrCreatePlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdatePlanet", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreatePlanet", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "updateOrCreateSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateSpecies", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateSpecies", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - }, - { - "name": "updateOrCreateStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateStarship", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateStarship", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - { - "name": "updateOrCreateVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "update", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "UpdateVehicle", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "create", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "CreateVehicle", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - }, - { - "name": "deleteAsset", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - }, - { - "name": "deleteFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "deletePerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "deletePlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "deleteSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - }, - { - "name": "deleteStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - { - "name": "deleteVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - }, - { - "name": "addToFilmPlanets", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "planetsPlanetId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmPlanetsPayload", - "ofType": null - } - }, - { - "name": "addToFilmSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "speciesSpeciesId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmSpeciesPayload", - "ofType": null - } - }, - { - "name": "addToFilmStarships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "starshipsStarshipId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmStarshipsPayload", - "ofType": null - } - }, - { - "name": "addToFilmVehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "vehiclesVehicleId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToFilmVehiclesPayload", - "ofType": null - } - }, - { - "name": "addToPeopleFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleFilmPayload", - "ofType": null - } - }, - { - "name": "addToPeoplePlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "homeworldPlanetId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "residentsPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeoplePlanetPayload", - "ofType": null - } - }, - { - "name": "addToPeopleSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "speciesSpeciesId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "peoplePersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleSpeciesPayload", - "ofType": null - } - }, - { - "name": "addToPeopleStarships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "starshipsStarshipId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleStarshipsPayload", - "ofType": null - } - }, - { - "name": "addToPeopleVehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "vehiclesVehicleId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AddToPeopleVehiclesPayload", - "ofType": null - } - }, - { - "name": "removeFromFilmPlanets", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "planetsPlanetId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmPlanetsPayload", - "ofType": null - } - }, - { - "name": "removeFromFilmSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "speciesSpeciesId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmSpeciesPayload", - "ofType": null - } - }, - { - "name": "removeFromFilmStarships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "starshipsStarshipId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmStarshipsPayload", - "ofType": null - } - }, - { - "name": "removeFromFilmVehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "vehiclesVehicleId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromFilmVehiclesPayload", - "ofType": null - } - }, - { - "name": "removeFromPeopleFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filmsFilmId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleFilmPayload", - "ofType": null - } - }, - { - "name": "removeFromPeoplePlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "homeworldPlanetId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "residentsPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeoplePlanetPayload", - "ofType": null - } - }, - { - "name": "removeFromPeopleSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "speciesSpeciesId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "peoplePersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleSpeciesPayload", - "ofType": null - } - }, - { - "name": "removeFromPeopleStarships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "starshipsStarshipId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleStarshipsPayload", - "ofType": null - } - }, - { - "name": "removeFromPeopleVehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "vehiclesVehicleId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "pilotsPersonId", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "RemoveFromPeopleVehiclesPayload", - "ofType": null - } - }, - { - "name": "invokeFunction", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "input", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "InvokeFunctionInput", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "InvokeFunctionPayload", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PersonPreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - } - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - } - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this person.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "PersonSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender", - "description": "", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "PersonSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PersonSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "PersonPreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PersonfilmsFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PersonhomeworldPlanet", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PersonspeciesSpecies", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PersonstarshipsStarship", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PersonvehiclesVehicle", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PlanetPreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "name", - "description": "The name of the planet", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "PlanetSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "PlanetSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PlanetSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "PlanetPreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PlanetfilmsFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "PlanetresidentsPerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromFilmPlanetsPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "planetsPlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromFilmSpeciesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "speciesSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromFilmStarshipsPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "starshipsStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromFilmVehiclesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "vehiclesVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromPeopleFilmPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "charactersPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "filmsFilm", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromPeoplePlanetPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "residentsPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "homeworldPlanet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromPeopleSpeciesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "peoplePerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "speciesSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromPeopleStarshipsPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "pilotsPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "starshipsStarship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "RemoveFromPeopleVehiclesPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "pilotsPerson", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "vehiclesVehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "SpeciesPreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - } - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this species.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "SpeciesSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "averageHeight", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "SpeciesSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "SpeciesSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "SpeciesPreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "SpeciesfilmsFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "SpeciespeoplePerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "StarshipPreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "StarshipSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "StarshipSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "StarshipSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "StarshipPreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "StarshipfilmsFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "StarshippilotsPerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Subscription", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "Asset", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "AssetSubscriptionPayload", - "ofType": null - } - }, - { - "name": "Film", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "FilmSubscriptionPayload", - "ofType": null - } - }, - { - "name": "Person", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "PersonSubscriptionPayload", - "ofType": null - } - }, - { - "name": "Planet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "PlanetSubscriptionPayload", - "ofType": null - } - }, - { - "name": "Species", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "SpeciesSubscriptionPayload", - "ofType": null - } - }, - { - "name": "Starship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "StarshipSubscriptionPayload", - "ofType": null - } - }, - { - "name": "Vehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "VehicleSubscriptionPayload", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "fileName", - "description": "Original File Name", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "The File Handle", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "The Mime Type", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "The Size Of The File", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "The Url Of The Asset", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "UpdateAsset", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "UpdateFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "UpdatePerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residentsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "residents", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetresidentsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "UpdatePlanet", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "peopleIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "people", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciespeoplePerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "UpdateSpecies", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshippilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "UpdateStarship", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclefilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilotsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "pilots", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehiclepilotsPerson", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "UpdateVehicle", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "VehiclePreviousValues", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mutation_in", - "description": "The subscription event gets dispatched when it's listed in mutation_in", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains", - "description": "The subscription event gets only dispatched when one of the updated fields names is included in this list", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_every", - "description": "The subscription event gets only dispatched when all of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedFields_contains_some", - "description": "The subscription event gets only dispatched when some of the field names included in this list have been updated", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "node", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleSubscriptionFilterNode", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "VehicleSubscriptionFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "VehicleSubscriptionFilterNode", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "VehicleSubscriptionPayload", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "mutation", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "_ModelMutationType", - "ofType": null - } - } - }, - { - "name": "node", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - }, - { - "name": "updatedFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "previousValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "VehiclePreviousValues", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "director", - "description": "The name of the director of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "charactersIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "characters", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmcharactersPerson", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planetsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "planets", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmplanetsPlanet", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "VehiclefilmsFilm", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - "defaultValue": null - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "homeworldId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonhomeworldPlanet", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "filmsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "films", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonfilmsFilm", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "speciesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "species", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonspeciesSpecies", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starshipsIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "starships", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonstarshipsStarship", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehiclesIds", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "vehicles", - "description": "", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonvehiclesVehicle", - "ofType": null - } - } - }, - "defaultValue": null - } - ], - "name": "VehiclepilotsPerson", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "_ModelMutationType", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "CREATED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UPDATED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DELETED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Asset", - "description": "System model for Assets", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "fileName", - "description": "Original File Name", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "handle", - "description": "The File Handle", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "height", - "description": "The height of the file in case it is an image", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "mimeType", - "description": "The Mime Type", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "size", - "description": "The Size Of The File", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "url", - "description": "The Url Of The Asset", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "width", - "description": "The width of the file in case it is an image", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "fileName_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "fileName_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "handle_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "handle_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mimeType_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mimeType_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "size_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "size_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "url_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "url_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "width_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "width_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "AssetFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "AssetOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fileName_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fileName_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "handle_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "handle_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimeType_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mimeType_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "size_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "url_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "width_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "width_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "DateTime", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "SCALAR", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Film", - "description": "A Film is a single film.", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "characters", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "director", - "description": "The name of the director of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "episodeId", - "description": "The episode number of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "openingCrawl", - "description": "The opening paragraphs at the beginning of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "planets", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - } - }, - { - "name": "producers", - "description": "The names of the producers of this film.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "releaseDate", - "description": " The ISO 8601 date format of film release at original creator country.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - }, - { - "name": "species", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - } - }, - { - "name": "starships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - } - }, - { - "name": "title", - "description": "The title of this film", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "vehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - } - }, - { - "name": "_charactersMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_planetsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_speciesMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_starshipsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_vehiclesMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "director_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "director_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "episodeId_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "episodeId_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "openingCrawl_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "releaseDate_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "releaseDate_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "title_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "characters_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "planets_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "FilmFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "FilmOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "director_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "director_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodeId_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "episodeId_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openingCrawl_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openingCrawl_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "releaseDate_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "releaseDate_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Node", - "description": "An object with an ID", - "interfaces": null, - "enumValues": null, - "fields": [ - { - "name": "id", - "description": "The id of the object.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - } - ], - "kind": "INTERFACE", - "possibleTypes": [ - { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Film", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Person", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Species", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - }, - { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - ] - }, - { - "inputFields": null, - "name": "PERSON_EYE_COLOR", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUEGREY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HAZEL", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PINK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLD", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DARK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PERSON_GENDER", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MALE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FEMALE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HERMAPHRODITE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PERSON_HAIR_COLOR", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "interfaces": null, - "enumValues": [ - { - "name": "AUBURN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLONDE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PERSON_SKIN_COLOR", - "description": "The skin color of this person.", - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FAIR", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLD", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIGHT", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREENTAN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PALE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "METAL", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DARK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWNMOTTLE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MOTTLEDGREEN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "TAN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SILVER", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Person", - "description": "A Person is an individual person or character within the Star Wars universe", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "birthYear", - "description": "The birth year of the person, using the in-universe standard of BBY or ABY - Before the Battle of Yavin or After the Battle of Yavin. The Battle of Yavin is a battle that occurs at the end of Star Wars episode IV: A New Hope.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "eyeColor", - "description": "The eye color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have an eye.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_EYE_COLOR", - "ofType": null - } - } - } - }, - { - "name": "films", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - }, - { - "name": "gender", - "description": " The gender of this person. Will be \"UNKNOWN\" if not known or null if the person does not have a gender.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - }, - { - "name": "hairColor", - "description": "The hair color of this person. Will be \"UNKNOWN\" if not known or null if the person does not have hair.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_HAIR_COLOR", - "ofType": null - } - } - } - }, - { - "name": "height", - "description": "The height of the person in centimeters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "homeworld", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "mass", - "description": "The mass of the person in kilograms.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this person.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "skinColor", - "description": "The skin color of this person.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_SKIN_COLOR", - "ofType": null - } - } - } - }, - { - "name": "species", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - } - }, - { - "name": "starships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "vehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - } - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_speciesMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_starshipsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_vehiclesMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "birthYear_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "birthYear_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender", - "description": "", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gender_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gender_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "PERSON_GENDER", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "height_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "height_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mass_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mass_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "homeworld", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "species_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "starships_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "vehicles_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "PersonFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PersonOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "birthYear_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "birthYear_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gender_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gender_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "height_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mass_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Planet", - "description": "A Planet is a large mass, planet or planetoid in the Star Wars Universe, at the time of 0 ABY.", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "climate", - "description": "The climate of this planet.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "diameter", - "description": "The diameter of this planet in kilometers.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "films", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - }, - { - "name": "gravity", - "description": "A number denoting the gravity of this planet, where \"1\" is normal or 1 standard G. \"2\" is twice or 2 standard Gs. \"0.5\" is half or 0.5 standard Gs.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "name", - "description": "The name of the planet", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "orbitalPeriod", - "description": "The number of standard days it takes for this planet to complete a single orbit of its local star.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "population", - "description": "The average population of sentient beings inhabiting this planet.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "residents", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - }, - { - "name": "rotationPeriod", - "description": "The number of standard hours it takes for this planet to complete a single rotation on its axis.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "surfaceWater", - "description": "The percentage of the planet surface that is naturally occurring water or bodies of water.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "terrain", - "description": "The terrain of this planet.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_residentsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "diameter_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "diameter_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "gravity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "gravity_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orbitalPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "population_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "population_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "rotationPeriod_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "surfaceWater_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "residents_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "PlanetFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "PlanetOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diameter_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "diameter_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gravity_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gravity_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orbitalPeriod_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "orbitalPeriod_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "population_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "population_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rotationPeriod_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "rotationPeriod_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "surfaceWater_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "surfaceWater_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Query", - "description": null, - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "allAssets", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "AssetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - } - } - } - }, - { - "name": "allFilms", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - } - }, - { - "name": "allPersons", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - } - }, - { - "name": "allPlanets", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - } - } - } - }, - { - "name": "allSpecies", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - } - } - } - }, - { - "name": "allStarships", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - } - } - } - }, - { - "name": "allVehicles", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - } - } - } - }, - { - "name": "_allAssetsMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "AssetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "AssetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_allFilmsMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_allPersonsMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_allPlanetsMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PlanetFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PlanetOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_allSpeciesMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "SpeciesOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_allStarshipsMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "StarshipOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_allVehiclesMeta", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "VehicleOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "Asset", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Asset", - "ofType": null - } - }, - { - "name": "Film", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "title", - "description": "The title of this film", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - }, - { - "name": "Person", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this person.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - }, - { - "name": "Planet", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of the planet", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Planet", - "ofType": null - } - }, - { - "name": "Species", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this species.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Species", - "ofType": null - } - }, - { - "name": "Starship", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Starship", - "ofType": null - } - }, - { - "name": "Vehicle", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "OBJECT", - "name": "Vehicle", - "ofType": null - } - }, - { - "name": "node", - "description": "Fetches an object given its ID", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "id", - "description": "The ID of an object", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - }, - "defaultValue": null - } - ], - "type": { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "SPECIES_EYE_COLOR", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "interfaces": null, - "enumValues": [ - { - "name": "AMBER", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLUE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLD", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HAZEL", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INDIGO", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PINK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SILVER", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GOLDEN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "SPECIES_HAIR_COLOR", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "interfaces": null, - "enumValues": [ - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLONDE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "SPECIES_SKIN_COLOR", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "interfaces": null, - "enumValues": [ - { - "name": "BLUE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BROWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "CAUCASIAN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "DARK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREEN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "GREY", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MAGENTA", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ORANGE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PALE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PALEPINK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PEACH", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PINK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "PURPLE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "RED", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "TAN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNKNOWN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "WHITE", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "YELLOW", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "BLACK", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ASIAN", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "HISPANIC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Species", - "description": "A Species is a type of person or character within the Star Wars Universe.", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "averageHeight", - "description": "The average height of this species in centimeters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "averageLifespan", - "description": "The average lifespan of this species in years.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "classification", - "description": "The classification of this species, such as \"mammal\" or \"reptile\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "designation", - "description": "The designation of this species, such as \"sentient\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "eyeColor", - "description": "The eye colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have eyes.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_EYE_COLOR", - "ofType": null - } - } - } - }, - { - "name": "films", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - }, - { - "name": "hairColor", - "description": "The hair colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have hairs.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_HAIR_COLOR", - "ofType": null - } - } - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "language", - "description": "The language commonly spoken by this species.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this species.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "people", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - }, - { - "name": "skinColor", - "description": "The skin colors for this species, \"UNKNOWN\" if not known, null if this species does not typically have a skin.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "SPECIES_SKIN_COLOR", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_peopleMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "SpeciesFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageHeight_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageHeight_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "averageLifespan_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "classification_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "classification_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "designation_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "designation_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "language_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "language_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "people_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "SpeciesFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "SpeciesOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "averageHeight_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageHeight_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageLifespan_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "averageLifespan_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "classification_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "classification_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "designation_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "designation_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "language_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Starship", - "description": "A Starship is a single transport craft that has hyperdrive capability.", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this starship can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "class", - "description": "The class of this starship, such as \"Starfighter\" or \"Deep Space Mobile Battlestation\"", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "consumables", - "description": "The maximum length of time that this starship can provide consumables for its entire crew without having to resupply.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "costInCredits", - "description": " The cost of this starship new, in galactic credits.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this starship.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "films", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - }, - { - "name": "hyperdriveRating", - "description": "The class of this starships hyperdrive.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "length", - "description": "The length of this starship in meters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "manufacturer", - "description": "The manufacturer of this starship.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "maxAtmospheringSpeed", - "description": " The maximum speed of this starship in the atmosphere. null if this starship is incapable of atmospheric flight.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "mglt", - "description": "The Maximum number of Megalights this starship can travel in a standard hour. A \"Megalight\" is a standard unit of distance and has never been defined before within the Star Wars universe.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this starship. The common name, such as \"Death Star\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "passengers", - "description": " The number of non-essential people this starship can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "pilots", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_pilotsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "StarshipFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "hyperdriveRating_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "mglt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "mglt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "StarshipFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "StarshipOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "cargoCapacity_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cargoCapacity_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hyperdriveRating_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hyperdriveRating_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mglt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mglt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Vehicle", - "description": "A Vehicle is a single transport craft that does not have hyperdrive capability.", - "interfaces": [ - { - "kind": "INTERFACE", - "name": "Node", - "ofType": null - } - ], - "enumValues": null, - "fields": [ - { - "name": "cargoCapacity", - "description": "The maximum number of kilograms that this vehicle can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "class", - "description": " The class of this vehicle, such as \"Wheeled\" or \"Repulsorcraft\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "consumables", - "description": "The maximum length of time that this vehicle can provide consumables for its entire crew without having to resupply.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "costInCredits", - "description": "The cost of this vehicle new, in Galactic Credits.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "createdAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "crew", - "description": "The number of personnel needed to run or pilot this vehicle.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "films", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Film", - "ofType": null - } - } - } - }, - { - "name": "id", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - { - "name": "isPublished", - "description": "indicates if the record is published", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "length", - "description": " The length of this vehicle in meters.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - }, - { - "name": "manufacturer", - "description": "The manufacturer of this vehicle.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - } - }, - { - "name": "maxAtmospheringSpeed", - "description": "The maximum speed of this vehicle in the atmosphere.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "model", - "description": "The model or official name of this vehicle. Such as \"All-Terrain Attack Transport\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "name", - "description": "The name of this vehicle. The common name, such as \"Sand Crawler\" or \"Speeder bike\".", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "passengers", - "description": "The number of non-essential people this vehicle can transport.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - }, - { - "name": "pilots", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "Person", - "ofType": null - } - } - } - }, - { - "name": "updatedAt", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - { - "name": "_filmsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "FilmOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - }, - { - "name": "_pilotsMeta", - "description": "Meta information about the query.", - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "filter", - "description": "", - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "orderBy", - "description": null, - "type": { - "kind": "ENUM", - "name": "PersonOrderBy", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "skip", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "before", - "description": null, - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "_QueryMeta", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": [ - { - "name": "AND", - "description": "Logical AND on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "OR", - "description": "Logical OR on all given filters.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "INPUT_OBJECT", - "name": "VehicleFilter", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "cargoCapacity_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "class_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "class_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "consumables_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "consumables_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "costInCredits_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "costInCredits_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "createdAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "createdAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "crew_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "crew_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id", - "description": "", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "id_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "id_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "ID", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "isPublished_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "length_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "length_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Float", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "maxAtmospheringSpeed_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "model_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "model_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name", - "description": "", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "name_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_contains", - "description": "All values containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_contains", - "description": "All values not containing the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_starts_with", - "description": "All values starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_starts_with", - "description": "All values not starting with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_ends_with", - "description": "All values ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "name_not_ends_with", - "description": "All values not ending with the given string.", - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers", - "description": "", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "passengers_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "passengers_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt", - "description": "", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_not", - "description": "All values that are not equal to given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_in", - "description": "All values that are contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_not_in", - "description": "All values that are not contained in given list.", - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - } - } - }, - "defaultValue": null - }, - { - "name": "updatedAt_lt", - "description": "All values less than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_lte", - "description": "All values less than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gt", - "description": "All values greater than the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "updatedAt_gte", - "description": "All values greater than or equal the given value.", - "type": { - "kind": "SCALAR", - "name": "DateTime", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "films_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "FilmFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_every", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_some", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - }, - { - "name": "pilots_none", - "description": null, - "type": { - "kind": "INPUT_OBJECT", - "name": "PersonFilter", - "ofType": null - }, - "defaultValue": null - } - ], - "name": "VehicleFilter", - "description": null, - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "INPUT_OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "VehicleOrderBy", - "description": null, - "interfaces": null, - "enumValues": [ - { - "name": "cargoCapacity_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cargoCapacity_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "class_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "consumables_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "costInCredits_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "createdAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "crew_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "id_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPublished_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "length_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "maxAtmospheringSpeed_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "model_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "passengers_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_ASC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "updatedAt_DESC", - "description": null, - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "_QueryMeta", - "description": "Meta information about the query.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "count", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Int", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL’s execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "name", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "description", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "locations", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__DirectiveLocation", - "ofType": null - } - } - } - } - }, - { - "name": "args", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - } - }, - { - "name": "onOperation", - "description": null, - "isDeprecated": true, - "deprecationReason": "Use `locations`.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "onFragment", - "description": null, - "isDeprecated": true, - "deprecationReason": "Use `locations`.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "onField", - "description": null, - "isDeprecated": true, - "deprecationReason": "Use `locations`.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "INPUT_OBJECT", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "name", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "description", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "isDeprecated", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "deprecationReason", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "name", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "description", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "args", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - } - }, - { - "name": "type", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - { - "name": "isDeprecated", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - } - } - }, - { - "name": "deprecationReason", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "name", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - }, - { - "name": "description", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "type", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "types", - "description": "A list of all types supported by this server.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - } - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Directive", - "ofType": null - } - } - } - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "interfaces": [], - "enumValues": null, - "fields": [ - { - "name": "kind", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "ENUM", - "name": "__TypeKind", - "ofType": null - } - } - }, - { - "name": "name", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "description", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "SCALAR", - "name": "String", - "ofType": null - } - }, - { - "name": "fields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Field", - "ofType": null - } - } - } - }, - { - "name": "interfaces", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - }, - { - "name": "possibleTypes", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - } - }, - { - "name": "enumValues", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { - "kind": "SCALAR", - "name": "Boolean", - "ofType": null - }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__EnumValue", - "ofType": null - } - } - } - }, - { - "name": "inputFields", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "OBJECT", - "name": "__InputValue", - "ofType": null - } - } - } - }, - { - "name": "ofType", - "description": null, - "isDeprecated": false, - "deprecationReason": null, - "args": [], - "type": { - "kind": "OBJECT", - "name": "__Type", - "ofType": null - } - } - ], - "kind": "OBJECT", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "fields": null, - "kind": "ENUM", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "SCALAR", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point).", - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "SCALAR", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "SCALAR", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "SCALAR", - "possibleTypes": null - }, - { - "inputFields": null, - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "interfaces": null, - "enumValues": null, - "fields": null, - "kind": "SCALAR", - "possibleTypes": null - } - ] - } -} \ No newline at end of file diff --git a/pkg/lexer/fixtures/introspection_lexed.golden b/pkg/lexer/fixtures/introspection_lexed.golden deleted file mode 100644 index f79b06284..000000000 --- a/pkg/lexer/fixtures/introspection_lexed.golden +++ /dev/null @@ -1,1952 +0,0 @@ -[ - { - "Keyword": 1, - "Literal": { - "Start": 0, - "End": 5 - }, - "TextPosition": { - "LineStart": 1, - "LineEnd": 1, - "CharStart": 1, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 6, - "End": 24 - }, - "TextPosition": { - "LineStart": 1, - "LineEnd": 1, - "CharStart": 7, - "CharEnd": 25 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 25, - "End": 26 - }, - "TextPosition": { - "LineStart": 1, - "LineEnd": 1, - "CharStart": 26, - "CharEnd": 27 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 29, - "End": 37 - }, - "TextPosition": { - "LineStart": 2, - "LineEnd": 2, - "CharStart": 3, - "CharEnd": 11 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 38, - "End": 39 - }, - "TextPosition": { - "LineStart": 2, - "LineEnd": 2, - "CharStart": 12, - "CharEnd": 13 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 44, - "End": 53 - }, - "TextPosition": { - "LineStart": 3, - "LineEnd": 3, - "CharStart": 5, - "CharEnd": 14 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 54, - "End": 55 - }, - "TextPosition": { - "LineStart": 3, - "LineEnd": 3, - "CharStart": 15, - "CharEnd": 16 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 62, - "End": 66 - }, - "TextPosition": { - "LineStart": 4, - "LineEnd": 4, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 71, - "End": 72 - }, - "TextPosition": { - "LineStart": 5, - "LineEnd": 5, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 77, - "End": 89 - }, - "TextPosition": { - "LineStart": 6, - "LineEnd": 6, - "CharStart": 5, - "CharEnd": 17 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 90, - "End": 91 - }, - "TextPosition": { - "LineStart": 6, - "LineEnd": 6, - "CharStart": 18, - "CharEnd": 19 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 98, - "End": 102 - }, - "TextPosition": { - "LineStart": 7, - "LineEnd": 7, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 107, - "End": 108 - }, - "TextPosition": { - "LineStart": 8, - "LineEnd": 8, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 113, - "End": 129 - }, - "TextPosition": { - "LineStart": 9, - "LineEnd": 9, - "CharStart": 5, - "CharEnd": 21 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 130, - "End": 131 - }, - "TextPosition": { - "LineStart": 9, - "LineEnd": 9, - "CharStart": 22, - "CharEnd": 23 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 138, - "End": 142 - }, - "TextPosition": { - "LineStart": 10, - "LineEnd": 10, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 147, - "End": 148 - }, - "TextPosition": { - "LineStart": 11, - "LineEnd": 11, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 153, - "End": 158 - }, - "TextPosition": { - "LineStart": 12, - "LineEnd": 12, - "CharStart": 5, - "CharEnd": 10 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 159, - "End": 160 - }, - "TextPosition": { - "LineStart": 12, - "LineEnd": 12, - "CharStart": 11, - "CharEnd": 12 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 167, - "End": 170 - }, - "TextPosition": { - "LineStart": 13, - "LineEnd": 13, - "CharStart": 7, - "CharEnd": 10 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 170, - "End": 178 - }, - "TextPosition": { - "LineStart": 13, - "LineEnd": 13, - "CharStart": 10, - "CharEnd": 18 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 183, - "End": 184 - }, - "TextPosition": { - "LineStart": 14, - "LineEnd": 14, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 189, - "End": 199 - }, - "TextPosition": { - "LineStart": 15, - "LineEnd": 15, - "CharStart": 5, - "CharEnd": 15 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 200, - "End": 201 - }, - "TextPosition": { - "LineStart": 15, - "LineEnd": 15, - "CharStart": 16, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 208, - "End": 212 - }, - "TextPosition": { - "LineStart": 16, - "LineEnd": 16, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 219, - "End": 230 - }, - "TextPosition": { - "LineStart": 17, - "LineEnd": 17, - "CharStart": 7, - "CharEnd": 18 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 237, - "End": 246 - }, - "TextPosition": { - "LineStart": 18, - "LineEnd": 18, - "CharStart": 7, - "CharEnd": 16 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 253, - "End": 257 - }, - "TextPosition": { - "LineStart": 19, - "LineEnd": 19, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 258, - "End": 259 - }, - "TextPosition": { - "LineStart": 19, - "LineEnd": 19, - "CharStart": 12, - "CharEnd": 13 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 268, - "End": 271 - }, - "TextPosition": { - "LineStart": 20, - "LineEnd": 20, - "CharStart": 9, - "CharEnd": 12 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 271, - "End": 281 - }, - "TextPosition": { - "LineStart": 20, - "LineEnd": 20, - "CharStart": 12, - "CharEnd": 22 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 288, - "End": 289 - }, - "TextPosition": { - "LineStart": 21, - "LineEnd": 21, - "CharStart": 7, - "CharEnd": 8 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 294, - "End": 295 - }, - "TextPosition": { - "LineStart": 22, - "LineEnd": 22, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 298, - "End": 299 - }, - "TextPosition": { - "LineStart": 23, - "LineEnd": 23, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 300, - "End": 301 - }, - "TextPosition": { - "LineStart": 24, - "LineEnd": 24, - "CharStart": 1, - "CharEnd": 2 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 303, - "End": 311 - }, - "TextPosition": { - "LineStart": 26, - "LineEnd": 26, - "CharStart": 1, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 312, - "End": 320 - }, - "TextPosition": { - "LineStart": 26, - "LineEnd": 26, - "CharStart": 10, - "CharEnd": 18 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 321, - "End": 323 - }, - "TextPosition": { - "LineStart": 26, - "LineEnd": 26, - "CharStart": 19, - "CharEnd": 21 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 324, - "End": 330 - }, - "TextPosition": { - "LineStart": 26, - "LineEnd": 26, - "CharStart": 22, - "CharEnd": 28 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 331, - "End": 332 - }, - "TextPosition": { - "LineStart": 26, - "LineEnd": 26, - "CharStart": 29, - "CharEnd": 30 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 335, - "End": 339 - }, - "TextPosition": { - "LineStart": 27, - "LineEnd": 27, - "CharStart": 3, - "CharEnd": 7 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 342, - "End": 346 - }, - "TextPosition": { - "LineStart": 28, - "LineEnd": 28, - "CharStart": 3, - "CharEnd": 7 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 349, - "End": 360 - }, - "TextPosition": { - "LineStart": 29, - "LineEnd": 29, - "CharStart": 3, - "CharEnd": 14 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 363, - "End": 369 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 3, - "CharEnd": 9 - } - }, - { - "Keyword": 24, - "Literal": { - "Start": 369, - "End": 370 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 9, - "CharEnd": 10 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 370, - "End": 387 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 10, - "CharEnd": 27 - } - }, - { - "Keyword": 4, - "Literal": { - "Start": 387, - "End": 388 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 27, - "CharEnd": 28 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 389, - "End": 393 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 29, - "CharEnd": 33 - } - }, - { - "Keyword": 25, - "Literal": { - "Start": 393, - "End": 394 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 33, - "CharEnd": 34 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 395, - "End": 396 - }, - "TextPosition": { - "LineStart": 30, - "LineEnd": 30, - "CharStart": 35, - "CharEnd": 36 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 401, - "End": 405 - }, - "TextPosition": { - "LineStart": 31, - "LineEnd": 31, - "CharStart": 5, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 410, - "End": 421 - }, - "TextPosition": { - "LineStart": 32, - "LineEnd": 32, - "CharStart": 5, - "CharEnd": 16 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 426, - "End": 430 - }, - "TextPosition": { - "LineStart": 33, - "LineEnd": 33, - "CharStart": 5, - "CharEnd": 9 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 431, - "End": 432 - }, - "TextPosition": { - "LineStart": 33, - "LineEnd": 33, - "CharStart": 10, - "CharEnd": 11 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 439, - "End": 442 - }, - "TextPosition": { - "LineStart": 34, - "LineEnd": 34, - "CharStart": 7, - "CharEnd": 10 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 442, - "End": 452 - }, - "TextPosition": { - "LineStart": 34, - "LineEnd": 34, - "CharStart": 10, - "CharEnd": 20 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 457, - "End": 458 - }, - "TextPosition": { - "LineStart": 35, - "LineEnd": 35, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 463, - "End": 467 - }, - "TextPosition": { - "LineStart": 36, - "LineEnd": 36, - "CharStart": 5, - "CharEnd": 9 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 468, - "End": 469 - }, - "TextPosition": { - "LineStart": 36, - "LineEnd": 36, - "CharStart": 10, - "CharEnd": 11 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 476, - "End": 479 - }, - "TextPosition": { - "LineStart": 37, - "LineEnd": 37, - "CharStart": 7, - "CharEnd": 10 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 479, - "End": 486 - }, - "TextPosition": { - "LineStart": 37, - "LineEnd": 37, - "CharStart": 10, - "CharEnd": 17 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 491, - "End": 492 - }, - "TextPosition": { - "LineStart": 38, - "LineEnd": 38, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 497, - "End": 509 - }, - "TextPosition": { - "LineStart": 39, - "LineEnd": 39, - "CharStart": 5, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 514, - "End": 531 - }, - "TextPosition": { - "LineStart": 40, - "LineEnd": 40, - "CharStart": 5, - "CharEnd": 22 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 534, - "End": 535 - }, - "TextPosition": { - "LineStart": 41, - "LineEnd": 41, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 538, - "End": 549 - }, - "TextPosition": { - "LineStart": 42, - "LineEnd": 42, - "CharStart": 3, - "CharEnd": 14 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 550, - "End": 551 - }, - "TextPosition": { - "LineStart": 42, - "LineEnd": 42, - "CharStart": 15, - "CharEnd": 16 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 556, - "End": 559 - }, - "TextPosition": { - "LineStart": 43, - "LineEnd": 43, - "CharStart": 5, - "CharEnd": 8 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 559, - "End": 569 - }, - "TextPosition": { - "LineStart": 43, - "LineEnd": 43, - "CharStart": 8, - "CharEnd": 18 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 572, - "End": 573 - }, - "TextPosition": { - "LineStart": 44, - "LineEnd": 44, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 576, - "End": 586 - }, - "TextPosition": { - "LineStart": 45, - "LineEnd": 45, - "CharStart": 3, - "CharEnd": 13 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 587, - "End": 588 - }, - "TextPosition": { - "LineStart": 45, - "LineEnd": 45, - "CharStart": 14, - "CharEnd": 15 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 593, - "End": 596 - }, - "TextPosition": { - "LineStart": 46, - "LineEnd": 46, - "CharStart": 5, - "CharEnd": 8 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 596, - "End": 603 - }, - "TextPosition": { - "LineStart": 46, - "LineEnd": 46, - "CharStart": 8, - "CharEnd": 15 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 606, - "End": 607 - }, - "TextPosition": { - "LineStart": 47, - "LineEnd": 47, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 610, - "End": 620 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 3, - "CharEnd": 13 - } - }, - { - "Keyword": 24, - "Literal": { - "Start": 620, - "End": 621 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 13, - "CharEnd": 14 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 621, - "End": 638 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 14, - "CharEnd": 31 - } - }, - { - "Keyword": 4, - "Literal": { - "Start": 638, - "End": 639 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 31, - "CharEnd": 32 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 640, - "End": 644 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 33, - "CharEnd": 37 - } - }, - { - "Keyword": 25, - "Literal": { - "Start": 644, - "End": 645 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 37, - "CharEnd": 38 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 646, - "End": 647 - }, - "TextPosition": { - "LineStart": 48, - "LineEnd": 48, - "CharStart": 39, - "CharEnd": 40 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 652, - "End": 656 - }, - "TextPosition": { - "LineStart": 49, - "LineEnd": 49, - "CharStart": 5, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 661, - "End": 672 - }, - "TextPosition": { - "LineStart": 50, - "LineEnd": 50, - "CharStart": 5, - "CharEnd": 16 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 677, - "End": 689 - }, - "TextPosition": { - "LineStart": 51, - "LineEnd": 51, - "CharStart": 5, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 694, - "End": 711 - }, - "TextPosition": { - "LineStart": 52, - "LineEnd": 52, - "CharStart": 5, - "CharEnd": 22 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 714, - "End": 715 - }, - "TextPosition": { - "LineStart": 53, - "LineEnd": 53, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 718, - "End": 731 - }, - "TextPosition": { - "LineStart": 54, - "LineEnd": 54, - "CharStart": 3, - "CharEnd": 16 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 732, - "End": 733 - }, - "TextPosition": { - "LineStart": 54, - "LineEnd": 54, - "CharStart": 17, - "CharEnd": 18 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 738, - "End": 741 - }, - "TextPosition": { - "LineStart": 55, - "LineEnd": 55, - "CharStart": 5, - "CharEnd": 8 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 741, - "End": 748 - }, - "TextPosition": { - "LineStart": 55, - "LineEnd": 55, - "CharStart": 8, - "CharEnd": 15 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 751, - "End": 752 - }, - "TextPosition": { - "LineStart": 56, - "LineEnd": 56, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 753, - "End": 754 - }, - "TextPosition": { - "LineStart": 57, - "LineEnd": 57, - "CharStart": 1, - "CharEnd": 2 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 756, - "End": 764 - }, - "TextPosition": { - "LineStart": 59, - "LineEnd": 59, - "CharStart": 1, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 765, - "End": 775 - }, - "TextPosition": { - "LineStart": 59, - "LineEnd": 59, - "CharStart": 10, - "CharEnd": 20 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 776, - "End": 778 - }, - "TextPosition": { - "LineStart": 59, - "LineEnd": 59, - "CharStart": 21, - "CharEnd": 23 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 779, - "End": 791 - }, - "TextPosition": { - "LineStart": 59, - "LineEnd": 59, - "CharStart": 24, - "CharEnd": 36 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 792, - "End": 793 - }, - "TextPosition": { - "LineStart": 59, - "LineEnd": 59, - "CharStart": 37, - "CharEnd": 38 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 796, - "End": 800 - }, - "TextPosition": { - "LineStart": 60, - "LineEnd": 60, - "CharStart": 3, - "CharEnd": 7 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 803, - "End": 814 - }, - "TextPosition": { - "LineStart": 61, - "LineEnd": 61, - "CharStart": 3, - "CharEnd": 14 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 817, - "End": 821 - }, - "TextPosition": { - "LineStart": 62, - "LineEnd": 62, - "CharStart": 3, - "CharEnd": 7 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 822, - "End": 823 - }, - "TextPosition": { - "LineStart": 62, - "LineEnd": 62, - "CharStart": 8, - "CharEnd": 9 - } - }, - { - "Keyword": 12, - "Literal": { - "Start": 828, - "End": 831 - }, - "TextPosition": { - "LineStart": 63, - "LineEnd": 63, - "CharStart": 5, - "CharEnd": 8 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 831, - "End": 838 - }, - "TextPosition": { - "LineStart": 63, - "LineEnd": 63, - "CharStart": 8, - "CharEnd": 15 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 841, - "End": 842 - }, - "TextPosition": { - "LineStart": 64, - "LineEnd": 64, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 845, - "End": 857 - }, - "TextPosition": { - "LineStart": 65, - "LineEnd": 65, - "CharStart": 3, - "CharEnd": 15 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 858, - "End": 859 - }, - "TextPosition": { - "LineStart": 66, - "LineEnd": 66, - "CharStart": 1, - "CharEnd": 2 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 861, - "End": 869 - }, - "TextPosition": { - "LineStart": 68, - "LineEnd": 68, - "CharStart": 1, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 870, - "End": 877 - }, - "TextPosition": { - "LineStart": 68, - "LineEnd": 68, - "CharStart": 10, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 878, - "End": 880 - }, - "TextPosition": { - "LineStart": 68, - "LineEnd": 68, - "CharStart": 18, - "CharEnd": 20 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 881, - "End": 887 - }, - "TextPosition": { - "LineStart": 68, - "LineEnd": 68, - "CharStart": 21, - "CharEnd": 27 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 888, - "End": 889 - }, - "TextPosition": { - "LineStart": 68, - "LineEnd": 68, - "CharStart": 28, - "CharEnd": 29 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 892, - "End": 896 - }, - "TextPosition": { - "LineStart": 69, - "LineEnd": 69, - "CharStart": 3, - "CharEnd": 7 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 899, - "End": 903 - }, - "TextPosition": { - "LineStart": 70, - "LineEnd": 70, - "CharStart": 3, - "CharEnd": 7 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 906, - "End": 912 - }, - "TextPosition": { - "LineStart": 71, - "LineEnd": 71, - "CharStart": 3, - "CharEnd": 9 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 913, - "End": 914 - }, - "TextPosition": { - "LineStart": 71, - "LineEnd": 71, - "CharStart": 10, - "CharEnd": 11 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 919, - "End": 923 - }, - "TextPosition": { - "LineStart": 72, - "LineEnd": 72, - "CharStart": 5, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 928, - "End": 932 - }, - "TextPosition": { - "LineStart": 73, - "LineEnd": 73, - "CharStart": 5, - "CharEnd": 9 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 937, - "End": 943 - }, - "TextPosition": { - "LineStart": 74, - "LineEnd": 74, - "CharStart": 5, - "CharEnd": 11 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 944, - "End": 945 - }, - "TextPosition": { - "LineStart": 74, - "LineEnd": 74, - "CharStart": 12, - "CharEnd": 13 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 952, - "End": 956 - }, - "TextPosition": { - "LineStart": 75, - "LineEnd": 75, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 963, - "End": 967 - }, - "TextPosition": { - "LineStart": 76, - "LineEnd": 76, - "CharStart": 7, - "CharEnd": 11 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 974, - "End": 980 - }, - "TextPosition": { - "LineStart": 77, - "LineEnd": 77, - "CharStart": 7, - "CharEnd": 13 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 981, - "End": 982 - }, - "TextPosition": { - "LineStart": 77, - "LineEnd": 77, - "CharStart": 14, - "CharEnd": 15 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 991, - "End": 995 - }, - "TextPosition": { - "LineStart": 78, - "LineEnd": 78, - "CharStart": 9, - "CharEnd": 13 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1004, - "End": 1008 - }, - "TextPosition": { - "LineStart": 79, - "LineEnd": 79, - "CharStart": 9, - "CharEnd": 13 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1017, - "End": 1023 - }, - "TextPosition": { - "LineStart": 80, - "LineEnd": 80, - "CharStart": 9, - "CharEnd": 15 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 1024, - "End": 1025 - }, - "TextPosition": { - "LineStart": 80, - "LineEnd": 80, - "CharStart": 16, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1036, - "End": 1040 - }, - "TextPosition": { - "LineStart": 81, - "LineEnd": 81, - "CharStart": 11, - "CharEnd": 15 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1051, - "End": 1055 - }, - "TextPosition": { - "LineStart": 82, - "LineEnd": 82, - "CharStart": 11, - "CharEnd": 15 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1066, - "End": 1072 - }, - "TextPosition": { - "LineStart": 83, - "LineEnd": 83, - "CharStart": 11, - "CharEnd": 17 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 1073, - "End": 1074 - }, - "TextPosition": { - "LineStart": 83, - "LineEnd": 83, - "CharStart": 18, - "CharEnd": 19 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1087, - "End": 1091 - }, - "TextPosition": { - "LineStart": 84, - "LineEnd": 84, - "CharStart": 13, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1104, - "End": 1108 - }, - "TextPosition": { - "LineStart": 85, - "LineEnd": 85, - "CharStart": 13, - "CharEnd": 17 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1121, - "End": 1127 - }, - "TextPosition": { - "LineStart": 86, - "LineEnd": 86, - "CharStart": 13, - "CharEnd": 19 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 1128, - "End": 1129 - }, - "TextPosition": { - "LineStart": 86, - "LineEnd": 86, - "CharStart": 20, - "CharEnd": 21 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1144, - "End": 1148 - }, - "TextPosition": { - "LineStart": 87, - "LineEnd": 87, - "CharStart": 15, - "CharEnd": 19 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1163, - "End": 1167 - }, - "TextPosition": { - "LineStart": 88, - "LineEnd": 88, - "CharStart": 15, - "CharEnd": 19 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1182, - "End": 1188 - }, - "TextPosition": { - "LineStart": 89, - "LineEnd": 89, - "CharStart": 15, - "CharEnd": 21 - } - }, - { - "Keyword": 28, - "Literal": { - "Start": 1189, - "End": 1190 - }, - "TextPosition": { - "LineStart": 89, - "LineEnd": 89, - "CharStart": 22, - "CharEnd": 23 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1207, - "End": 1211 - }, - "TextPosition": { - "LineStart": 90, - "LineEnd": 90, - "CharStart": 17, - "CharEnd": 21 - } - }, - { - "Keyword": 1, - "Literal": { - "Start": 1228, - "End": 1232 - }, - "TextPosition": { - "LineStart": 91, - "LineEnd": 91, - "CharStart": 17, - "CharEnd": 21 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1247, - "End": 1248 - }, - "TextPosition": { - "LineStart": 92, - "LineEnd": 92, - "CharStart": 15, - "CharEnd": 16 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1261, - "End": 1262 - }, - "TextPosition": { - "LineStart": 93, - "LineEnd": 93, - "CharStart": 13, - "CharEnd": 14 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1273, - "End": 1274 - }, - "TextPosition": { - "LineStart": 94, - "LineEnd": 94, - "CharStart": 11, - "CharEnd": 12 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1283, - "End": 1284 - }, - "TextPosition": { - "LineStart": 95, - "LineEnd": 95, - "CharStart": 9, - "CharEnd": 10 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1291, - "End": 1292 - }, - "TextPosition": { - "LineStart": 96, - "LineEnd": 96, - "CharStart": 7, - "CharEnd": 8 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1297, - "End": 1298 - }, - "TextPosition": { - "LineStart": 97, - "LineEnd": 97, - "CharStart": 5, - "CharEnd": 6 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1301, - "End": 1302 - }, - "TextPosition": { - "LineStart": 98, - "LineEnd": 98, - "CharStart": 3, - "CharEnd": 4 - } - }, - { - "Keyword": 29, - "Literal": { - "Start": 1303, - "End": 1304 - }, - "TextPosition": { - "LineStart": 99, - "LineEnd": 99, - "CharStart": 1, - "CharEnd": 2 - } - } -] \ No newline at end of file diff --git a/pkg/lexer/identkeyword/identkeyword.go b/pkg/lexer/identkeyword/identkeyword.go deleted file mode 100644 index 393c12060..000000000 --- a/pkg/lexer/identkeyword/identkeyword.go +++ /dev/null @@ -1,105 +0,0 @@ -//go:generate stringer -type=IdentKeyword - -// Package identkeyword contains all possible keywords for GraphQL identifiers -package identkeyword - -type IdentKeyword int - -const ( - UNDEFINED IdentKeyword = iota - ON - TRUE - FALSE - NULL - QUERY - MUTATION - SUBSCRIPTION - FRAGMENT - IMPLEMENTS - SCHEMA - SCALAR - TYPE - INTERFACE - UNION - ENUM - INPUT - DIRECTIVE - EXTEND - REPEATABLE -) - -func KeywordFromLiteral(literal []byte) IdentKeyword { - switch len(literal) { - case 2: - if literal[0] == 'o' && literal[1] == 'n' { - return ON - } - case 4: - if literal[0] == 'n' && literal[1] == 'u' && literal[2] == 'l' && literal[3] == 'l' { - return NULL - } - if literal[0] == 'e' && literal[1] == 'n' && literal[2] == 'u' && literal[3] == 'm' { - return ENUM - } - if literal[0] == 't' { - if literal[1] == 'r' && literal[2] == 'u' && literal[3] == 'e' { - return TRUE - } - if literal[1] == 'y' && literal[2] == 'p' && literal[3] == 'e' { - return TYPE - } - } - case 5: - if literal[0] == 'f' && literal[1] == 'a' && literal[2] == 'l' && literal[3] == 's' && literal[4] == 'e' { - return FALSE - } - if literal[0] == 'u' && literal[1] == 'n' && literal[2] == 'i' && literal[3] == 'o' && literal[4] == 'n' { - return UNION - } - if literal[0] == 'q' && literal[1] == 'u' && literal[2] == 'e' && literal[3] == 'r' && literal[4] == 'y' { - return QUERY - } - if literal[0] == 'i' && literal[1] == 'n' && literal[2] == 'p' && literal[3] == 'u' && literal[4] == 't' { - return INPUT - } - case 6: - if literal[0] == 'e' && literal[1] == 'x' && literal[2] == 't' && literal[3] == 'e' && literal[4] == 'n' && literal[5] == 'd' { - return EXTEND - } - if literal[0] == 's' { - if literal[1] == 'c' && literal[2] == 'h' && literal[3] == 'e' && literal[4] == 'm' && literal[5] == 'a' { - return SCHEMA - } - if literal[1] == 'c' && literal[2] == 'a' && literal[3] == 'l' && literal[4] == 'a' && literal[5] == 'r' { - return SCALAR - } - } - case 8: - if literal[0] == 'm' && literal[1] == 'u' && literal[2] == 't' && literal[3] == 'a' && literal[4] == 't' && literal[5] == 'i' && literal[6] == 'o' && literal[7] == 'n' { - return MUTATION - } - if literal[0] == 'f' && literal[1] == 'r' && literal[2] == 'a' && literal[3] == 'g' && literal[4] == 'm' && literal[5] == 'e' && literal[6] == 'n' && literal[7] == 't' { - return FRAGMENT - } - case 9: - if literal[0] == 'i' && literal[1] == 'n' && literal[2] == 't' && literal[3] == 'e' && literal[4] == 'r' && literal[5] == 'f' && literal[6] == 'a' && literal[7] == 'c' && literal[8] == 'e' { - return INTERFACE - } - if literal[0] == 'd' && literal[1] == 'i' && literal[2] == 'r' && literal[3] == 'e' && literal[4] == 'c' && literal[5] == 't' && literal[6] == 'i' && literal[7] == 'v' && literal[8] == 'e' { - return DIRECTIVE - } - case 10: - if literal[0] == 'i' && literal[1] == 'm' && literal[2] == 'p' && literal[3] == 'l' && literal[4] == 'e' && literal[5] == 'm' && literal[6] == 'e' && literal[7] == 'n' && literal[8] == 't' && literal[9] == 's' { - return IMPLEMENTS - } - if literal[0] == 'r' && literal[1] == 'e' && literal[2] == 'p' && literal[3] == 'e' && literal[4] == 'a' && literal[5] == 't' && literal[6] == 'a' && literal[7] == 'b' && literal[8] == 'l' && literal[9] == 'e' { - return REPEATABLE - } - case 12: - if literal[0] == 's' && literal[1] == 'u' && literal[2] == 'b' && literal[3] == 's' && literal[4] == 'c' && literal[5] == 'r' && literal[6] == 'i' && literal[7] == 'p' && literal[8] == 't' && literal[9] == 'i' && literal[10] == 'o' && literal[11] == 'n' { - return SUBSCRIPTION - } - } - - return UNDEFINED -} diff --git a/pkg/lexer/identkeyword/identkeyword_string.go b/pkg/lexer/identkeyword/identkeyword_string.go deleted file mode 100644 index bfc2d13ba..000000000 --- a/pkg/lexer/identkeyword/identkeyword_string.go +++ /dev/null @@ -1,42 +0,0 @@ -// Code generated by "stringer -type=IdentKeyword"; DO NOT EDIT. - -package identkeyword - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[UNDEFINED-0] - _ = x[ON-1] - _ = x[TRUE-2] - _ = x[FALSE-3] - _ = x[NULL-4] - _ = x[QUERY-5] - _ = x[MUTATION-6] - _ = x[SUBSCRIPTION-7] - _ = x[FRAGMENT-8] - _ = x[IMPLEMENTS-9] - _ = x[SCHEMA-10] - _ = x[SCALAR-11] - _ = x[TYPE-12] - _ = x[INTERFACE-13] - _ = x[UNION-14] - _ = x[ENUM-15] - _ = x[INPUT-16] - _ = x[DIRECTIVE-17] - _ = x[EXTEND-18] - _ = x[REPEATABLE-19] -} - -const _IdentKeyword_name = "UNDEFINEDONTRUEFALSENULLQUERYMUTATIONSUBSCRIPTIONFRAGMENTIMPLEMENTSSCHEMASCALARTYPEINTERFACEUNIONENUMINPUTDIRECTIVEEXTENDREPEATABLE" - -var _IdentKeyword_index = [...]uint8{0, 9, 11, 15, 20, 24, 29, 37, 49, 57, 67, 73, 79, 83, 92, 97, 101, 106, 115, 121, 131} - -func (i IdentKeyword) String() string { - if i < 0 || i >= IdentKeyword(len(_IdentKeyword_index)-1) { - return "IdentKeyword(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _IdentKeyword_name[_IdentKeyword_index[i]:_IdentKeyword_index[i+1]] -} diff --git a/pkg/lexer/keyword/keyword.go b/pkg/lexer/keyword/keyword.go deleted file mode 100644 index bfaf5356a..000000000 --- a/pkg/lexer/keyword/keyword.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:generate stringer -type=Keyword - -// Package keyword contains all possible GraphQL keywords -package keyword - -type Keyword int - -const ( - UNDEFINED Keyword = iota - IDENT - COMMENT - EOF - - COLON - BANG - LT - TAB - SPACE - COMMA - AT - DOT - SPREAD - PIPE - SLASH - EQUALS - SUB - AND - QUOTE - - DOLLAR - STRING - BLOCKSTRING - INTEGER - FLOAT - - LPAREN - RPAREN - LBRACK - RBRACK - LBRACE - RBRACE -) diff --git a/pkg/lexer/keyword/keyword_string.go b/pkg/lexer/keyword/keyword_string.go deleted file mode 100644 index f37f6a776..000000000 --- a/pkg/lexer/keyword/keyword_string.go +++ /dev/null @@ -1,52 +0,0 @@ -// Code generated by "stringer -type=Keyword"; DO NOT EDIT. - -package keyword - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[UNDEFINED-0] - _ = x[IDENT-1] - _ = x[COMMENT-2] - _ = x[EOF-3] - _ = x[COLON-4] - _ = x[BANG-5] - _ = x[LT-6] - _ = x[TAB-7] - _ = x[SPACE-8] - _ = x[COMMA-9] - _ = x[AT-10] - _ = x[DOT-11] - _ = x[SPREAD-12] - _ = x[PIPE-13] - _ = x[SLASH-14] - _ = x[EQUALS-15] - _ = x[SUB-16] - _ = x[AND-17] - _ = x[QUOTE-18] - _ = x[DOLLAR-19] - _ = x[STRING-20] - _ = x[BLOCKSTRING-21] - _ = x[INTEGER-22] - _ = x[FLOAT-23] - _ = x[LPAREN-24] - _ = x[RPAREN-25] - _ = x[LBRACK-26] - _ = x[RBRACK-27] - _ = x[LBRACE-28] - _ = x[RBRACE-29] -} - -const _Keyword_name = "UNDEFINEDIDENTCOMMENTEOFCOLONBANGLTTABSPACECOMMAATDOTSPREADPIPESLASHEQUALSSUBANDQUOTEDOLLARSTRINGBLOCKSTRINGINTEGERFLOATLPARENRPARENLBRACKRBRACKLBRACERBRACE" - -var _Keyword_index = [...]uint8{0, 9, 14, 21, 24, 29, 33, 35, 38, 43, 48, 50, 53, 59, 63, 68, 74, 77, 80, 85, 91, 97, 108, 115, 120, 126, 132, 138, 144, 150, 156} - -func (i Keyword) String() string { - if i < 0 || i >= Keyword(len(_Keyword_index)-1) { - return "Keyword(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _Keyword_name[_Keyword_index[i]:_Keyword_index[i+1]] -} diff --git a/pkg/lexer/lexer.go b/pkg/lexer/lexer.go deleted file mode 100644 index 7b3c2f2af..000000000 --- a/pkg/lexer/lexer.go +++ /dev/null @@ -1,430 +0,0 @@ -// Package lexer contains the logic to turn an ast.Input into lexed tokens -package lexer - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/runes" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/token" -) - -// Lexer emits tokens from a input reader -type Lexer struct { - input *ast.Input -} - -func (l *Lexer) SetInput(input *ast.Input) { - l.input = input -} - -// Read emits the next token -func (l *Lexer) Read() (tok token.Token) { - - var next byte - - for { - tok.SetStart(l.input.InputPosition, l.input.TextPosition) - next = l.readRune() - if !l.byteIsWhitespace(next) { - break - } - } - - if l.matchSingleRuneToken(next, &tok) { - return - } - - switch next { - case runes.HASHTAG: - l.readComment(&tok) - return - case runes.QUOTE: - l.readString(&tok) - return - case runes.DOT: - l.readDotOrSpread(&tok) - return - } - - if runeIsDigit(next) { - l.readDigit(&tok) - return - } - - l.readIdent() - tok.Keyword = keyword.IDENT - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) - return -} - -func (l *Lexer) matchSingleRuneToken(r byte, tok *token.Token) bool { - - switch r { - case runes.EOF: - tok.Keyword = keyword.EOF - case runes.PIPE: - tok.Keyword = keyword.PIPE - case runes.EQUALS: - tok.Keyword = keyword.EQUALS - case runes.AT: - tok.Keyword = keyword.AT - case runes.COLON: - tok.Keyword = keyword.COLON - case runes.BANG: - tok.Keyword = keyword.BANG - case runes.LPAREN: - tok.Keyword = keyword.LPAREN - case runes.RPAREN: - tok.Keyword = keyword.RPAREN - case runes.LBRACE: - tok.Keyword = keyword.LBRACE - case runes.RBRACE: - tok.Keyword = keyword.RBRACE - case runes.LBRACK: - tok.Keyword = keyword.LBRACK - case runes.RBRACK: - tok.Keyword = keyword.RBRACK - case runes.AND: - tok.Keyword = keyword.AND - case runes.SUB: - tok.Keyword = keyword.SUB - case runes.DOLLAR: - tok.Keyword = keyword.DOLLAR - default: - return false - } - - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) - - return true -} - -func (l *Lexer) readIdent() { - for { - if l.input.InputPosition < l.input.Length { - if !l.runeIsIdent(l.input.RawBytes[l.input.InputPosition]) { - return - } - l.input.TextPosition.CharStart++ - l.input.InputPosition++ - } else { - return - } - } -} - -func (l *Lexer) readDotOrSpread(tok *token.Token) { - - isSpread := l.peekEquals(false, runes.DOT, runes.DOT) - - if isSpread { - l.swallowAmount(2) - tok.Keyword = keyword.SPREAD - } else { - tok.Keyword = keyword.DOT - } - - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) -} - -func (l *Lexer) readComment(tok *token.Token) { - - tok.Keyword = keyword.COMMENT - - for { - next := l.readRune() - switch next { - case runes.EOF: - return - case runes.CARRIAGERETURN, runes.LINETERMINATOR: - if l.peekRune(true) != runes.HASHTAG { - return - } - default: - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) - } - } -} - -func (l *Lexer) readString(tok *token.Token) { - - if l.peekEquals(false, runes.QUOTE, runes.QUOTE) { - l.swallowAmount(2) - l.readBlockString(tok) - } else { - l.readSingleLineString(tok) - } -} - -func (l *Lexer) swallowAmount(amount int) { - for i := 0; i < amount; i++ { - l.readRune() - } -} - -func (l *Lexer) peekEquals(ignoreWhitespace bool, equals ...byte) bool { - - var whitespaceOffset int - if ignoreWhitespace { - whitespaceOffset = l.peekWhitespaceLength() - } - - start := l.input.InputPosition + whitespaceOffset - end := l.input.InputPosition + len(equals) + whitespaceOffset - - if end > l.input.Length { - return false - } - - for i := 0; i < len(equals); i++ { - if l.input.RawBytes[start+i] != equals[i] { - return false - } - } - - return true -} - -func (l *Lexer) peekWhitespaceLength() (amount int) { - for i := l.input.InputPosition; i < l.input.Length; i++ { - if l.byteIsWhitespace(l.input.RawBytes[i]) { - amount++ - } else { - break - } - } - - return amount -} - -func (l *Lexer) readDigit(tok *token.Token) { - - var r byte - for { - r = l.peekRune(false) - if !runeIsDigit(r) { - break - } - l.readRune() - } - - hasExponent := r == runes.EXPONENT_LOWER || r == runes.EXPONENT_UPPER - isFloat := r == runes.DOT || hasExponent - - if isFloat { - l.readRune() - l.readFloat(hasExponent, tok) - return - } - - tok.Keyword = keyword.INTEGER - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) -} - -func (l *Lexer) readFloat(hasReadExponentAlready bool, tok *token.Token) { - - var r byte - for { - r = l.peekRune(false) - if !runeIsDigit(r) { - break - } - l.readRune() - } - - if hasReadExponentAlready { - float := keyword.FLOAT - tok.Keyword = float - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) - return - } - - optionalExponent := l.peekRune(false) - if optionalExponent == runes.EXPONENT_LOWER || optionalExponent == runes.EXPONENT_UPPER { - l.readRune() - } - - optionalPlusMinus := l.peekRune(false) - if optionalPlusMinus == runes.SUB || optionalPlusMinus == runes.ADD { - l.readRune() - } - - for { - r = l.peekRune(false) - if !runeIsDigit(r) { - break - } - l.readRune() - } - - float := keyword.FLOAT - tok.Keyword = float - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) -} - -func (l *Lexer) readRune() (r byte) { - - if l.input.InputPosition < l.input.Length { - r = l.input.RawBytes[l.input.InputPosition] - - if r == runes.LINETERMINATOR { - l.input.TextPosition.LineStart++ - l.input.TextPosition.CharStart = 1 - } else { - l.input.TextPosition.CharStart++ - } - - l.input.InputPosition++ - } else { - r = runes.EOF - } - - return -} - -func (l *Lexer) peekRune(ignoreWhitespace bool) (r byte) { - - for i := l.input.InputPosition; i < l.input.Length; i++ { - r = l.input.RawBytes[i] - if !ignoreWhitespace { - return r - } else if !l.byteIsWhitespace(r) { - return r - } - } - - return runes.EOF -} - -func (l *Lexer) runeIsIdent(r byte) bool { - - switch { - case r >= 'a' && r <= 'z': - return true - case r >= 'A' && r <= 'Z': - return true - case r >= '0' && r <= '9': - return true - case r == runes.SUB: - return true - case r == runes.UNDERSCORE: - return true - default: - return false - } -} - -func runeIsDigit(r byte) bool { - switch { - case r >= '0' && r <= '9': - return true - default: - return false - } -} - -func (l *Lexer) byteIsWhitespace(r byte) bool { - switch r { - case runes.SPACE, runes.TAB, runes.CARRIAGERETURN, runes.LINETERMINATOR, runes.COMMA: - return true - default: - return false - } -} - -func (l *Lexer) readBlockString(tok *token.Token) { - tok.Keyword = keyword.BLOCKSTRING - - tok.SetStart(l.input.InputPosition, l.input.TextPosition) - tok.TextPosition.CharStart -= 3 - - escaped := false - quoteCount := 0 - whitespaceCount := 0 - reachedFirstNonWhitespace := false - leadingWhitespaceToken := 0 - - for { - next := l.readRune() - switch next { - case runes.SPACE, runes.TAB, runes.CARRIAGERETURN, runes.LINETERMINATOR: - quoteCount = 0 - whitespaceCount++ - case runes.EOF: - return - case runes.QUOTE: - if escaped { - escaped = !escaped - continue - } - - quoteCount++ - - if quoteCount == 3 { - tok.SetEnd(l.input.InputPosition-3, l.input.TextPosition) - tok.Literal.Start += uint32(leadingWhitespaceToken) - tok.Literal.End -= uint32(whitespaceCount) - return - } - - case runes.BACKSLASH: - escaped = !escaped - quoteCount = 0 - whitespaceCount = 0 - default: - if !reachedFirstNonWhitespace { - reachedFirstNonWhitespace = true - leadingWhitespaceToken = whitespaceCount - } - escaped = false - quoteCount = 0 - whitespaceCount = 0 - } - } -} - -func (l *Lexer) readSingleLineString(tok *token.Token) { - - tok.Keyword = keyword.STRING - - tok.SetStart(l.input.InputPosition, l.input.TextPosition) - tok.TextPosition.CharStart -= 1 - - escaped := false - whitespaceCount := 0 - reachedFirstNonWhitespace := false - leadingWhitespaceToken := 0 - - for { - next := l.readRune() - switch next { - case runes.SPACE, runes.TAB: - whitespaceCount++ - case runes.EOF: - tok.SetEnd(l.input.InputPosition, l.input.TextPosition) - tok.Literal.Start += uint32(leadingWhitespaceToken) - tok.Literal.End -= uint32(whitespaceCount) - return - case runes.QUOTE, runes.CARRIAGERETURN, runes.LINETERMINATOR: - if escaped { - escaped = !escaped - continue - } - - tok.SetEnd(l.input.InputPosition-1, l.input.TextPosition) - tok.Literal.Start += uint32(leadingWhitespaceToken) - tok.Literal.End -= uint32(whitespaceCount) - return - case runes.BACKSLASH: - escaped = !escaped - whitespaceCount = 0 - default: - if !reachedFirstNonWhitespace { - reachedFirstNonWhitespace = true - leadingWhitespaceToken = whitespaceCount - } - escaped = false - whitespaceCount = 0 - } - } -} diff --git a/pkg/lexer/lexer_test.go b/pkg/lexer/lexer_test.go deleted file mode 100644 index 6598b08c9..000000000 --- a/pkg/lexer/lexer_test.go +++ /dev/null @@ -1,680 +0,0 @@ -package lexer - -import ( - "encoding/json" - "fmt" - "os" - "testing" - - "github.com/jensneuse/diffview" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/token" - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestLexer_Peek_Read(t *testing.T) { - - type checkFunc func(lex *Lexer, i int) - - run := func(inStr string, checks ...checkFunc) { - - in := &ast.Input{} - in.ResetInputBytes([]byte(inStr)) - lexer := &Lexer{} - lexer.SetInput(in) - - for i := range checks { - checks[i](lexer, i+1) - } - } - - mustRead := func(k keyword.Keyword, wantLiteral string) checkFunc { - return func(lex *Lexer, i int) { - tok := lex.Read() - if k != tok.Keyword { - panic(fmt.Errorf("mustRead: want(keyword): %s, got: %s [check: %d]", k.String(), tok.String(), i)) - } - gotLiteral := string(lex.input.ByteSlice(tok.Literal)) - if wantLiteral != gotLiteral { - panic(fmt.Errorf("mustRead: want(literal): %s, got: %s [check: %d]", wantLiteral, gotLiteral, i)) - } - } - } - - resetInput := func(input string) checkFunc { - return func(lex *Lexer, i int) { - lex.input.ResetInputBytes([]byte(input)) - } - } - - mustReadPosition := func(lineStart, charStart, lineEnd, charEnd uint32) checkFunc { - return func(lex *Lexer, i int) { - tok := lex.Read() - - if lineStart != tok.TextPosition.LineStart { - panic(fmt.Errorf("mustReadPosition: want(lineStart): %d, got: %d [check: %d]", lineStart, tok.TextPosition.LineStart, i)) - } - if charStart != tok.TextPosition.CharStart { - panic(fmt.Errorf("mustReadPosition: want(charStart): %d, got: %d [check: %d]", charStart, tok.TextPosition.CharStart, i)) - } - if lineEnd != tok.TextPosition.LineEnd { - panic(fmt.Errorf("mustReadPosition: want(lineEnd): %d, got: %d [check: %d]", lineEnd, tok.TextPosition.LineEnd, i)) - } - if charEnd != tok.TextPosition.CharEnd { - panic(fmt.Errorf("mustReadPosition: want(charEnd): %d, got: %d [check: %d]", charEnd, tok.TextPosition.CharEnd, i)) - } - } - } - - mustPeekWhitespaceLength := func(want int) checkFunc { - return func(lex *Lexer, i int) { - got := lex.peekWhitespaceLength() - if want != got { - panic(fmt.Errorf("mustPeekWhitespaceLength: want: %d, got: %d [check: %d]", want, got, i)) - } - } - } - - t.Run("peek whitespace length", func(t *testing.T) { - run(" foo", mustPeekWhitespaceLength(3)) - }) - t.Run("peek whitespace length with tab", func(t *testing.T) { - run(" foo", mustPeekWhitespaceLength(4)) - }) - t.Run("peek whitespace length with linebreak", func(t *testing.T) { - run(" \nfoo", mustPeekWhitespaceLength(4)) - }) - t.Run("peek whitespace length with carriage return", func(t *testing.T) { - run(" \rfoo", mustPeekWhitespaceLength(4)) - }) - t.Run("peek whitespace length with comma", func(t *testing.T) { - run(" ,foo", mustPeekWhitespaceLength(4)) - }) - t.Run("read correct when resetting input", func(t *testing.T) { - run("x", - mustRead(keyword.IDENT, "x"), - resetInput("y"), - mustRead(keyword.IDENT, "y"), - ) - }) - t.Run("read eof multiple times", func(t *testing.T) { - run("x", - mustRead(keyword.IDENT, "x"), - mustRead(keyword.EOF, ""), - mustRead(keyword.EOF, ""), - ) - }) - t.Run("read integer", func(t *testing.T) { - run("1337", mustRead(keyword.INTEGER, "1337")) - }) - t.Run("read negative integer", func(t *testing.T) { - run("-1337", mustRead(keyword.SUB, "-"), - mustRead(keyword.INTEGER, "1337")) - }) - t.Run("read integer with comma", func(t *testing.T) { - run("1337,", mustRead(keyword.INTEGER, "1337")) - }) - t.Run("read float", func(t *testing.T) { - run("13.37", mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read negative float", func(t *testing.T) { - run("-13.37", mustRead(keyword.SUB, "-"), - mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read float", func(t *testing.T) { - run("1.1)", mustRead(keyword.FLOAT, "1.1")) - }) - t.Run("read float with space", func(t *testing.T) { - run("13.37 ", mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read float with tab", func(t *testing.T) { - run("13.37 ", mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read with lineTerminator", func(t *testing.T) { - run("13.37\n", mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read with carriage return and line feed", func(t *testing.T) { - run("13.37\r\n", mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read float with comma", func(t *testing.T) { - run("13.37,", mustRead(keyword.FLOAT, "13.37")) - }) - t.Run("read float + . + int", func(t *testing.T) { - run("1.3.3", mustRead(keyword.FLOAT, "1.3"), - mustRead(keyword.DOT, "."), - mustRead(keyword.INTEGER, "3"), - ) - }) - t.Run("read float + ident", func(t *testing.T) { - run("1.3x", mustRead(keyword.FLOAT, "1.3"), - mustRead(keyword.IDENT, "x"), - ) - }) - t.Run("fail reading incomplete float", func(t *testing.T) { - run("13.", mustRead(keyword.FLOAT, "13.")) - }) - t.Run("read plancks constant", func(t *testing.T) { - run("6.63E-34", mustRead(keyword.FLOAT, "6.63E-34")) - }) - t.Run("read electron mass kg", func(t *testing.T) { - run("9.10938356e-3", mustRead(keyword.FLOAT, "9.10938356e-3")) - }) - t.Run("read earth mass kg", func(t *testing.T) { - run("5.9724e24", mustRead(keyword.FLOAT, "5.9724e24")) - }) - t.Run("read earth circumference m", func(t *testing.T) { - run("4E7", mustRead(keyword.FLOAT, "4E7")) - }) - t.Run("read an inch in mm", func(t *testing.T) { - run("2.54E+1", mustRead(keyword.FLOAT, "2.54E+1")) - }) - t.Run("read electron charge/mass ratio", func(t *testing.T) { - run("-1.758E11", mustRead(keyword.SUB, "-"), - mustRead(keyword.FLOAT, "1.758E11")) - }) - t.Run("read single line string", func(t *testing.T) { - run("\"foo\"", mustRead(keyword.STRING, "foo")) - }) - t.Run("read single line string with leading/trailing whitespace", func(t *testing.T) { - run("\" foo \"", mustRead(keyword.STRING, "foo")) - }) - t.Run("peek incomplete string as quote", func(t *testing.T) { - run("\"foo", mustRead(keyword.STRING, "foo")) - }) - t.Run("read single line string with escaped quote", func(t *testing.T) { - run("\"foo \\\" bar\"", mustRead(keyword.STRING, "foo \\\" bar")) - }) - t.Run("read single line string with escaped backslash", func(t *testing.T) { - run("\"foo \\\\ bar\"", mustRead(keyword.STRING, "foo \\\\ bar")) - }) - t.Run("read multi line string with escaped quote", func(t *testing.T) { - run("\"\"\"foo \\\" bar\"\"\"", mustRead(keyword.BLOCKSTRING, "foo \\\" bar")) - }) - t.Run("read multi line string with two escaped quotes", func(t *testing.T) { - run("\"\"\"foo \"\" bar\"\"\"", mustRead(keyword.BLOCKSTRING, "foo \"\" bar")) - }) - t.Run("read multi line string", func(t *testing.T) { - run("\"\"\"\nfoo\nbar\"\"\"", mustRead(keyword.BLOCKSTRING, "foo\nbar")) - }) - t.Run("read multi line string with carriage return", func(t *testing.T) { - run("\"\"\"\r\nfoo\r\nbar\"\"\"", mustRead(keyword.BLOCKSTRING, "foo\r\nbar")) - }) - t.Run("read multi line string with escaped backslash", func(t *testing.T) { - run("\"\"\"foo \\\\ bar\"\"\"", mustRead(keyword.BLOCKSTRING, "foo \\\\ bar")) - }) - t.Run("read multi line string with leading/trailing space", func(t *testing.T) { - run(`""" foo """`, mustRead(keyword.BLOCKSTRING, "foo")) - }) - t.Run("read multi line string with trailing leading/trailing tab", func(t *testing.T) { - run(`""" foo """`, mustRead(keyword.BLOCKSTRING, "foo")) - }) - t.Run("read multi line string with trailing leading/trailing LT", func(t *testing.T) { - run(`""" - foo -"""`, mustRead(keyword.BLOCKSTRING, "foo")) - }) - t.Run("complex multi line string", func(t *testing.T) { - run("\"\"\"block string uses \\\"\"\"\n\"\"\"", mustRead(keyword.BLOCKSTRING, "block string uses \\\"\"\"")) - }) - t.Run("complex multi line string with carriage return", func(t *testing.T) { - run("\"\"\"block string uses \\\"\"\"\r\n\"\"\"", mustRead(keyword.BLOCKSTRING, "block string uses \\\"\"\"")) - }) - t.Run("read multi line string with trailing leading/trailing whitespace combination", func(t *testing.T) { - run(` """ - foo - """`, mustRead(keyword.BLOCKSTRING, "foo")) - }) - t.Run("read pipe", func(t *testing.T) { - run("|", mustRead(keyword.PIPE, "|")) - }) - t.Run("err reading dot", func(t *testing.T) { - run(".", mustRead(keyword.DOT, ".")) - }) - t.Run("read fragment spread", func(t *testing.T) { - run("...", mustRead(keyword.SPREAD, "...")) - }) - t.Run("must not read invalid fragment spread", func(t *testing.T) { - run("..", - mustRead(keyword.DOT, "."), - mustRead(keyword.DOT, ".")) - }) - t.Run("read variable", func(t *testing.T) { - run("$123", mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.INTEGER, "123")) - }) - t.Run("read variable 2", func(t *testing.T) { - run("$foo", mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.IDENT, "foo")) - }) - t.Run("read variable 3", func(t *testing.T) { - run("$_foo", mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.IDENT, "_foo")) - }) - t.Run("read variable 3", func(t *testing.T) { - run("$123", mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.INTEGER, "123")) - }) - t.Run("read variable 4", func(t *testing.T) { - run("$foo\n", mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.IDENT, "foo")) - }) - t.Run("read variable 4 with carriage return", func(t *testing.T) { - run("$foo\r\n", mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.IDENT, "foo")) - }) - t.Run("read err invalid variable", func(t *testing.T) { - run("$ foo", - mustRead(keyword.DOLLAR, "$"), - mustRead(keyword.IDENT, "foo"), - ) - }) - t.Run("read @", func(t *testing.T) { - run("@", mustRead(keyword.AT, "@")) - }) - t.Run("read equals", func(t *testing.T) { - run("=", mustRead(keyword.EQUALS, "=")) - }) - t.Run("read variable colon", func(t *testing.T) { - run(":", mustRead(keyword.COLON, ":")) - }) - t.Run("read bang", func(t *testing.T) { - run("!", mustRead(keyword.BANG, "!")) - }) - t.Run("read bracket open", func(t *testing.T) { - run("(", mustRead(keyword.LPAREN, "(")) - }) - t.Run("read bracket close", func(t *testing.T) { - run(")", mustRead(keyword.RPAREN, ")")) - }) - t.Run("read squared bracket open", func(t *testing.T) { - run("[", mustRead(keyword.LBRACK, "[")) - }) - t.Run("read squared bracket close", func(t *testing.T) { - run("]", mustRead(keyword.RBRACK, "]")) - }) - t.Run("read curly bracket open", func(t *testing.T) { - run("{", mustRead(keyword.LBRACE, "{")) - }) - t.Run("read curly bracket close", func(t *testing.T) { - run("}", mustRead(keyword.RBRACE, "}")) - }) - t.Run("read and", func(t *testing.T) { - run("&", mustRead(keyword.AND, "&")) - }) - t.Run("read EOF", func(t *testing.T) { - run("", mustRead(keyword.EOF, "")) - }) - t.Run("read ident", func(t *testing.T) { - run("foo", mustRead(keyword.IDENT, "foo")) - }) - t.Run("read ident with colon", func(t *testing.T) { - run("foo:", mustRead(keyword.IDENT, "foo")) - }) - t.Run("read ident with negative sign", func(t *testing.T) { - run("foo-bar", mustRead(keyword.IDENT, "foo-bar")) - }) - t.Run("read true", func(t *testing.T) { - run("true", mustRead(keyword.IDENT, "true")) - }) - t.Run("read true with space", func(t *testing.T) { - run(" true ", mustRead(keyword.IDENT, "true")) - }) - t.Run("read false", func(t *testing.T) { - run("false", mustRead(keyword.IDENT, "false")) - }) - t.Run("read query", func(t *testing.T) { - run("query", mustRead(keyword.IDENT, "query")) - }) - t.Run("read mutation", func(t *testing.T) { - run("mutation", mustRead(keyword.IDENT, "mutation")) - }) - t.Run("read subscription", func(t *testing.T) { - run("subscription", mustRead(keyword.IDENT, "subscription")) - }) - t.Run("read fragment", func(t *testing.T) { - run("fragment", mustRead(keyword.IDENT, "fragment")) - }) - t.Run("read fragment", func(t *testing.T) { - run("\n\n fragment", mustRead(keyword.IDENT, "fragment")) - }) - t.Run("read fragment with carriage return", func(t *testing.T) { - run("\r\n\r\n fragment", mustRead(keyword.IDENT, "fragment")) - }) - t.Run("read implements", func(t *testing.T) { - run("implements", mustRead(keyword.IDENT, "implements")) - }) - t.Run("read schema", func(t *testing.T) { - run("schema", mustRead(keyword.IDENT, "schema")) - }) - t.Run("read scalar", func(t *testing.T) { - run("scalar", mustRead(keyword.IDENT, "scalar")) - }) - t.Run("read type", func(t *testing.T) { - run("type", mustRead(keyword.IDENT, "type")) - }) - t.Run("read interface", func(t *testing.T) { - run("interface", mustRead(keyword.IDENT, "interface")) - }) - t.Run("read union", func(t *testing.T) { - run("union", mustRead(keyword.IDENT, "union")) - }) - t.Run("read enum", func(t *testing.T) { - run("enum", mustRead(keyword.IDENT, "enum")) - }) - t.Run("read input", func(t *testing.T) { - run("input", mustRead(keyword.IDENT, "input")) - }) - t.Run("read directive", func(t *testing.T) { - run("directive", mustRead(keyword.IDENT, "directive")) - }) - t.Run("read inputValue", func(t *testing.T) { - run("inputValue", mustRead(keyword.IDENT, "inputValue")) - }) - t.Run("read extend", func(t *testing.T) { - run("extend", mustRead(keyword.IDENT, "extend")) - }) - t.Run("read on", func(t *testing.T) { - run("on", mustRead(keyword.IDENT, "on")) - }) - t.Run("read on with whitespace", func(t *testing.T) { - run("on ", mustRead(keyword.IDENT, "on")) - }) - t.Run("read ignore comma", func(t *testing.T) { - run(",", mustRead(keyword.EOF, "")) - }) - t.Run("read ignore space", func(t *testing.T) { - run(" ", mustRead(keyword.EOF, "")) - }) - t.Run("read ignore tab", func(t *testing.T) { - run(" ", mustRead(keyword.EOF, "")) - }) - t.Run("read ignore lineTerminator", func(t *testing.T) { - run("\n", mustRead(keyword.EOF, "")) - }) - t.Run("read ignore lineTerminator with carriage return", func(t *testing.T) { - run("\r\n", mustRead(keyword.EOF, "")) - }) - t.Run("read null", func(t *testing.T) { - run("null", mustRead(keyword.IDENT, "null")) - }) - t.Run("read single line comment", func(t *testing.T) { - run("# A connection to a list of items.", - mustRead(keyword.COMMENT, "# A connection to a list of items.")) - }) - t.Run("read single line comment", func(t *testing.T) { - run("# A connection to a list of items.", - mustRead(keyword.COMMENT, "# A connection to a list of items.")) - }) - t.Run("read single line comment", func(t *testing.T) { - run("# A connection to a list of items.\nident", - mustRead(keyword.COMMENT, "# A connection to a list of items."), - mustRead(keyword.IDENT, "ident"), - ) - }) - t.Run("read single line comment with carriage return", func(t *testing.T) { - run("# A connection to a list of items.\r\nident", - mustRead(keyword.COMMENT, "# A connection to a list of items."), - mustRead(keyword.IDENT, "ident"), - ) - }) - t.Run("read multi line comment", func(t *testing.T) { - run(`#1 -#2 -#three`, - mustRead(keyword.COMMENT, "#1\n#2\n#three"), - ) - }) - t.Run("multi read 'foo:'", func(t *testing.T) { - run("foo:", - mustRead(keyword.IDENT, "foo"), - mustRead(keyword.COLON, ":"), - ) - }) - t.Run("multi read '1,2,3'", func(t *testing.T) { - run("1,2,3", - mustRead(keyword.INTEGER, "1"), - mustRead(keyword.INTEGER, "2"), - mustRead(keyword.INTEGER, "3"), - ) - }) - t.Run("multi read positions", func(t *testing.T) { - run(`foo bar baz -bal - bas """ -x""" -"foo bar baz " - ... -$foo - 1337 `, - mustReadPosition(1, 1, 1, 4), - mustReadPosition(1, 5, 1, 8), - mustReadPosition(1, 9, 1, 12), - mustReadPosition(2, 1, 2, 4), - mustReadPosition(3, 2, 3, 5), - mustReadPosition(3, 6, 4, 5), - mustReadPosition(5, 1, 5, 15), - mustReadPosition(6, 2, 6, 5), - mustReadPosition(7, 1, 7, 2), - mustReadPosition(7, 2, 7, 5), - mustReadPosition(8, 2, 8, 6), - ) - }) - t.Run("multi read nested structure", func(t *testing.T) { - run(`Goland { - ... on GoWater { - ... on GoAir { - go - } - } - }`, - mustRead(keyword.IDENT, "Goland"), mustRead(keyword.LBRACE, "{"), - mustRead(keyword.SPREAD, "..."), mustRead(keyword.IDENT, "on"), mustRead(keyword.IDENT, "GoWater"), mustRead(keyword.LBRACE, "{"), - mustRead(keyword.SPREAD, "..."), mustRead(keyword.IDENT, "on"), mustRead(keyword.IDENT, "GoAir"), mustRead(keyword.LBRACE, "{"), - mustRead(keyword.IDENT, "go"), - mustRead(keyword.RBRACE, "}"), - mustRead(keyword.RBRACE, "}"), - mustRead(keyword.RBRACE, "}"), - ) - }) - t.Run("multi read many idents and strings", func(t *testing.T) { - run(`1337 1338 1339 "foo" "bar" """foo bar""" """foo -bar""" """foo -bar -baz -""" -13.37`, - mustRead(keyword.INTEGER, "1337"), mustRead(keyword.INTEGER, "1338"), mustRead(keyword.INTEGER, "1339"), - mustRead(keyword.STRING, "foo"), mustRead(keyword.STRING, "bar"), mustRead(keyword.BLOCKSTRING, "foo bar"), - mustRead(keyword.BLOCKSTRING, "foo\nbar"), - mustRead(keyword.BLOCKSTRING, "foo\nbar\nbaz"), - mustRead(keyword.FLOAT, "13.37"), - ) - }) - t.Run("append input", func(t *testing.T) { - - in := &ast.Input{} - lexer := &Lexer{} - lexer.SetInput(in) - - in.ResetInputBytes([]byte("foo")) - - foo := lexer.Read() - if string(in.ByteSlice(foo.Literal)) != "foo" { - t.Fatal("want foo") - } - - in.AppendInputBytes([]byte(" bar")) - - bar := lexer.Read() - if string(in.ByteSlice(bar.Literal)) != "bar" { - t.Fatal("want bar") - } - - in.AppendInputBytes([]byte(" baz")) - - baz := lexer.Read() - if string(in.ByteSlice(baz.Literal)) != "baz" { - t.Fatal("want baz") - } - }) -} - -var introspectionQuery = `query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -}` - -func TestLexerRegressions(t *testing.T) { - - in := &ast.Input{} - in.ResetInputBytes([]byte(introspectionQuery)) - lexer := &Lexer{} - lexer.SetInput(in) - - var total []token.Token - for { - tok := lexer.Read() - if tok.Keyword == keyword.EOF { - break - } - - total = append(total, tok) - } - - data, err := json.MarshalIndent(total, "", " ") - if err != nil { - t.Fatal(err) - } - - goldie.Assert(t, "introspection_lexed", data) - if t.Failed() { - - fixture, err := os.ReadFile("./fixtures/introspection_lexed.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("introspection_lexed", fixture, data) - } -} - -func BenchmarkLexer(b *testing.B) { - - in := &ast.Input{} - lexer := &Lexer{} - lexer.SetInput(in) - - inputBytes := []byte(introspectionQuery) - - b.ReportAllocs() - b.ResetTimer() - b.SetBytes(int64(len(inputBytes))) - - for i := 0; i < b.N; i++ { - - in.ResetInputBytes(inputBytes) - - var key keyword.Keyword - - for key != keyword.EOF { - key = lexer.Read().Keyword - } - } -} diff --git a/pkg/lexer/literal/literal.go b/pkg/lexer/literal/literal.go deleted file mode 100644 index 81075ffe1..000000000 --- a/pkg/lexer/literal/literal.go +++ /dev/null @@ -1,156 +0,0 @@ -// Package literal contains a selection of frequently used literals with GraphQL APIs -package literal - -import "bytes" - -const ( - COLON_BYTE = byte(':') - COMMA_BYTE = byte(',') - LBRACK_BYTE = byte('[') - RBRACK_BYTE = byte(']') - LBRACE_BYTE = byte('{') - RBRACE_BYTE = byte('}') - SUB_BYTE = byte('-') -) - -var ( - COLON = []byte{COLON_BYTE} - BANG = []byte("!") - LINETERMINATOR = []byte("\n") - TAB = []byte(" ") - SPACE = []byte(" ") - QUOTE = []byte("\"") - COMMA = []byte{COMMA_BYTE} - AT = []byte("@") - DOLLAR = []byte("$") - DOT = []byte(".") - SPREAD = []byte("...") - PIPE = []byte("|") - SLASH = []byte("/") - BACKSLASH = []byte("\\") - EQUALS = []byte("=") - SUB = []byte{SUB_BYTE} - AND = []byte("&") - - LPAREN = []byte("(") - RPAREN = []byte(")") - LBRACK = []byte{LBRACK_BYTE} - RBRACK = []byte{RBRACK_BYTE} - LBRACE = []byte{LBRACE_BYTE} - DOUBLE_LBRACE = []byte("{{") - DOUBLE_RBRACE = []byte("}}") - RBRACE = []byte{RBRACE_BYTE} - - GOBOOL = []byte("bool") - GOINT32 = []byte("int32") - GOFLOAT32 = []byte("float32") - GOSTRING = []byte("string") - GONIL = []byte("nil") - - EOF = []byte("eof") - ID = []byte("ID") - Date = []byte("Date") - BOOLEAN = []byte("Boolean") - STRING = []byte("String") - INT = []byte("Int") - FLOAT = []byte("Float") - TYPE = []byte("type") - UNDERSCORETYPE = []byte("__type") - UNDERSCORESCHEMA = []byte("__schema") - TYPENAME = []byte("__typename") - GRAPHQLTYPE = []byte("graphqlType") - INTERFACE = []byte("interface") - INPUT = []byte("input") - WASMFILE = []byte("wasmFile") - INCLUDE = []byte("include") - IF = []byte("if") - SKIP = []byte("skip") - SCHEMA = []byte("schema") - EXTEND = []byte("extend") - SCALAR = []byte("scalar") - UNION = []byte("union") - ENUM = []byte("enum") - DIRECTIVE = []byte("directive") - REPEATABLE = []byte("repeatable") - QUERY = []byte("query") - MUTATION = []byte("mutation") - SUBSCRIPTION = []byte("subscription") - IMPLEMENTS = []byte("implements") - ON = []byte("on") - FRAGMENT = []byte("fragment") - NULL = []byte("null") - OBJECT = []byte("object") - DATA = []byte("data") - URL = []byte("url") - CONFIG_FILE_PATH = []byte("configFilePath") - CONFIG_STRING = []byte("configString") - DELAY_SECONDS = []byte("delaySeconds") - PIPELINE_CONFIG = []byte("pipelineConfig") - PIPELINE_CONFIG_STRING = []byte("pipelineConfigString") - PIPELINE_CONFIG_FILE = []byte("pipelineConfigFile") - TRANSFORMATION = []byte("transformation") - INPUT_JSON = []byte("inputJSON") - DEFAULT_TYPENAME = []byte("defaultTypeName") - STATUS_CODE_TYPENAME_MAPPINGS = []byte("statusCodeTypeNameMappings") - DOT_OBJECT_DOT = []byte(".object.") - DOT_ARGUMENTS_DOT = []byte(".arguments.") - ADDR = []byte("addr") - ADD = []byte("add") - BROKERADDR = []byte("brokerAddr") - CLIENTID = []byte("clientID") - TOPIC = []byte("topic") - HOST = []byte("host") - PARAMS = []byte("params") - FIELD = []byte("field") - BODY = []byte("body") - METHOD = []byte("method") - MODE = []byte("mode") - HEADERS = []byte("headers") - KEY = []byte("key") - OP = []byte("op") - REPLACE = []byte("replace") - INITIAL_BATCH_SIZE = []byte("initialBatchSize") - MILLISECONDS = []byte("milliSeconds") - PATH = []byte("path") - VALUE = []byte("value") - HTTP_METHOD_GET = []byte("GET") - HTTP_METHOD_POST = []byte("POST") - HTTP_METHOD_PUT = []byte("PUT") - HTTP_METHOD_DELETE = []byte("DELETE") - HTTP_METHOD_PATCH = []byte("PATCH") - - TRUE = []byte("true") - FALSE = []byte("false") - - LocationQuery = []byte("QUERY") - LocationMutation = []byte("MUTATION") - LocationSubscription = []byte("SUBSCRIPTION") - LocationField = []byte("FIELD") - LocationFragmentDefinition = []byte("FRAGMENT_DEFINITION") - LocationFragmentSpread = []byte("FRAGMENT_SPREAD") - LocationInlineFragment = []byte("INLINE_FRAGMENT") - LocationVariableDefinition = []byte("VARIABLE_DEFINITION") - - LocationSchema = []byte("SCHEMA") - LocationScalar = []byte("SCALAR") - LocationObject = []byte("OBJECT") - LocationFieldDefinition = []byte("FIELD_DEFINITION") - LocationArgumentDefinition = []byte("ARGUMENT_DEFINITION") - LocationInterface = []byte("INTERFACE") - LocationUnion = []byte("UNION") - LocationEnum = []byte("ENUM") - LocationEnumValue = []byte("ENUM_VALUE") - LocationInputObject = []byte("INPUT_OBJECT") - LocationInputFieldDefinition = []byte("INPUT_FIELD_DEFINITION") -) - -const ( - DOUBLE_LBRACE_STR = "{{" - DOUBLE_RBRACE_STR = "}}" -) - -type Literal []byte - -func (l Literal) Equals(another Literal) bool { - return bytes.Equal(l, another) -} diff --git a/pkg/lexer/position/position.go b/pkg/lexer/position/position.go deleted file mode 100644 index e21fdc8c8..000000000 --- a/pkg/lexer/position/position.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package position contains the objects and logic to properly describe the position of a token in a GraphQL document -package position - -import "fmt" - -type Position struct { - LineStart uint32 - LineEnd uint32 - CharStart uint32 - CharEnd uint32 -} - -func (p Position) String() string { - return fmt.Sprintf("%d:%d-%d:%d", p.LineStart, p.CharStart, p.LineEnd, p.CharEnd) -} - -func (p *Position) Reset() { - p.LineStart = 1 - p.LineEnd = 1 - p.CharStart = 1 - p.CharEnd = 1 -} - -func (p *Position) MergeStartIntoStart(position Position) { - p.LineStart = position.LineStart - p.CharStart = position.CharStart -} - -func (p *Position) MergeStartIntoEnd(position Position) { - p.LineEnd = position.LineStart - p.CharEnd = position.CharStart -} - -func (p *Position) MergeEndIntoEnd(position Position) { - p.LineEnd = position.LineEnd - p.CharEnd = position.CharEnd -} - -func (p *Position) IsBefore(another Position) bool { - return p.LineEnd < another.LineStart || - p.LineEnd == another.LineStart && p.CharEnd < another.CharStart -} diff --git a/pkg/lexer/runes/runes.go b/pkg/lexer/runes/runes.go deleted file mode 100644 index af1fe2fe1..000000000 --- a/pkg/lexer/runes/runes.go +++ /dev/null @@ -1,35 +0,0 @@ -// Package runes contains all possible 'special' runes in a GraphQL document -package runes - -const ( - EOF = 0 - COLON = ':' - BANG = '!' - CARRIAGERETURN = '\r' - LINETERMINATOR = '\n' - TAB = '\t' - SPACE = ' ' - COMMA = ',' - HASHTAG = '#' - QUOTE = '"' - BACKSLASH = '\\' - DOT = '.' - EXPONENT_LOWER = 'e' - EXPONENT_UPPER = 'E' - AT = '@' - DOLLAR = '$' - PIPE = '|' - SLASH = '/' - EQUALS = '=' - SUB = '-' - ADD = '+' - AND = '&' - UNDERSCORE = '_' - - LPAREN = '(' - RPAREN = ')' - LBRACK = '[' - RBRACK = ']' - LBRACE = '{' - RBRACE = '}' -) diff --git a/pkg/lexer/token/token.go b/pkg/lexer/token/token.go deleted file mode 100644 index 1982f6a5b..000000000 --- a/pkg/lexer/token/token.go +++ /dev/null @@ -1,32 +0,0 @@ -// Package token contains the object and logic needed to describe a lexed token in a GraphQL document -package token - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/keyword" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -type Token struct { - Keyword keyword.Keyword - Literal ast.ByteSliceReference - TextPosition position.Position -} - -func (t Token) String() string { - return fmt.Sprintf("token:: Keyword: %s, Pos: %s", t.Keyword, t.TextPosition) -} - -func (t *Token) SetStart(inputPosition int, textPosition position.Position) { - t.Literal.Start = uint32(inputPosition) - t.TextPosition.LineStart = textPosition.LineStart - t.TextPosition.CharStart = textPosition.CharStart -} - -func (t *Token) SetEnd(inputPosition int, textPosition position.Position) { - t.Literal.End = uint32(inputPosition) - t.TextPosition.LineEnd = textPosition.LineStart - t.TextPosition.CharEnd = textPosition.CharStart -} diff --git a/pkg/middleware/middleware.go b/pkg/middleware/middleware.go deleted file mode 100644 index 2c1bd4016..000000000 --- a/pkg/middleware/middleware.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package middleware contains useful middleware components for GraphQL services, e.g. for complexity analysis. -package middleware diff --git a/pkg/middleware/operation_complexity/operation_complexity.go b/pkg/middleware/operation_complexity/operation_complexity.go deleted file mode 100644 index 2615d834c..000000000 --- a/pkg/middleware/operation_complexity/operation_complexity.go +++ /dev/null @@ -1,292 +0,0 @@ -/* -package operation_complexity implements two common algorithms used by GitHub to calculate GraphQL query complexity - -1. Node count, the maximum number of Nodes a query may return -2. Complexity, the maximum number of Node requests that might be needed to execute the query - -OperationComplexityEstimator takes a schema definition and a query and then walks recursively through the query to calculate both variables. - -The calculation can be influenced by integer arguments on fields that indicate the amount of Nodes returned by a field. - -To help the algorithm understand your schema you could make use of these two directives: - -- directive @nodeCountMultiply on ARGUMENT_DEFINITION -- directive @nodeCountSkip on FIELD - -nodeCountMultiply: -Indicates that the Int value the directive is applied on should be used as a Node multiplier - -nodeCountSkip: -Indicates that the algorithm should skip this Node. This is useful to whitelist certain query paths, e.g. for introspection. -*/ -package operation_complexity - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type OperationStats struct { - NodeCount int - Complexity int - Depth int -} - -type RootFieldStats struct { - TypeName string - FieldName string - Alias string - Stats OperationStats -} - -var ( - nodeCountMultiply = []byte("nodeCountMultiply") - nodeCountSkip = []byte("nodeCountSkip") -) - -type OperationComplexityEstimator struct { - walker *astvisitor.Walker - visitor *complexityVisitor -} - -func NewOperationComplexityEstimator() *OperationComplexityEstimator { - - walker := astvisitor.NewWalker(48) - visitor := &complexityVisitor{ - Walker: &walker, - multipliers: make([]multiplier, 0, 16), - } - - walker.RegisterEnterDocumentVisitor(visitor) - walker.RegisterEnterArgumentVisitor(visitor) - walker.RegisterLeaveFieldVisitor(visitor) - walker.RegisterEnterFieldVisitor(visitor) - walker.RegisterEnterSelectionSetVisitor(visitor) - walker.RegisterEnterFragmentDefinitionVisitor(visitor) - - return &OperationComplexityEstimator{ - walker: &walker, - visitor: visitor, - } -} - -func (n *OperationComplexityEstimator) Do(operation, definition *ast.Document, report *operationreport.Report) (OperationStats, []RootFieldStats) { - n.visitor.count = 0 - n.visitor.complexity = 0 - n.visitor.maxFieldDepth = 0 - n.visitor.multipliers = n.visitor.multipliers[:0] - - n.visitor.maxSelectionSetFieldDepth = 0 - n.visitor.selectionSetDepth = 0 - - if n.visitor.calculatedRootFieldStats == nil { - n.visitor.calculatedRootFieldStats = make([]RootFieldStats, 0, len(definition.RootOperationTypeDefinitions)) - } - n.visitor.calculatedRootFieldStats = n.visitor.calculatedRootFieldStats[:0] - - if n.visitor.rootOperationTypeNames == nil { - n.visitor.rootOperationTypeNames = make(map[string]struct{}, len(definition.RootOperationTypeDefinitions)) - } - for key := range n.visitor.rootOperationTypeNames { - delete(n.visitor.rootOperationTypeNames, key) - } - - n.walker.Walk(operation, definition, report) - - depth := n.visitor.maxFieldDepth - n.visitor.selectionSetDepth - globalResult := OperationStats{ - NodeCount: n.visitor.count, - Complexity: n.visitor.complexity, - Depth: depth, - } - - return globalResult, n.visitor.calculatedRootFieldStats -} - -func CalculateOperationComplexity(operation, definition *ast.Document, report *operationreport.Report) (OperationStats, []RootFieldStats) { - estimator := NewOperationComplexityEstimator() - return estimator.Do(operation, definition, report) -} - -type complexityVisitor struct { - *astvisitor.Walker - operation, definition *ast.Document - count int - complexity int - maxFieldDepth int - multipliers []multiplier - - maxSelectionSetFieldDepth int - selectionSetDepth int - - rootOperationTypeNames map[string]struct{} - - currentRootFieldStats RootFieldStats - currentRootFieldMaxDepth int - currentRootFieldMaxSelectionSetDepth int - currentRootFieldSelectionSetDepth int - - calculatedRootFieldStats []RootFieldStats -} - -type multiplier struct { - fieldRef int - multi int -} - -func (c *complexityVisitor) calculateMultiplied(i int) int { - for _, j := range c.multipliers { - i = i * j.multi - } - return i -} - -func (c *complexityVisitor) EnterDocument(operation, definition *ast.Document) { - c.operation = operation - c.definition = definition - - for i := 0; i < len(c.definition.RootOperationTypeDefinitions); i++ { - name := c.definition.Input.ByteSliceString(c.definition.RootOperationTypeDefinitions[i].NamedType.Name) - c.rootOperationTypeNames[name] = struct{}{} - } -} - -func (c *complexityVisitor) EnterArgument(ref int) { - - if c.Ancestors[len(c.Ancestors)-1].Kind != ast.NodeKindField { - return - } - - definition, ok := c.ArgumentInputValueDefinition(ref) - if !ok { - return - } - - if !c.definition.InputValueDefinitionHasDirective(definition, nodeCountMultiply) { - return - } - - value := c.operation.ArgumentValue(ref) - if value.Kind == ast.ValueKindInteger { - multi := c.operation.IntValueAsInt32(value.Ref) - c.multipliers = append(c.multipliers, multiplier{ - fieldRef: c.Ancestors[len(c.Ancestors)-1].Ref, - multi: int(multi), - }) - } -} - -func (c *complexityVisitor) EnterField(ref int) { - definition, exists := c.FieldDefinition(ref) - if !exists { - return - } - - if _, exits := c.definition.FieldDefinitionDirectiveByName(definition, nodeCountSkip); exits { - c.SkipNode() - return - } - - typeName, fieldName, alias := c.extractFieldRelatedNames(ref, definition) - if c.isRootType(typeName) { - c.resetCurrentRootFieldComplexity(typeName, fieldName, alias) - } - - if !c.operation.FieldHasSelections(ref) { - return - } - - c.complexity = c.complexity + c.calculateMultiplied(1) - if c.Depth > c.maxFieldDepth { - c.maxFieldDepth = c.Depth - } - - c.currentRootFieldStats.Stats.Complexity = c.currentRootFieldStats.Stats.Complexity + c.calculateMultiplied(1) - if c.Depth > c.currentRootFieldMaxDepth { - c.currentRootFieldMaxDepth = c.Depth - } -} - -func (c *complexityVisitor) LeaveField(ref int) { - if c.isRootTypeField() { - c.endRootFieldComplexityCalculation() - } - - if len(c.multipliers) == 0 { - return - } - - if c.multipliers[len(c.multipliers)-1].fieldRef == ref { - c.multipliers = c.multipliers[:len(c.multipliers)-1] - } -} - -func (c *complexityVisitor) EnterSelectionSet(ref int) { - - if c.Ancestors[len(c.Ancestors)-1].Kind != ast.NodeKindField { - return - } - - c.count = c.count + c.calculateMultiplied(1) - if c.Depth > c.maxSelectionSetFieldDepth { - c.maxSelectionSetFieldDepth = c.Depth - c.selectionSetDepth++ - } - - c.currentRootFieldStats.Stats.NodeCount = c.currentRootFieldStats.Stats.NodeCount + c.calculateMultiplied(1) - if c.Depth > c.currentRootFieldMaxSelectionSetDepth { - c.currentRootFieldMaxSelectionSetDepth = c.Depth - c.currentRootFieldSelectionSetDepth++ - } -} - -func (c *complexityVisitor) EnterFragmentDefinition(ref int) { - c.SkipNode() -} - -func (c *complexityVisitor) resetCurrentRootFieldComplexity(typeName, fieldName, alias string) { - c.currentRootFieldStats = RootFieldStats{ - TypeName: typeName, - FieldName: fieldName, - Alias: alias, - Stats: OperationStats{ - NodeCount: 0, - Complexity: 0, - Depth: 0, - }, - } -} - -func (c *complexityVisitor) endRootFieldComplexityCalculation() { - currentDepth := c.currentRootFieldMaxDepth - c.currentRootFieldSelectionSetDepth - if currentDepth > 0 { - currentDepth-- - } - c.currentRootFieldStats.Stats.Depth = currentDepth - c.calculatedRootFieldStats = append(c.calculatedRootFieldStats, c.currentRootFieldStats) - - c.currentRootFieldMaxDepth = 0 - c.currentRootFieldMaxSelectionSetDepth = 0 - c.currentRootFieldSelectionSetDepth = 0 -} - -func (c *complexityVisitor) extractFieldRelatedNames(ref, definitionRef int) (typeName, fieldName, alias string) { - fieldName = c.definition.FieldDefinitionNameString(definitionRef) - alias = c.operation.FieldAliasOrNameString(ref) - if fieldName == alias { - alias = "" - } - - return c.EnclosingTypeDefinition.NameString(c.definition), fieldName, alias -} - -func (c *complexityVisitor) isRootType(name string) bool { - _, ok := c.rootOperationTypeNames[name] - return ok -} - -func (c *complexityVisitor) isRootTypeField() bool { - enclosingTypeName := c.EnclosingTypeDefinition.NameString(c.definition) - return c.isRootType(enclosingTypeName) -} diff --git a/pkg/middleware/operation_complexity/operation_complexity_test.go b/pkg/middleware/operation_complexity/operation_complexity_test.go deleted file mode 100644 index 1a3eb6226..000000000 --- a/pkg/middleware/operation_complexity/operation_complexity_test.go +++ /dev/null @@ -1,895 +0,0 @@ -package operation_complexity - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/astnormalization" - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeparser" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -func TestCalculateOperationComplexity(t *testing.T) { - t.Run("query with a scalar return type", func(t *testing.T) { - run(t, testDefinition, ` - { - currentPeriod - }`, - OperationStats{ - NodeCount: 0, - Complexity: 0, - Depth: 0, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "currentPeriod", - Stats: OperationStats{ - NodeCount: 0, - Complexity: 0, - Depth: 0, - }, - }, - }, - ) - }) - t.Run("one user", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 1) { - id - balance - name - address { - city - country - } - } - }`, - OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 3, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("one user with inline fragments", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 1) { - ... { - id - balance - name - address { - city - country - } - } - } - }`, - OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 3, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("one user with fragments", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 1) { - ...UserFragment - } - } - fragment UserFragment on User { - id - balance - name - address { - city - country - } - } - `, - OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 3, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("multiple users", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 10) { - id - balance - name - address { - city - country - } - } - }`, - OperationStats{ - NodeCount: 20, - Complexity: 11, - Depth: 3, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 20, - Complexity: 11, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("multiple users with multiple transactions", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 10) { - id - balance - name - address { - city - country - } - transactions(first: 5) { - id - amount - } - } - }`, - OperationStats{ - NodeCount: 70, - Complexity: 21, - Depth: 3, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 70, - Complexity: 21, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("multiple users with multiple transactions with nested senders", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 10) { - id - balance - name - address { - city - country - } - transactions(first: 5) { - id - amount - sender { - id - transactions(first: 10) { - id - amount - } - } - recipient { - id - transactions(first: 5) { - id - amount - } - } - } - } - }`, - OperationStats{ - NodeCount: 920, - Complexity: 221, - Depth: 5, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 920, - Complexity: 221, - Depth: 4, - }, - }, - }, - ) - }) - t.Run("multiple queries and one being an alias", func(t *testing.T) { - run(t, testDefinition, ` - { - person: user(id: "1") { - name - } - users(first: 1) { - id - balance - name - address { - city - country - } - } - bestUsers: users(first: 10) { - id - balance - name - address { - city - country - } - transactions(first: 5) { - id - amount - } - } - }`, - OperationStats{ - NodeCount: 73, - Complexity: 24, - Depth: 3, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "user", - Alias: "person", - Stats: OperationStats{ - NodeCount: 1, - Complexity: 1, - Depth: 1, - }, - }, - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - }, - { - TypeName: "Query", - FieldName: "users", - Alias: "bestUsers", - Stats: OperationStats{ - NodeCount: 70, - Complexity: 21, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("multiple queries with different depth higher depth first", func(t *testing.T) { - run(t, testDefinition, ` - { - transactions(first: 1) { - id - sender { - id - transactions(first: 1) { - id - } - } - } - users(first: 1) { - id - address { - city - } - } - }`, - OperationStats{ - NodeCount: 5, - Complexity: 5, - Depth: 4, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "transactions", - Stats: OperationStats{ - NodeCount: 3, - Complexity: 3, - Depth: 3, - }, - }, - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - }, - }, - ) - }) - t.Run("multiple queries with different depth higher depth last", func(t *testing.T) { - run(t, testDefinition, ` - { - users(first: 1) { - id - address { - city - } - } - transactions(first: 1) { - id - sender { - id - transactions(first: 1) { - id - } - } - } - }`, - OperationStats{ - NodeCount: 5, - Complexity: 5, - Depth: 4, - }, - []RootFieldStats{ - { - TypeName: "Query", - FieldName: "users", - Stats: OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - }, - { - TypeName: "Query", - FieldName: "transactions", - Stats: OperationStats{ - NodeCount: 3, - Complexity: 3, - Depth: 3, - }, - }, - }, - ) - }) - t.Run("multiple mutations with alias", func(t *testing.T) { - run(t, testDefinition, ` - mutation AlterUsers { - createJohn: createUser(input: {balance: 10, name: "John Doe", email: "john@doe.fake"}) { - id - } - createJane: createUser(input: {balance: 100, name: "Jane Doe", email: "jane@doe.fake"}) { - id - } - }`, - OperationStats{ - NodeCount: 2, - Complexity: 2, - Depth: 2, - }, - []RootFieldStats{ - { - TypeName: "Mutation", - FieldName: "createUser", - Alias: "createJohn", - Stats: OperationStats{ - NodeCount: 1, - Complexity: 1, - Depth: 1, - }, - }, - { - TypeName: "Mutation", - FieldName: "createUser", - Alias: "createJane", - Stats: OperationStats{ - NodeCount: 1, - Complexity: 1, - Depth: 1, - }, - }, - }, - ) - }) - t.Run("introspection query", func(t *testing.T) { - run(t, testDefinition, introspectionQuery, - OperationStats{ - NodeCount: 0, - Complexity: 0, - Depth: 0, - }, - []RootFieldStats{}, - ) - }) -} - -var run = func(t *testing.T, definition, operation string, expectedGlobalComplexityResult OperationStats, expectedFieldsComplexityResult []RootFieldStats) { - def := unsafeparser.ParseGraphqlDocumentString(definition) - op := unsafeparser.ParseGraphqlDocumentString(operation) - report := operationreport.Report{} - - astnormalization.NormalizeOperation(&op, &def, &report) - - actualGlobalComplexityResult, actualFieldsComplexityResult := CalculateOperationComplexity(&op, &def, &report) - if report.HasErrors() { - require.NoError(t, report) - } - - assert.Equal(t, expectedGlobalComplexityResult.NodeCount, actualGlobalComplexityResult.NodeCount, "unexpected global node count") - assert.Equal(t, expectedGlobalComplexityResult.Complexity, actualGlobalComplexityResult.Complexity, "unexpected global complexity") - assert.Equal(t, expectedGlobalComplexityResult.Depth, actualGlobalComplexityResult.Depth, "unexpected global depth") - assert.Equal(t, expectedFieldsComplexityResult, actualFieldsComplexityResult, "unexpected fields complexity result") -} - -func BenchmarkEstimateComplexity(b *testing.B) { - def := unsafeparser.ParseGraphqlDocumentString(testDefinition) - op := unsafeparser.ParseGraphqlDocumentString(complexQuery) - - estimator := NewOperationComplexityEstimator() - report := operationreport.Report{} - - b.ResetTimer() - b.ReportAllocs() - - for i := 0; i < b.N; i++ { - globalComplexityResult, _ := estimator.Do(&op, &def, &report) - if report.HasErrors() { - b.Fatal(report) - } - - if globalComplexityResult.NodeCount != 920 { - b.Fatalf("want nodeCount: 920, got: %d\n", globalComplexityResult.NodeCount) - } - if globalComplexityResult.Complexity != 221 { - b.Fatalf("want complexity: 221, got: %d\n", globalComplexityResult.Complexity) - } - if globalComplexityResult.Depth != 5 { - b.Fatalf("want depth: 5, got: %d\n", globalComplexityResult.Depth) - } - } -} - -const complexQuery = ` -{ - users(first: 10) { - id - balance - name - address { - city - country - } - transactions(first: 5) { - id - amount - sender { - id - transactions(first: 10) { - id - amount - } - } - recipient { - id - transactions(first: 5) { - id - amount - } - } - } - } -}` - -const testDefinition = ` - -directive @nodeCountMultiply on ARGUMENT_DEFINITION -directive @nodeCountSkip on FIELD - -scalar Date - -type User { - id: ID! - balance: Int! - name: String! - email: String! - address: Address - transactions(first: Int! @nodeCountMultiply, afterID: ID): [Transaction] -} - -type Address { - street: String - city: String - postalCode: String - country: String -} - -type Transaction { - id: ID! - date: Date! - amount: Int! - sender: User! - recipient: User! -} - -input NewTransaction { - sender: ID! - recipient: ID! - amount: Int! -} - -input AddressInput { - street: String! - city: String! - postalCode: String! - country: String! -} - -input UpdateUserDetailsInput { - name: String - address: AddressInput -} - -input NewUserInput { - balance: Int! - name: String! - email: String! -} - -type Query { - __schema: __Schema! @nodeCountSkip - user(id: ID!): User - users(first: Int! @nodeCountMultiply, afterID: ID): [User] - transactions(first: Int! @nodeCountMultiply, afterID: ID): [Transaction] - currentPeriod: String -} - -type Mutation { - createUser(input: NewUserInput!): User - makeTransaction(input: NewTransaction!): Transaction! - updateUserDetails(userID: ID!,input: UpdateUserDetailsInput!): User -} - -schema { - query: Query - mutation: Mutation -} - -"The 'Int' scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1." -scalar Int -"The 'Float' scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point)." -scalar Float -"The 'String' scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text." -scalar String -"The 'Boolean' scalar type represents 'true' or 'false' ." -scalar Boolean -"The 'ID' scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as '4') or integer (such as 4) input value will be accepted as an ID." -scalar ID @custom(typeName: "string") -"Directs the executor to include this field or fragment only when the argument is true." -directive @include( - " Included when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Directs the executor to skip this field or fragment when the argument is true." -directive @skip( - "Skipped when true." - if: Boolean! -) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT -"Marks an element of a GraphQL schema as no longer supported." -directive @deprecated( - """ - Explains why this element was deprecated, usually also including a suggestion - for how to access supported similar data. Formatted in - [Markdown](https://daringfireball.net/projects/markdown/). - """ - reason: String = "No longer supported" -) on FIELD_DEFINITION | ENUM_VALUE - -""" -A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document. -In some cases, you need to provide options to alter GraphQL's execution behavior -in ways field arguments will not suffice, such as conditionally including or -skipping a field. Directives provide this by describing additional information -to the executor. -""" -type __Directive { - name: String! - description: String - locations: [__DirectiveLocation!]! - args: [__InputValue!]! -} - -""" -A Directive can be adjacent to many parts of the GraphQL language, a -__DirectiveLocation describes one such possible adjacencies. -""" -enum __DirectiveLocation { - "Location adjacent to a query operation." - QUERY - "Location adjacent to a mutation operation." - MUTATION - "Location adjacent to a subscription operation." - SUBSCRIPTION - "Location adjacent to a field." - FIELD - "Location adjacent to a fragment definition." - FRAGMENT_DEFINITION - "Location adjacent to a fragment spread." - FRAGMENT_SPREAD - "Location adjacent to an inline fragment." - INLINE_FRAGMENT - "Location adjacent to a schema definition." - SCHEMA - "Location adjacent to a scalar definition." - SCALAR - "Location adjacent to an object type definition." - OBJECT - "Location adjacent to a field definition." - FIELD_DEFINITION - "Location adjacent to an argument definition." - ARGUMENT_DEFINITION - "Location adjacent to an interface definition." - INTERFACE - "Location adjacent to a union definition." - UNION - "Location adjacent to an enum definition." - ENUM - "Location adjacent to an enum value definition." - ENUM_VALUE - "Location adjacent to an input object type definition." - INPUT_OBJECT - "Location adjacent to an input object field definition." - INPUT_FIELD_DEFINITION -} -""" -One possible value for a given Enum. Enum values are unique values, not a -placeholder for a string or numeric value. However an Enum value is returned in -a JSON response as a string. -""" -type __EnumValue { - name: String! - description: String - isDeprecated: Boolean! - deprecationReason: String -} - -""" -Object and Interface types are described by a list of Fields, each of which has -a name, potentially a list of arguments, and a return type. -""" -type __Field { - name: String! - description: String - args: [__InputValue!]! - type: __Type! - isDeprecated: Boolean! - deprecationReason: String -} - -"""Arguments provided to Fields or Directives and the input fields of an -InputObject are represented as Input Values which describe their type and -optionally a default value. -""" -type __InputValue { - name: String! - description: String - type: __Type! - "A GraphQL-formatted string representing the default value for this input value." - defaultValue: String -} - -""" -A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all -available types and directives on the server, as well as the entry points for -query, mutation, and subscription operations. -""" -type __Schema { - "A list of all types supported by this server." - types: [__Type!]! - "The type that query operations will be rooted at." - queryType: __Type! - "If this server supports mutation, the type that mutation operations will be rooted at." - mutationType: __Type - "If this server support subscription, the type that subscription operations will be rooted at." - subscriptionType: __Type - "A list of all directives supported by this server." - directives: [__Directive!]! -} - -""" -The fundamental unit of any GraphQL Schema is the type. There are many kinds of -types in GraphQL as represented by the '__TypeKind' enum. - -Depending on the kind of a type, certain fields describe information about that -type. Scalar types provide no information beyond a name and description, while -Enum types provide their values. Object and Interface types provide the fields -they describe. Abstract types, Union and Interface, provide the Object types -possible at runtime. List and NonNull types compose other types. -""" -type __Type { - kind: __TypeKind! - name: String - description: String - fields(includeDeprecated: Boolean = false): [__Field!] - interfaces: [__Type!] - possibleTypes: [__Type!] - enumValues(includeDeprecated: Boolean = false): [__EnumValue!] - inputFields: [__InputValue!] - ofType: __Type -} - -"An enum describing what kind of type a given '__Type' is." -enum __TypeKind { - "Indicates this type is a scalar." - SCALAR - "Indicates this type is an object. 'fields' and 'interfaces' are valid fields." - OBJECT - "Indicates this type is an interface. 'fields' ' and ' 'possibleTypes' are valid fields." - INTERFACE - "Indicates this type is a union. 'possibleTypes' is a valid field." - UNION - "Indicates this type is an enum. 'enumValues' is a valid field." - ENUM - "Indicates this type is an input object. 'inputFields' is a valid field." - INPUT_OBJECT - "Indicates this type is a list. 'ofType' is a valid field." - LIST - "Indicates this type is a non-null. 'ofType' is a valid field." - NON_NULL -}` - -const introspectionQuery = ` -query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -}` diff --git a/pkg/operationreport/externalerror.go b/pkg/operationreport/externalerror.go deleted file mode 100644 index 6b0df5e86..000000000 --- a/pkg/operationreport/externalerror.go +++ /dev/null @@ -1,494 +0,0 @@ -package operationreport - -import ( - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphqlerrors" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/position" -) - -const ( - NotCompatibleTypeErrMsg = "%s cannot represent value: %s" - NotStringErrMsg = "%s cannot represent a non string value: %s" - NotIntegerErrMsg = "%s cannot represent non-integer value: %s" - BigIntegerErrMsg = "%s cannot represent non 32-bit signed integer value: %s" - NotFloatErrMsg = "%s cannot represent non numeric value: %s" - NotBooleanErrMsg = "%s cannot represent a non boolean value: %s" - NotIDErrMsg = "%s cannot represent a non-string and non-integer value: %s" - NotEnumErrMsg = `Enum "%s" cannot represent non-enum value: %s.` - NotAnEnumMemberErrMsg = `Value "%s" does not exist in "%s" enum.` - NullValueErrMsg = `Expected value of type "%s", found null.` - UnknownArgumentOnDirectiveErrMsg = `Unknown argument "%s" on directive "@%s".` - UnknownArgumentOnFieldErrMsg = `Unknown argument "%s" on field "%s.%s".` - UnknownTypeErrMsg = `Unknown type "%s".` - VariableIsNotInputTypeErrMsg = `Variable "$%s" cannot be non-input type "%s".` - MissingRequiredFieldOfInputObjectErrMsg = `Field "%s.%s" of required type "%s" was not provided.` - UnknownFieldOfInputObjectErrMsg = `Field "%s" is not defined by type "%s".` - DuplicatedFieldInputObjectErrMsg = `There can be only one input field named "%s".` - ValueIsNotAnInputObjectTypeErrMsg = `Expected value of type "%s", found %s.` -) - -type ExternalError struct { - Message string `json:"message"` - Path ast.Path `json:"path"` - Locations []graphqlerrors.Location `json:"locations"` -} - -func LocationsFromPosition(position ...position.Position) []graphqlerrors.Location { - out := make([]graphqlerrors.Location, len(position)) - for i, p := range position { - out[i].Line = p.LineStart - out[i].Column = p.CharStart - } - return out -} - -func ErrDocumentDoesntContainExecutableOperation() (err ExternalError) { - err.Message = "document doesn't contain any executable operation" - return -} - -func ErrFieldUndefinedOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("field: %s not defined on type: %s", fieldName, typeName) - return err -} - -func ErrFieldNameMustBeUniqueOnType(fieldName, typeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("field '%s.%s' can only be defined once", typeName, fieldName) - return err -} - -func ErrTypeUndefined(typeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf(UnknownTypeErrMsg, typeName) - return err -} - -func ErrInvalidOperationType(operationType ast.OperationType) (err ExternalError) { - err.Message = fmt.Sprintf("invalid operation type %d", int(operationType)) - return err -} - -func ErrOperationTypeUndefined(operationType ast.OperationType) (err ExternalError) { - err.Message = fmt.Sprintf("operation type %s is not defined; did you forget to merge the base schema?", operationType.Name()) - return err -} - -func ErrScalarTypeUndefined(scalarName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("scalar not defined: %s", scalarName) - return err -} - -func ErrInterfaceTypeUndefined(interfaceName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("interface type not defined: %s", interfaceName) - return err -} - -func ErrUnionTypeUndefined(unionName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("union type not defined: %s", unionName) - return err -} - -func ErrEnumTypeUndefined(enumName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("enum type not defined: %s", enumName) - return err -} - -func ErrInputObjectTypeUndefined(inputObjectName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("input object type not defined: %s", inputObjectName) - return err -} - -func ErrTypeNameMustBeUnique(typeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("there can be only one type named '%s'", typeName) - return err -} - -func ErrOperationNameMustBeUnique(operationName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("operation name must be unique: %s", operationName) - return err -} - -func ErrAnonymousOperationMustBeTheOnlyOperationInDocument() (err ExternalError) { - err.Message = "anonymous operation name the only operation in a graphql document" - return err -} - -func ErrRequiredOperationNameIsMissing() (err ExternalError) { - err.Message = "operation name is required when providing multiple operations" - return err -} - -func ErrOperationWithProvidedOperationNameNotFound(operationName string) (err ExternalError) { - err.Message = fmt.Sprintf("cannot find an operation with name: %s", operationName) - return err -} - -func ErrSubscriptionMustOnlyHaveOneRootSelection(subscriptionName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("subscription: %s must only have one root selection", subscriptionName) - return err -} - -func ErrFieldSelectionOnUnion(fieldName, unionName ast.ByteSlice) (err ExternalError) { - - err.Message = fmt.Sprintf("cannot select field: %s on union: %s", fieldName, unionName) - return err -} - -func ErrFieldsConflict(objectName, leftType, rightType ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("fields '%s' conflict because they return conflicting types '%s' and '%s'", objectName, leftType, rightType) - return err -} - -func ErrTypesForFieldMismatch(objectName, leftType, rightType ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("differing types '%s' and '%s' for objectName '%s'", leftType, rightType, objectName) - return err -} - -func ErrResponseOfDifferingTypesMustBeOfSameShape(leftObjectName, rightObjectName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("objects '%s' and '%s' on differing response types must be of same response shape", leftObjectName, rightObjectName) - return err -} - -func ErrDifferingFieldsOnPotentiallySameType(objectName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("differing fields for objectName '%s' on (potentially) same type", objectName) - return err -} - -func ErrFieldSelectionOnScalar(fieldName, scalarTypeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("cannot select field: %s on scalar %s", fieldName, scalarTypeName) - return err -} - -func ErrMissingFieldSelectionOnNonScalar(fieldName, enclosingTypeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("non scalar field: %s on type: %s must have selections", fieldName, enclosingTypeName) - return err -} - -func ErrArgumentNotDefinedOnDirective(argName, directiveName ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(UnknownArgumentOnDirectiveErrMsg, argName, directiveName) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrUnknownType(typeName ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(UnknownTypeErrMsg, typeName) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrMissingRequiredFieldOfInputObject(objName, fieldName, typeName ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(MissingRequiredFieldOfInputObjectErrMsg, objName, fieldName, typeName) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrUnknownFieldOfInputObject(objName, fieldName ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(UnknownFieldOfInputObjectErrMsg, objName, fieldName) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrDuplicatedFieldInputObject(fieldName ast.ByteSlice, first, duplicated position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(DuplicatedFieldInputObjectErrMsg, fieldName) - - err.Locations = []graphqlerrors.Location{ - { - Line: first.LineStart, - Column: first.CharStart, - }, - { - Line: duplicated.LineStart, - Column: duplicated.CharStart, - }, - } - - return err -} - -func ErrArgumentNotDefinedOnField(argName, typeName, fieldName ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(UnknownArgumentOnFieldErrMsg, argName, typeName, fieldName) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrNullValueDoesntSatisfyInputValueDefinition(inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NullValueErrMsg, inputType) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyEnum(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotEnumErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntExistsInEnum(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotAnEnumMemberErrMsg, value, inputType) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyType(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotCompatibleTypeErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueIsNotAnInputObjectType(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(ValueIsNotAnInputObjectTypeErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyString(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotStringErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyInt(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotIntegerErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrBigIntValueDoesntSatisfyInt(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(BigIntegerErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyFloat(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotFloatErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyBoolean(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotBooleanErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrValueDoesntSatisfyID(value, inputType ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(NotIDErrMsg, inputType, value) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrVariableTypeDoesntSatisfyInputValueDefinition(value, inputType, expectedType ast.ByteSlice, valuePos, variableDefinitionPos position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(`Variable "%v" of type "%v" used in position expecting type "%v".`, value, inputType, expectedType) - err.Locations = LocationsFromPosition(variableDefinitionPos, valuePos) - return err -} - -func ErrVariableNotDefinedOnOperation(variableName, operationName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("variable: %s not defined on operation: %s", variableName, operationName) - return err -} - -func ErrVariableDefinedButNeverUsed(variableName, operationName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("variable: %s defined on operation: %s but never used", variableName, operationName) - return err -} - -func ErrVariableMustBeUnique(variableName, operationName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("variable: %s must be unique per operation: %s", variableName, operationName) - return err -} - -func ErrVariableNotDefinedOnArgument(variableName, argumentName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("variable: %s not defined on argument: %s", variableName, argumentName) - return err -} - -func ErrVariableOfTypeIsNoValidInputValue(variableName, ofTypeName ast.ByteSlice, position position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(VariableIsNotInputTypeErrMsg, variableName, ofTypeName) - err.Locations = LocationsFromPosition(position) - - return err -} - -func ErrArgumentMustBeUnique(argName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("argument: %s must be unique", argName) - return err -} - -func ErrArgumentRequiredOnField(argName, fieldName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("argument: %s is required on field: %s but missing", argName, fieldName) - return err -} - -func ErrArgumentOnFieldMustNotBeNull(argName, fieldName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("argument: %s on field: %s must not be null", argName, fieldName) - return err -} - -func ErrFragmentSpreadFormsCycle(spreadName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("fragment spread: %s forms fragment cycle", spreadName) - return err -} - -func ErrInvalidFragmentSpread(fragmentName, fragmentTypeName, enclosingName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf( - "fragment spread: fragment %s must be spread on type %s and not type %s", - fragmentName, fragmentTypeName, enclosingName, - ) - return err -} - -func ErrFragmentDefinedButNotUsed(fragmentName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("fragment: %s defined but not used", fragmentName) - return err -} - -func ErrFragmentUndefined(fragmentName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("fragment: %s undefined", fragmentName) - return err -} - -func ErrInlineFragmentOnTypeDisallowed(onTypeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("inline fragment on type: %s disallowed", onTypeName) - return err -} - -func ErrInlineFragmentOnTypeMismatchEnclosingType(fragmentTypeName, enclosingTypeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("inline fragment on type: %s mismatches enclosing type: %s", fragmentTypeName, enclosingTypeName) - return err -} - -func ErrFragmentDefinitionOnTypeDisallowed(fragmentName, onTypeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("fragment: %s on type: %s disallowed", fragmentName, onTypeName) - return err -} - -func ErrFragmentDefinitionMustBeUnique(fragmentName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("fragment: %s must be unique per document", fragmentName) - return err -} - -func ErrDirectiveUndefined(directiveName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("directive: %s undefined", directiveName) - return err -} - -func ErrDirectiveNotAllowedOnNode(directiveName, nodeKindName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("directive: %s not allowed on node of kind: %s", directiveName, nodeKindName) - return err -} - -func ErrDirectiveMustBeUniquePerLocation(directiveName ast.ByteSlice, position, duplicatePosition position.Position) (err ExternalError) { - err.Message = fmt.Sprintf(`The directive "@%s" can only be used once at this location.`, directiveName) - if duplicatePosition.LineStart < position.LineStart || duplicatePosition.CharStart < position.CharStart { - err.Locations = LocationsFromPosition(duplicatePosition, position) - } else { - err.Locations = LocationsFromPosition(position, duplicatePosition) - } - - return err -} - -func ErrOnlyOneQueryTypeAllowed() (err ExternalError) { - err.Message = "there can be only one query type in schema" - return err -} - -func ErrOnlyOneMutationTypeAllowed() (err ExternalError) { - err.Message = "there can be only one mutation type in schema" - return err -} - -func ErrOnlyOneSubscriptionTypeAllowed() (err ExternalError) { - err.Message = "there can be only one subscription type in schema" - return err -} - -func ErrEnumValueNameMustBeUnique(enumName, enumValueName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("enum value '%s.%s' can only be defined once", enumName, enumValueName) - return err -} - -func ErrUnionMembersMustBeUnique(unionName, memberName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("union member '%s.%s' can only be defined once", unionName, memberName) - return err -} - -func ErrTransitiveInterfaceNotImplemented(typeName, transitiveInterfaceName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("type %s does not implement transitive interface %s", typeName, transitiveInterfaceName) - return err -} - -func ErrTransitiveInterfaceExtensionImplementingWithoutBody(interfaceExtensionName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("interface extension %s implementing interface without body", interfaceExtensionName) - return err -} - -func ErrTypeDoesNotImplementFieldFromInterface(typeName, interfaceName, fieldName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("type '%s' does not implement field '%s' from interface '%s'", typeName, fieldName, interfaceName) - return err -} - -func ErrImplementingTypeDoesNotHaveFields(typeName ast.ByteSlice) (err ExternalError) { - err.Message = fmt.Sprintf("type '%s' implements an interface but does not have any fields defined", typeName) - return err -} - -func ErrSharedTypesMustBeIdenticalToFederate(typeName string) (err ExternalError) { - err.Message = fmt.Sprintf("the shared type named '%s' must be identical in any subgraphs to federate", typeName) - return err -} - -func ErrEntitiesMustNotBeDuplicated(typeName string) (err ExternalError) { - err.Message = fmt.Sprintf("the entity named '%s' is defined in the subgraph(s) more than once", typeName) - return err -} - -func ErrSharedTypesMustNotBeExtended(typeName string) (err ExternalError) { - err.Message = fmt.Sprintf("the type named '%s' cannot be extended because it is a shared type", typeName) - return err -} - -func ErrExtensionOrphansMustResolveInSupergraph(extensionNameBytes []byte) (err ExternalError) { - err.Message = fmt.Sprintf("the extension orphan named '%s' was never resolved in the supergraph", extensionNameBytes) - return err -} - -func ErrTypeBodyMustNotBeEmpty(definitionType, typeName string) (err ExternalError) { - err.Message = fmt.Sprintf("the %s named '%s' is invalid due to an empty body", definitionType, typeName) - return err -} - -func ErrEntityExtensionMustHaveKeyDirective(typeName string) (err ExternalError) { - err.Message = fmt.Sprintf("an extension of the entity named '%s' does not have a key directive", typeName) - return err -} - -func ErrExtensionWithKeyDirectiveMustExtendEntity(typeName string) (err ExternalError) { - err.Message = fmt.Sprintf("the extension named '%s' has a key directive but there is no entity of the same name", typeName) - return err -} - -func ErrDuplicateFieldsMustBeIdentical(fieldName, parentName, typeOne, typeTwo string) (err ExternalError) { - err.Message = fmt.Sprintf("field '%s' on type '%s' is defined in multiple subgraphs "+ - "but the fields cannot be merged because the types of the fields are non-identical:\n"+ - "first subgraph: type '%s'\n second subgraph: type '%s'", fieldName, parentName, typeOne, typeTwo) - return err -} diff --git a/pkg/operationreport/externalerror_test.go b/pkg/operationreport/externalerror_test.go deleted file mode 100644 index ade31677b..000000000 --- a/pkg/operationreport/externalerror_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package operationreport - -import ( - "bytes" - "encoding/json" - "testing" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" -) - -func TestPath_MarshalJSON(t *testing.T) { - p1 := ast.PathItem{ - Kind: ast.ArrayIndex, - ArrayIndex: 1, - } - - data, err := json.Marshal(p1) - if err != nil { - t.Fatal(err) - } - - if string(data) != "1" { - t.Fatalf("want 1, got: %s", string(data)) - } - - var p2 ast.PathItem - err = json.Unmarshal([]byte("1"), &p2) - if err != nil { - t.Fatal(err) - } - - if p2.Kind != ast.ArrayIndex { - t.Fatalf("want ArrayIndex, got: %d", p2.Kind) - } - if p2.ArrayIndex != 1 { - t.Fatalf("want 1, got: %d", p2.ArrayIndex) - } - - var p3 ast.PathItem - err = json.Unmarshal([]byte("\"field\""), &p3) - if err != nil { - t.Fatal(err) - } - - if p3.Kind != ast.FieldName { - t.Fatalf("want FieldName, got: %d", p3.Kind) - } - if !bytes.Equal(p3.FieldName, []byte("field")) { - t.Fatalf("want field, got: %s", p3.FieldName) - } - - p4 := ast.PathItem{ - Kind: ast.FieldName, - FieldName: []byte("field"), - } - - data, err = json.Marshal(p4) - if err != nil { - t.Fatal(err) - } - - if string(data) != "\"field\"" { - t.Fatalf("want \"field\", got: %s", string(data)) - } - - var p5 ast.PathItem - err = json.Unmarshal([]byte("\"field"), &p5) - if err == nil { - t.Fatalf("want err, got nil") - } -} diff --git a/pkg/operationreport/operationreport.go b/pkg/operationreport/operationreport.go deleted file mode 100644 index c7d3ef201..000000000 --- a/pkg/operationreport/operationreport.go +++ /dev/null @@ -1,67 +0,0 @@ -// Package operationreport helps generating the errors object for a GraphQL Operation. -package operationreport - -import ( - "errors" - "fmt" -) - -type Report struct { - InternalErrors []error - ExternalErrors []ExternalError -} - -func (r Report) Error() string { - out := "" - for i := range r.InternalErrors { - if i != 0 { - out += "\n" - } - out += fmt.Sprintf("internal: %s", r.InternalErrors[i].Error()) - } - if len(out) > 0 && len(r.ExternalErrors) > 0 { - out += "\n" - } - for i := range r.ExternalErrors { - if i != 0 { - out += "\n" - } - out += fmt.Sprintf("external: %s, locations: %+v, path: %v", r.ExternalErrors[i].Message, r.ExternalErrors[i].Locations, r.ExternalErrors[i].Path) - } - return out -} - -func (r *Report) HasErrors() bool { - return len(r.InternalErrors) > 0 || len(r.ExternalErrors) > 0 -} - -func (r *Report) Reset() { - r.InternalErrors = r.InternalErrors[:0] - r.ExternalErrors = r.ExternalErrors[:0] -} - -func (r *Report) AddInternalError(err error) { - r.InternalErrors = append(r.InternalErrors, err) -} - -func (r *Report) AddExternalError(gqlError ExternalError) { - r.ExternalErrors = append(r.ExternalErrors, gqlError) -} - -type FormatExternalErrorMessage func(report *Report) string - -func ExternalErrorMessage(err error, formatFunction FormatExternalErrorMessage) (message string, ok bool) { - var report Report - if errors.As(err, &report) { - msg := formatFunction(&report) - return msg, true - } - return "", false -} - -func UnwrappedErrorMessage(err error) string { - for result := err; result != nil; result = errors.Unwrap(result) { - err = result - } - return err.Error() -} diff --git a/pkg/operationreport/operationreport_test.go b/pkg/operationreport/operationreport_test.go deleted file mode 100644 index afd5ef008..000000000 --- a/pkg/operationreport/operationreport_test.go +++ /dev/null @@ -1,63 +0,0 @@ -package operationreport - -import ( - "errors" - "fmt" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestExternalErrorMessage(t *testing.T) { - runExternalErrorMessage := func(err error, expectedSuccess bool, expectedMessage string) func(t *testing.T) { - return func(t *testing.T) { - msg, ok := ExternalErrorMessage(err, testFormatExternalErrorMessage) - assert.Equal(t, expectedSuccess, ok) - assert.Equal(t, expectedMessage, msg) - } - } - - t.Run("Passing a non-report returns false", - runExternalErrorMessage(testErrorLevel1, false, ""), - ) - - t.Run("Passing a report retrieves the inner error", - runExternalErrorMessage(testWrappedReport, true, externalErrorString), - ) -} - -func TestUnwrappedErrorMessage(t *testing.T) { - actual := UnwrappedErrorMessage(testErrorLevel2) - assert.Equal(t, testErrorString, actual) -} - -const ( - externalErrorString = "example external error 1" - testErrorString = "test error string" -) - -var testFormatExternalErrorMessage = func(report *Report) string { - if len(report.ExternalErrors) > 0 { - return report.ExternalErrors[0].Message - } - return "" -} - -var testReport = Report{ - InternalErrors: []error{ - errors.New("example internal error"), - }, - ExternalErrors: []ExternalError{ - { - Message: externalErrorString, - Path: nil, - Locations: nil, - }, - { - Message: "example external error 2", - }, - }, -} - -var testErrorLevel1 = errors.New(testErrorString) -var testErrorLevel2 = fmt.Errorf("level 2: %w", testErrorLevel1) -var testWrappedReport = fmt.Errorf("level 2: %w", testReport) diff --git a/pkg/playground/files/favicon.png b/pkg/playground/files/favicon.png deleted file mode 100644 index ccbd94b3bf99f76ec746642933ee375bcf642278..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5057 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 - - - - - - GraphQL Playground - - - - - - -

- - -
Loading - GraphQL Playground -
-
- - - - \ No newline at end of file diff --git a/pkg/playground/files/playground.js b/pkg/playground/files/playground.js deleted file mode 100644 index 4b2e40ef6..000000000 --- a/pkg/playground/files/playground.js +++ /dev/null @@ -1 +0,0 @@ -!function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="/",t(t.s=794)}([function(e,t,n){"use strict";e.exports=n(313)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){for(var n in e)t.hasOwnProperty(n)||(t[n]=e[n])}(n(87));var r=n(87);t.styled=r.default},function(e,t,n){!function(t,n){e.exports=n()}(0,function(){"use strict";function e(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}function t(e){for(var t=e.childNodes.length;t>0;--t)e.removeChild(e.firstChild);return e}function n(e,n){return t(e).appendChild(n)}function r(e,t,n,r){var i=document.createElement(e);if(n&&(i.className=n),r&&(i.style.cssText=r),"string"==typeof t)i.appendChild(document.createTextNode(t));else if(t)for(var o=0;o=t)return a+(t-o);a+=s-o,a+=n-a%n,o=s+1}}function f(e,t){for(var n=0;n=t)return r+Math.min(a,t-i);if(i+=o-r,i+=n-i%n,r=o+1,i>=t)return r}}function h(e){for(;Qa.length<=e;)Qa.push(m(Qa)+" ");return Qa[e]}function m(e){return e[e.length-1]}function g(e,t){for(var n=[],r=0;r"\x80"&&(e.toUpperCase()!=e.toLowerCase()||Ka.test(e))}function C(e,t){return t?!!(t.source.indexOf("\\w")>-1&&x(e))||t.test(e):x(e)}function E(e){for(var t in e)if(e.hasOwnProperty(t)&&e[t])return!1;return!0}function D(e){return e.charCodeAt(0)>=768&&Ja.test(e)}function w(e,t,n){for(;(n<0?t>0:tn?-1:1;;){if(t==n)return t;var i=(t+n)/2,o=r<0?Math.ceil(i):Math.floor(i);if(o==t)return e(o)?t:n;e(o)?n=o:t=o+r}}function k(e,t,n){var o=this;this.input=n,o.scrollbarFiller=r("div",null,"CodeMirror-scrollbar-filler"),o.scrollbarFiller.setAttribute("cm-not-content","true"),o.gutterFiller=r("div",null,"CodeMirror-gutter-filler"),o.gutterFiller.setAttribute("cm-not-content","true"),o.lineDiv=i("div",null,"CodeMirror-code"),o.selectionDiv=r("div",null,null,"position: relative; z-index: 1"),o.cursorDiv=r("div",null,"CodeMirror-cursors"),o.measure=r("div",null,"CodeMirror-measure"),o.lineMeasure=r("div",null,"CodeMirror-measure"),o.lineSpace=i("div",[o.measure,o.lineMeasure,o.selectionDiv,o.cursorDiv,o.lineDiv],null,"position: relative; outline: none");var a=i("div",[o.lineSpace],"CodeMirror-lines");o.mover=r("div",[a],null,"position: relative"),o.sizer=r("div",[o.mover],"CodeMirror-sizer"),o.sizerWidth=null,o.heightForcer=r("div",null,null,"position: absolute; height: "+Ga+"px; width: 1px;"),o.gutters=r("div",null,"CodeMirror-gutters"),o.lineGutter=null,o.scroller=r("div",[o.sizer,o.heightForcer,o.gutters],"CodeMirror-scroll"),o.scroller.setAttribute("tabIndex","-1"),o.wrapper=r("div",[o.scrollbarFiller,o.gutterFiller,o.scroller],"CodeMirror"),ba&&xa<8&&(o.gutters.style.zIndex=-1,o.scroller.style.paddingRight=0),Ca||ma&&Oa||(o.scroller.draggable=!0),e&&(e.appendChild?e.appendChild(o.wrapper):e(o.wrapper)),o.viewFrom=o.viewTo=t.first,o.reportedViewFrom=o.reportedViewTo=t.first,o.view=[],o.renderedView=null,o.externalMeasured=null,o.viewOffset=0,o.lastWrapHeight=o.lastWrapWidth=0,o.updateLineNumbers=null,o.nativeBarWidth=o.barHeight=o.barWidth=0,o.scrollbarsClipped=!1,o.lineNumWidth=o.lineNumInnerWidth=o.lineNumChars=null,o.alignWidgets=!1,o.cachedCharWidth=o.cachedTextHeight=o.cachedPaddingH=null,o.maxLine=null,o.maxLineLength=0,o.maxLineChanged=!1,o.wheelDX=o.wheelDY=o.wheelStartX=o.wheelStartY=null,o.shift=!1,o.selForContextMenu=null,o.activeTouch=null,n.init(o)}function A(e,t){if((t-=e.first)<0||t>=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?P(n,A(e,n).text.length):G(t,A(e,t.line).text.length)}function G(e,t){var n=e.ch;return null==n||n>t?P(e.line,t):n<0?P(e.line,0):e}function V(e,t){for(var n=[],r=0;r=t:o.to>t);(r||(r=[])).push(new W(a,o.from,u?null:o.to))}}return r}function X(e,t,n){var r;if(e)for(var i=0;i=t:o.to>t);if(s||o.from==t&&"bookmark"==a.type&&(!n||o.marker.insertLeft)){var u=null==o.from||(a.inclusiveLeft?o.from<=t:o.from0&&s)for(var C=0;C0)){var l=[u,1],p=M(c.from,s.from),d=M(c.to,s.to);(p<0||!a.inclusiveLeft&&!p)&&l.push({from:c.from,to:s.from}),(d>0||!a.inclusiveRight&&!d)&&l.push({from:s.to,to:c.to}),i.splice.apply(i,l),u+=l.length-3}}return i}function ne(e){var t=e.markedSpans;if(t){for(var n=0;nt)&&(!n||ae(n,o.marker)<0)&&(n=o.marker)}return n}function pe(e,t,n,r,i){var o=A(e,t),a=Xa&&o.markedSpans;if(a)for(var s=0;s=0&&p<=0||l<=0&&p>=0)&&(l<=0&&(u.marker.inclusiveRight&&i.inclusiveLeft?M(c.to,n)>=0:M(c.to,n)>0)||l>=0&&(u.marker.inclusiveRight&&i.inclusiveLeft?M(c.from,r)<=0:M(c.from,r)<0)))return!0}}}function fe(e){for(var t;t=ue(e);)e=t.find(-1,!0).line;return e}function de(e){for(var t;t=ce(e);)e=t.find(1,!0).line;return e}function he(e){for(var t,n;t=ce(e);)e=t.find(1,!0).line,(n||(n=[])).push(e);return n}function me(e,t){var n=A(e,t),r=fe(n);return n==r?t:F(r)}function ge(e,t){if(t>e.lastLine())return t;var n,r=A(e,t);if(!ye(e,r))return t;for(;n=ce(r);)r=n.find(1,!0).line;return F(r)+1}function ye(e,t){var n=Xa&&t.markedSpans;if(n)for(var r=void 0,i=0;it.maxLineLength&&(t.maxLineLength=n,t.maxLine=e)})}function Ee(e,t,n,r){if(!e)return r(t,n,"ltr",0);for(var i=!1,o=0;ot||t==n&&a.to==t)&&(r(Math.max(a.from,t),Math.min(a.to,n),1==a.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}function De(e,t,n){var r;Za=null;for(var i=0;it)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Za=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Za=i)}return null!=r?r:Za}function we(e,t){var n=e.order;return null==n&&(n=e.order=es(e.text,t)),n}function Se(e,t){return e._handlers&&e._handlers[t]||ts}function ke(e,t,n){if(e.removeEventListener)e.removeEventListener(t,n,!1);else if(e.detachEvent)e.detachEvent("on"+t,n);else{var r=e._handlers,i=r&&r[t];if(i){var o=f(i,n);o>-1&&(r[t]=i.slice(0,o).concat(i.slice(o+1)))}}}function Ae(e,t){var n=Se(e,t);if(n.length)for(var r=Array.prototype.slice.call(arguments,2),i=0;i0}function Fe(e){e.prototype.on=function(e,t){ns(this,e,t)},e.prototype.off=function(e,t){ke(this,e,t)}}function Ne(e){e.preventDefault?e.preventDefault():e.returnValue=!1}function Ie(e){e.stopPropagation?e.stopPropagation():e.cancelBubble=!0}function Le(e){return null!=e.defaultPrevented?e.defaultPrevented:0==e.returnValue}function Pe(e){Ne(e),Ie(e)}function Me(e){return e.target||e.srcElement}function je(e){var t=e.which;return null==t&&(1&e.button?t=1:2&e.button?t=3:4&e.button&&(t=2)),Fa&&e.ctrlKey&&1==t&&(t=3),t}function Re(e){if(null==Ua){var t=r("span","\u200b");n(e,r("span",[t,document.createTextNode("x")])),0!=e.firstChild.offsetHeight&&(Ua=t.offsetWidth<=1&&t.offsetHeight>2&&!(ba&&xa<8))}var i=Ua?r("span","\u200b"):r("span","\xa0",null,"display: inline-block; width: 1px; margin-right: -1px");return i.setAttribute("cm-text",""),i}function Be(e){if(null!=za)return za;var r=n(e,document.createTextNode("A\u062eA")),i=Pa(r,0,1).getBoundingClientRect(),o=Pa(r,1,2).getBoundingClientRect();return t(e),!(!i||i.left==i.right)&&(za=o.right-i.right<3)}function $e(e){if(null!=ss)return ss;var t=n(e,r("span","x")),i=t.getBoundingClientRect(),o=Pa(t,0,1).getBoundingClientRect();return ss=Math.abs(i.left-o.left)>1}function Ue(e,t){arguments.length>2&&(t.dependencies=Array.prototype.slice.call(arguments,2)),us[e]=t}function ze(e,t){cs[e]=t}function Ge(e){if("string"==typeof e&&cs.hasOwnProperty(e))e=cs[e];else if(e&&"string"==typeof e.name&&cs.hasOwnProperty(e.name)){var t=cs[e.name];"string"==typeof t&&(t={name:t}),e=b(t,e),e.name=t.name}else{if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+xml$/.test(e))return Ge("application/xml");if("string"==typeof e&&/^[\w\-]+\/[\w\-]+\+json$/.test(e))return Ge("application/json")}return"string"==typeof e?{name:e}:e||{name:"null"}}function Ve(e,t){t=Ge(t);var n=us[t.name];if(!n)return Ve(e,"text/plain");var r=n(e,t);if(ls.hasOwnProperty(t.name)){var i=ls[t.name];for(var o in i)i.hasOwnProperty(o)&&(r.hasOwnProperty(o)&&(r["_"+o]=r[o]),r[o]=i[o])}if(r.name=t.name,t.helperType&&(r.helperType=t.helperType),t.modeProps)for(var a in t.modeProps)r[a]=t.modeProps[a];return r}function qe(e,t){l(t,ls.hasOwnProperty(e)?ls[e]:ls[e]={})}function He(e,t){if(!0===t)return t;if(e.copyState)return e.copyState(t);var n={};for(var r in t){var i=t[r];i instanceof Array&&(i=i.concat([])),n[r]=i}return n}function We(e,t){for(var n;e.innerMode&&(n=e.innerMode(t))&&n.mode!=e;)t=n.state,e=n.mode;return n||{mode:e,state:t}}function Qe(e,t,n){return!e.startState||e.startState(t,n)}function Ke(e,t,n,r){var i=[e.state.modeGen],o={};rt(e,t.text,e.doc.mode,n,function(e,t){return i.push(e,t)},o,r);for(var a=n.state,s=0;se&&i.splice(u,1,e,i[u+1],r),u+=2,c=Math.min(e,r)}if(t)if(s.opaque)i.splice(n,u-n,e,"overlay "+t),u=n+2;else for(;ne.options.maxHighlightLength&&He(e.doc.mode,r.state),o=Ke(e,t,r);i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))}return t.styles}function Ye(e,t,n){var r=e.doc,i=e.display;if(!r.mode.startState)return new ds(r,!0,t);var o=it(e,t,n),a=o>r.first&&A(r,o-1).stateAfter,s=a?ds.fromSaved(r,a,o):new ds(r,Qe(r.mode),o);return r.iter(o,t,function(n){Xe(e,n.text,s);var r=s.line;n.stateAfter=r==t-1||r%5==0||r>=i.viewFrom&&rt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}function tt(e,t,n,r){var i,o=e.doc,a=o.mode;t=z(o,t);var s,u=A(o,t.line),c=Ye(e,t.line,n),l=new ps(u.text,e.options.tabSize,c);for(r&&(s=[]);(r||l.pose.options.maxHighlightLength?(s=!1,a&&Xe(e,t,r,p.pos),p.pos=t.length,u=null):u=nt(et(n,p,r.state,f),o),f){var d=f[0].name;d&&(u="m-"+(u?d+" "+u:d))}if(!s||l!=u){for(;ca;--s){if(s<=o.first)return o.first;var u=A(o,s-1),c=u.stateAfter;if(c&&(!n||s+(c instanceof fs?c.lookAhead:0)<=o.modeFrontier))return s;var l=p(u.text,null,e.options.tabSize);(null==i||r>l)&&(i=s-1,r=l)}return i}function ot(e,t){if(e.modeFrontier=Math.min(e.modeFrontier,t),!(e.highlightFrontiern;r--){var i=A(e,r).stateAfter;if(i&&(!(i instanceof fs)||r+i.lookAhead1&&!/ /.test(e))return e;for(var n=t,r="",i=0;ic&&p.from<=c));f++);if(p.to>=l)return e(n,r,i,o,a,s,u);e(n,r.slice(0,p.to-c),i,o,null,s,u),o=null,r=r.slice(p.to-c),c=p.to}}}function ht(e,t,n,r){var i=!r&&n.widgetNode;i&&e.map.push(e.pos,e.pos+t,i),!r&&e.cm.display.input.needsContentAttribute&&(i||(i=e.content.appendChild(document.createElement("span"))),i.setAttribute("cm-marker",n.id)),i&&(e.cm.display.input.setUneditable(i),e.content.appendChild(i)),e.pos+=t,e.trailingSpace=!1}function mt(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var a,s,u,c,l,p,f,d=i.length,h=0,m=1,g="",y=0;;){if(y==h){u=c=l=p=s="",f=null,y=1/0;for(var v=[],b=void 0,x=0;xh||E.collapsed&&C.to==h&&C.from==h)?(null!=C.to&&C.to!=h&&y>C.to&&(y=C.to,c=""),E.className&&(u+=" "+E.className),E.css&&(s=(s?s+";":"")+E.css),E.startStyle&&C.from==h&&(l+=" "+E.startStyle),E.endStyle&&C.to==y&&(b||(b=[])).push(E.endStyle,C.to),E.title&&!p&&(p=E.title),E.collapsed&&(!f||ae(f.marker,E)<0)&&(f=C)):C.from>h&&y>C.from&&(y=C.from)}if(b)for(var D=0;D=d)break;for(var S=Math.min(d,y);;){if(g){var k=h+g.length;if(!f){var A=k>S?g.slice(0,S-h):g;t.addToken(t,A,a?a+u:u,l,h+A.length==y?c:"",p,s)}if(k>=S){g=g.slice(S-h),h=S;break}h=k,l=""}g=i.slice(o,o=n[m++]),a=ut(n[m++],t.cm.options)}}else for(var _=1;_2&&o.push((u.bottom+c.top)/2-n.top)}}o.push(n.bottom-n.top)}}function Vt(e,t,n){if(e.line==t)return{map:e.measure.map,cache:e.measure.cache};for(var r=0;rn)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}function qt(e,t){t=fe(t);var r=F(t),i=e.display.externalMeasured=new gt(e.doc,t,r);i.lineN=r;var o=i.built=ct(e,i);return i.text=o.pre,n(e.display.lineMeasure,o.pre),i}function Ht(e,t,n,r){return Kt(e,Qt(e,t),n,r)}function Wt(e,t){if(t>=e.display.viewFrom&&t=n.lineN&&tt)&&(o=u-s,i=o-1,t>=u&&(a="right")),null!=i){if(r=e[c+2],s==u&&n==(r.insertLeft?"left":"right")&&(a=n),"left"==n&&0==i)for(;c&&e[c-2]==e[c-3]&&e[c-1].insertLeft;)r=e[2+(c-=3)],a="left";if("right"==n&&i==u-s)for(;c=0&&(n=e[i]).left==n.right;i--);return n}function Xt(e,t,n,r){var i,o=Jt(t.map,n,r),a=o.node,s=o.start,u=o.end,c=o.collapse;if(3==a.nodeType){for(var l=0;l<4;l++){for(;s&&D(t.line.text.charAt(o.coverStart+s));)--s;for(;o.coverStart+u0&&(c=r="right");var p;i=e.options.lineWrapping&&(p=a.getClientRects()).length>1?p["right"==r?p.length-1:0]:a.getBoundingClientRect()}if(ba&&xa<9&&!s&&(!i||!i.left&&!i.right)){var f=a.parentNode.getClientRects()[0];i=f?{left:f.left,right:f.left+Cn(e.display),top:f.top,bottom:f.bottom}:Cs}for(var d=i.top-t.rect.top,h=i.bottom-t.rect.top,m=(d+h)/2,g=t.view.measure.heights,y=0;y=r.text.length?(c=r.text.length,l="before"):c<=0&&(c=0,l="after"),!u)return a("before"==l?c-1:c,"before"==l);var p=De(u,c,l),f=Za,d=s(c,p,"before"==l);return null!=f&&(d.other=s(c,f,"before"!=l)),d}function pn(e,t){var n=0;t=z(e.doc,t),e.options.lineWrapping||(n=Cn(e.display)*t.ch);var r=A(e.doc,t.line),i=be(r)+jt(e.display);return{left:n,right:n,top:i,bottom:i+r.height}}function fn(e,t,n,r,i){var o=P(e,t,n);return o.xRel=i,r&&(o.outside=!0),o}function dn(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return fn(r.first,0,null,!0,-1);var i=N(r,n),o=r.first+r.size-1;if(i>o)return fn(r.first+r.size-1,A(r,o).text.length,null,!0,1);t<0&&(t=0);for(var a=A(r,i);;){var s=yn(e,a,i,t,n),u=le(a,s.ch+(s.xRel>0?1:0));if(!u)return s;var c=u.find(1);if(c.line==i)return c;a=A(r,i=c.line)}}function hn(e,t,n,r){r-=an(t);var i=t.text.length,o=S(function(t){return Kt(e,n,t-1).bottom<=r},i,0);return i=S(function(t){return Kt(e,n,t).top>r},o,i),{begin:o,end:i}}function mn(e,t,n,r){return n||(n=Qt(e,t)),hn(e,t,n,sn(e,t,Kt(e,n,r),"line").top)}function gn(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function yn(e,t,n,r,i){i-=be(t);var o=Qt(e,t),a=an(t),s=0,u=t.text.length,c=!0,l=we(t,e.doc.direction);if(l){var p=(e.options.lineWrapping?bn:vn)(e,t,n,o,l,r,i);c=1!=p.level,s=c?p.from:p.to-1,u=c?p.to:p.from-1}var f,d,h=null,m=null,g=S(function(t){var n=Kt(e,o,t);return n.top+=a,n.bottom+=a,!!gn(n,r,i,!1)&&(n.top<=i&&n.left<=r&&(h=t,m=n),!0)},s,u),y=!1;if(m){var v=r-m.left=x.bottom}return g=w(t.text,g,1),fn(n,g,d,y,r-f)}function vn(e,t,n,r,i,o,a){var s=S(function(s){var u=i[s],c=1!=u.level;return gn(ln(e,P(n,c?u.to:u.from,c?"before":"after"),"line",t,r),o,a,!0)},0,i.length-1),u=i[s];if(s>0){var c=1!=u.level,l=ln(e,P(n,c?u.from:u.to,c?"after":"before"),"line",t,r);gn(l,o,a,!0)&&l.top>a&&(u=i[s-1])}return u}function bn(e,t,n,r,i,o,a){var s=hn(e,t,r,a),u=s.begin,c=s.end;/\s/.test(t.text.charAt(c-1))&&c--;for(var l=null,p=null,f=0;f=c||d.to<=u)){var h=1!=d.level,m=Kt(e,r,h?Math.min(c,d.to)-1:Math.max(u,d.from)).right,g=mg)&&(l=d,p=g)}}return l||(l=i[i.length-1]),l.fromc&&(l={from:l.from,to:c,level:l.level}),l}function xn(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==gs){gs=r("pre");for(var i=0;i<49;++i)gs.appendChild(document.createTextNode("x")),gs.appendChild(r("br"));gs.appendChild(document.createTextNode("x"))}n(e.measure,gs);var o=gs.offsetHeight/50;return o>3&&(e.cachedTextHeight=o),t(e.measure),o||1}function Cn(e){if(null!=e.cachedCharWidth)return e.cachedCharWidth;var t=r("span","xxxxxxxxxx"),i=r("pre",[t]);n(e.measure,i);var o=t.getBoundingClientRect(),a=(o.right-o.left)/10;return a>2&&(e.cachedCharWidth=a),a||10}function En(e){for(var t=e.display,n={},r={},i=t.gutters.clientLeft,o=t.gutters.firstChild,a=0;o;o=o.nextSibling,++a)n[e.options.gutters[a]]=o.offsetLeft+o.clientLeft+i,r[e.options.gutters[a]]=o.clientWidth;return{fixedPos:Dn(t),gutterTotalWidth:t.gutters.offsetWidth,gutterLeft:n,gutterWidth:r,wrapperWidth:t.wrapper.clientWidth}}function Dn(e){return e.scroller.getBoundingClientRect().left-e.sizer.getBoundingClientRect().left}function wn(e){var t=xn(e.display),n=e.options.lineWrapping,r=n&&Math.max(5,e.display.scroller.clientWidth/Cn(e.display)-3);return function(i){if(ye(e.doc,i))return 0;var o=0;if(i.widgets)for(var a=0;a=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;r=e.display.viewTo||s.to().line0?t.blinker=setInterval(function(){return t.cursorDiv.style.visibility=(n=!n)?"":"hidden"},e.options.cursorBlinkRate):e.options.cursorBlinkRate<0&&(t.cursorDiv.style.visibility="hidden")}}function Ln(e){e.state.focused||(e.display.input.focus(),Mn(e))}function Pn(e){e.state.delayingBlurEvent=!0,setTimeout(function(){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1,jn(e))},100)}function Mn(e,t){e.state.delayingBlurEvent&&(e.state.delayingBlurEvent=!1),"nocursor"!=e.options.readOnly&&(e.state.focused||(Ae(e,"focus",e,t),e.state.focused=!0,s(e.display.wrapper,"CodeMirror-focused"),e.curOp||e.display.selForContextMenu==e.doc.sel||(e.display.input.reset(),Ca&&setTimeout(function(){return e.display.input.reset(!0)},20)),e.display.input.receivedFocus()),In(e))}function jn(e,t){e.state.delayingBlurEvent||(e.state.focused&&(Ae(e,"blur",e,t),e.state.focused=!1,Ra(e.display.wrapper,"CodeMirror-focused")),clearInterval(e.display.blinker),setTimeout(function(){e.state.focused||(e.display.shift=!1)},150))}function Rn(e){for(var t=e.display,n=t.lineDiv.offsetTop,r=0;r.005||u<-.005)&&(O(i.line,o),Bn(i.line),i.rest))for(var c=0;c=a&&(o=N(t,be(A(t,u))-e.wrapper.clientHeight),a=u)}return{from:o,to:Math.max(a,o+1)}}function Un(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=Dn(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",a=0;a(window.innerHeight||document.documentElement.clientHeight)&&(o=!1),null!=o&&!Aa){var a=r("div","\u200b",null,"position: absolute;\n top: "+(t.top-n.viewOffset-jt(e.display))+"px;\n height: "+(t.bottom-t.top+$t(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;");e.display.lineSpace.appendChild(a),a.scrollIntoView(o),e.display.lineSpace.removeChild(a)}}}function Vn(e,t,n,r){null==r&&(r=0);var i;e.options.lineWrapping||t!=n||(t=t.ch?P(t.line,"before"==t.sticky?t.ch-1:t.ch,"after"):t,n="before"==t.sticky?P(t.line,t.ch+1,"before"):t);for(var o=0;o<5;o++){var a=!1,s=ln(e,t),u=n&&n!=t?ln(e,n):s;i={left:Math.min(s.left,u.left),top:Math.min(s.top,u.top)-r,right:Math.max(s.left,u.left),bottom:Math.max(s.bottom,u.bottom)+r};var c=Hn(e,i),l=e.doc.scrollTop,p=e.doc.scrollLeft;if(null!=c.scrollTop&&(Zn(e,c.scrollTop),Math.abs(e.doc.scrollTop-l)>1&&(a=!0)),null!=c.scrollLeft&&(tr(e,c.scrollLeft),Math.abs(e.doc.scrollLeft-p)>1&&(a=!0)),!a)break}return i}function qn(e,t){var n=Hn(e,t);null!=n.scrollTop&&Zn(e,n.scrollTop),null!=n.scrollLeft&&tr(e,n.scrollLeft)}function Hn(e,t){var n=e.display,r=xn(e.display);t.top<0&&(t.top=0);var i=e.curOp&&null!=e.curOp.scrollTop?e.curOp.scrollTop:n.scroller.scrollTop,o=zt(e),a={};t.bottom-t.top>o&&(t.bottom=t.top+o);var s=e.doc.height+Rt(n),u=t.tops-r;if(t.topi+o){var l=Math.min(t.top,(c?s:t.bottom)-o);l!=i&&(a.scrollTop=l)}var p=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft,f=Ut(e)-(e.options.fixedGutter?n.gutters.offsetWidth:0),d=t.right-t.left>f;return d&&(t.right=t.left+f),t.left<10?a.scrollLeft=0:t.leftf+p-3&&(a.scrollLeft=t.right+(d?0:10)-f),a}function Wn(e,t){null!=t&&(Yn(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc.scrollTop:e.curOp.scrollTop)+t)}function Qn(e){Yn(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Kn(e,t,n){null==t&&null==n||Yn(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Jn(e,t){Yn(e),e.curOp.scrollToPos=t}function Yn(e){var t=e.curOp.scrollToPos;if(t){e.curOp.scrollToPos=null;Xn(e,pn(e,t.from),pn(e,t.to),t.margin)}}function Xn(e,t,n,r){var i=Hn(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Kn(e,i.scrollLeft,i.scrollTop)}function Zn(e,t){Math.abs(e.doc.scrollTop-t)<2||(ma||Fr(e,{top:t}),er(e,t,!0),ma&&Fr(e),wr(e,100))}function er(e,t,n){t=Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t),(e.display.scroller.scrollTop!=t||n)&&(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function tr(e,t,n,r){t=Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,Un(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function nr(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Rt(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+$t(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}function rr(e,t){t||(t=nr(e));var n=e.display.barWidth,r=e.display.barHeight;ir(e,t);for(var i=0;i<4&&n!=e.display.barWidth||r!=e.display.barHeight;i++)n!=e.display.barWidth&&e.options.lineWrapping&&Rn(e),ir(e,nr(e)),n=e.display.barWidth,r=e.display.barHeight}function ir(e,t){var n=e.display,r=n.scrollbars.update(t);n.sizer.style.paddingRight=(n.barWidth=r.right)+"px",n.sizer.style.paddingBottom=(n.barHeight=r.bottom)+"px",n.heightForcer.style.borderBottom=r.bottom+"px solid transparent",r.right&&r.bottom?(n.scrollbarFiller.style.display="block",n.scrollbarFiller.style.height=r.bottom+"px",n.scrollbarFiller.style.width=r.right+"px"):n.scrollbarFiller.style.display="",r.bottom&&e.options.coverGutterNextToScrollbar&&e.options.fixedGutter?(n.gutterFiller.style.display="block",n.gutterFiller.style.height=r.bottom+"px",n.gutterFiller.style.width=t.gutterWidth+"px"):n.gutterFiller.style.display=""}function or(e){e.display.scrollbars&&(e.display.scrollbars.clear(),e.display.scrollbars.addClass&&Ra(e.display.wrapper,e.display.scrollbars.addClass)),e.display.scrollbars=new ws[e.options.scrollbarStyle](function(t){e.display.wrapper.insertBefore(t,e.display.scrollbarFiller),ns(t,"mousedown",function(){e.state.focused&&setTimeout(function(){return e.display.input.focus()},0)}),t.setAttribute("cm-not-content","true")},function(t,n){"horizontal"==n?tr(e,t):Zn(e,t)},e),e.display.scrollbars.addClass&&s(e.display.wrapper,e.display.scrollbars.addClass)}function ar(e){e.curOp={cm:e,viewChanged:!1,startHeight:e.doc.height,forceUpdate:!1,updateInput:null,typing:!1,changeObjs:null,cursorActivityHandlers:null,cursorActivityCalled:0,selectionChanged:!1,updateMaxLine:!1,scrollLeft:null,scrollTop:null,scrollToPos:null,focus:!1,id:++Ss},vt(e.curOp)}function sr(e){xt(e.curOp,function(e){for(var t=0;t=n.viewTo)||n.maxLineChanged&&t.options.lineWrapping,e.update=e.mustUpdate&&new ks(t,e.mustUpdate&&{top:e.scrollTop,ensure:e.scrollToPos},e.forceUpdate)}function lr(e){e.updatedDisplay=e.mustUpdate&&Tr(e.cm,e.update)}function pr(e){var t=e.cm,n=t.display;e.updatedDisplay&&Rn(t),e.barMeasure=nr(t),n.maxLineChanged&&!t.options.lineWrapping&&(e.adjustWidthTo=Ht(t,n.maxLine,n.maxLine.text.length).left+3,t.display.sizerWidth=e.adjustWidthTo,e.barMeasure.scrollWidth=Math.max(n.scroller.clientWidth,n.sizer.offsetLeft+e.adjustWidthTo+$t(t)+t.display.barWidth),e.maxScrollLeft=Math.max(0,n.sizer.offsetLeft+e.adjustWidthTo-Ut(t))),(e.updatedDisplay||e.selectionChanged)&&(e.preparedSelection=n.input.prepareSelection())}function fr(e){var t=e.cm;null!=e.adjustWidthTo&&(t.display.sizer.style.minWidth=e.adjustWidthTo+"px",e.maxScrollLeftt)&&(i.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=i.viewTo)Xa&&me(e.doc,t)i.viewFrom?xr(e):(i.viewFrom+=r,i.viewTo+=r);else if(t<=i.viewFrom&&n>=i.viewTo)xr(e);else if(t<=i.viewFrom){var o=Cr(e,n,n+r,1);o?(i.view=i.view.slice(o.index),i.viewFrom=o.lineN,i.viewTo+=r):xr(e)}else if(n>=i.viewTo){var a=Cr(e,t,t,-1);a?(i.view=i.view.slice(0,a.index),i.viewTo=a.lineN):xr(e)}else{var s=Cr(e,t,t,-1),u=Cr(e,n,n+r,1);s&&u?(i.view=i.view.slice(0,s.index).concat(yt(e,s.lineN,u.lineN)).concat(i.view.slice(u.index)),i.viewTo+=r):xr(e)}var c=i.externalMeasured;c&&(n=i.lineN&&t=r.viewTo)){var o=r.view[An(e,t)];if(null!=o.node){var a=o.changes||(o.changes=[]);-1==f(a,n)&&a.push(n)}}}function xr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function Cr(e,t,n,r){var i,o=An(e,t),a=e.display.view;if(!Xa||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,u=0;u0){if(o==a.length-1)return null;i=s+a[o].size-t,o++}else i=s-t;t+=i,n+=i}for(;me(e.doc,n)!=n;){if(o==(r<0?0:a.length-1))return null;n+=r*a[o-(r<0?1:0)].size,o+=r}return{index:o,lineN:n}}function Er(e,t,n){var r=e.display;0==r.view.length||t>=r.viewTo||n<=r.viewFrom?(r.view=yt(e,t,n),r.viewFrom=t):(r.viewFrom>t?r.view=yt(e,t,r.viewFrom).concat(r.view):r.viewFromn&&(r.view=r.view.slice(0,An(e,n)))),r.viewTo=n}function Dr(e){for(var t=e.display.view,n=0,r=0;r=e.display.viewTo)){var n=+new Date+e.options.workTime,r=Ye(e,t.highlightFrontier),i=[];t.iter(r.line,Math.min(t.first+t.size,e.display.viewTo+500),function(o){if(r.line>=e.display.viewFrom){var a=o.styles,s=o.text.length>e.options.maxHighlightLength?He(t.mode,r.state):null,u=Ke(e,o,r,!0);s&&(r.state=s),o.styles=u.styles;var c=o.styleClasses,l=u.classes;l?o.styleClasses=l:c&&(o.styleClasses=null);for(var p=!a||a.length!=o.styles.length||c!=l&&(!c||!l||c.bgClass!=l.bgClass||c.textClass!=l.textClass),f=0;!p&&fn)return wr(e,e.options.workDelay),!0}),t.highlightFrontier=r.line,t.modeFrontier=Math.max(t.modeFrontier,r.line),i.length&&hr(e,function(){for(var t=0;t=r.viewFrom&&n.visible.to<=r.viewTo&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo)&&r.renderedView==r.view&&0==Dr(e))return!1;zn(e)&&(xr(e),n.dims=En(e));var o=i.first+i.size,a=Math.max(n.visible.from-e.options.viewportMargin,i.first),s=Math.min(o,n.visible.to+e.options.viewportMargin);r.viewFroms&&r.viewTo-s<20&&(s=Math.min(o,r.viewTo)),Xa&&(a=me(e.doc,a),s=ge(e.doc,s));var u=a!=r.viewFrom||s!=r.viewTo||r.lastWrapHeight!=n.wrapperHeight||r.lastWrapWidth!=n.wrapperWidth;Er(e,a,s),r.viewOffset=be(A(e.doc,r.viewFrom)),e.display.mover.style.top=r.viewOffset+"px";var c=Dr(e);if(!u&&0==c&&!n.force&&r.renderedView==r.view&&(null==r.updateLineNumbers||r.updateLineNumbers>=r.viewTo))return!1;var l=Ar(e);return c>4&&(r.lineDiv.style.display="none"),Nr(e,r.updateLineNumbers,n.dims),c>4&&(r.lineDiv.style.display=""),r.renderedView=r.view,_r(l),t(r.cursorDiv),t(r.selectionDiv),r.gutters.style.height=r.sizer.style.minHeight=0,u&&(r.lastWrapHeight=n.wrapperHeight,r.lastWrapWidth=n.wrapperWidth,wr(e,400)),r.updateLineNumbers=null,!0}function Or(e,t){for(var n=t.viewport,r=!0;(r&&e.options.lineWrapping&&t.oldDisplayWidth!=Ut(e)||(n&&null!=n.top&&(n={top:Math.min(e.doc.height+Rt(e.display)-zt(e),n.top)}),t.visible=$n(e.display,e.doc,n),!(t.visible.from>=e.display.viewFrom&&t.visible.to<=e.display.viewTo)))&&Tr(e,t);r=!1){Rn(e);var i=nr(e);_n(e),rr(e,i),Lr(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function Fr(e,t){var n=new ks(e,t);if(Tr(e,n)){Rn(e),Or(e,n);var r=nr(e);_n(e),rr(e,r),Lr(e,r),n.finish()}}function Nr(e,n,r){function i(t){var n=t.nextSibling;return Ca&&Fa&&e.display.currentWheelTarget==t?t.style.display="none":t.parentNode.removeChild(t),n}for(var o=e.display,a=e.options.lineNumbers,s=o.lineDiv,u=s.firstChild,c=o.view,l=o.viewFrom,p=0;p-1&&(h=!1),Dt(e,d,l,r)),h&&(t(d.lineNumber),d.lineNumber.appendChild(document.createTextNode(L(e.options,l)))),u=d.node.nextSibling}else{var m=Ft(e,d,l,r);s.insertBefore(m,u)}l+=d.size}for(;u;)u=i(u)}function Ir(e){var t=e.display.gutters.offsetWidth;e.display.sizer.style.marginLeft=t+"px"}function Lr(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+$t(e)+"px"}function Pr(e){var n=e.display.gutters,i=e.options.gutters;t(n);for(var o=0;o-1&&!e.lineNumbers&&(e.gutters=e.gutters.slice(0),e.gutters.splice(t,1))}function jr(e){var t=e.wheelDeltaX,n=e.wheelDeltaY;return null==t&&e.detail&&e.axis==e.HORIZONTAL_AXIS&&(t=e.detail),null==n&&e.detail&&e.axis==e.VERTICAL_AXIS?n=e.detail:null==n&&(n=e.wheelDelta),{x:t,y:n}}function Rr(e){var t=jr(e);return t.x*=_s,t.y*=_s,t}function Br(e,t){var n=jr(t),r=n.x,i=n.y,o=e.display,a=o.scroller,s=a.scrollWidth>a.clientWidth,u=a.scrollHeight>a.clientHeight;if(r&&s||i&&u){if(i&&Fa&&Ca)e:for(var c=t.target,l=o.view;c!=a;c=c.parentNode)for(var p=0;p=0){var a=$(o.from(),i.from()),s=B(o.to(),i.to()),u=o.empty()?i.from()==i.head:o.from()==o.head;r<=t&&--t,e.splice(--r,2,new Os(u?s:a,u?a:s))}}return new Ts(e,t)}function Ur(e,t){return new Ts([new Os(e,t||e)],0)}function zr(e){return e.text?P(e.from.line+e.text.length-1,m(e.text).length+(1==e.text.length?e.from.ch:0)):e.to}function Gr(e,t){if(M(e,t.from)<0)return e;if(M(e,t.to)<=0)return zr(t);var n=e.line+t.text.length-(t.to.line-t.from.line)-1,r=e.ch;return e.line==t.to.line&&(r+=zr(t).ch-t.to.ch),P(n,r)}function Vr(e,t){for(var n=[],r=0;r1&&e.remove(s.line+1,h-1),e.insert(s.line+1,v)}Ct(e,"change",e,t)}function Yr(e,t,n){function r(e,i,o){if(e.linked)for(var a=0;a1&&!e.done[e.done.length-2].ranges?(e.done.pop(),m(e.done)):void 0}function oi(e,t,n,r){var i=e.history;i.undone.length=0;var o,a,s=+new Date;if((i.lastOp==r||i.lastOrigin==t.origin&&t.origin&&("+"==t.origin.charAt(0)&&i.lastModTime>s-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=ii(i,i.lastOp==r)))a=m(o.changes),0==M(t.from,t.to)&&0==M(t.from,a.to)?a.to=zr(t):o.changes.push(ni(e,t));else{var u=m(i.done);for(u&&u.ranges||ui(e.sel,i.done),o={changes:[ni(e,t)],generation:i.generation},i.done.push(o);i.done.length>i.undoDepth;)i.done.shift(),i.done[0].ranges||i.done.shift()}i.done.push(n),i.generation=++i.maxGeneration,i.lastModTime=i.lastSelTime=s,i.lastOp=i.lastSelOp=r,i.lastOrigin=i.lastSelOrigin=t.origin,a||Ae(e,"historyAdded")}function ai(e,t,n,r){var i=t.charAt(0);return"*"==i||"+"==i&&n.ranges.length==r.ranges.length&&n.somethingSelected()==r.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)}function si(e,t,n,r){var i=e.history,o=r&&r.origin;n==i.lastSelOp||o&&i.lastSelOrigin==o&&(i.lastModTime==i.lastSelTime&&i.lastOrigin==o||ai(e,o,m(i.done),t))?i.done[i.done.length-1]=t:ui(t,i.done),i.lastSelTime=+new Date,i.lastSelOrigin=o,i.lastSelOp=n,r&&!1!==r.clearRedo&&ri(i.undone)}function ui(e,t){var n=m(t);n&&n.ranges&&n.equals(e)||t.push(e)}function ci(e,t,n,r){var i=t["spans_"+e.id],o=0;e.iter(Math.max(e.first,n),Math.min(e.first+e.size,r),function(n){n.markedSpans&&((i||(i=t["spans_"+e.id]={}))[o]=n.markedSpans),++o})}function li(e){if(!e)return null;for(var t,n=0;n-1&&(m(s)[p]=c[p],delete c[p])}}}return r}function hi(e,t,n,r){if(r){var i=e.anchor;if(n){var o=M(t,i)<0;o!=M(n,i)<0?(i=t,t=n):o!=M(t,n)<0&&(t=n)}return new Os(i,t)}return new Os(n||t,t)}function mi(e,t,n,r,i){null==i&&(i=e.cm&&(e.cm.display.shift||e.extend)),Ci(e,new Ts([hi(e.sel.primary(),t,n,i)],0),r)}function gi(e,t,n){for(var r=[],i=e.cm&&(e.cm.display.shift||e.extend),o=0;o=t.ch:s.to>t.ch))){if(i&&(Ae(u,"beforeCursorEnter"),u.explicitlyCleared)){if(o.markedSpans){--a;continue}break}if(!u.atomic)continue;if(n){var c=u.find(r<0?1:-1),l=void 0;if((r<0?u.inclusiveRight:u.inclusiveLeft)&&(c=_i(e,c,-r,c&&c.line==t.line?o:null)),c&&c.line==t.line&&(l=M(c,n))&&(r<0?l<0:l>0))return ki(e,c,t,r,i)}var p=u.find(r<0?-1:1);return(r<0?u.inclusiveLeft:u.inclusiveRight)&&(p=_i(e,p,r,p.line==t.line?o:null)),p?ki(e,p,t,r,i):null}}return t}function Ai(e,t,n,r,i){var o=r||1,a=ki(e,t,n,o,i)||!i&&ki(e,t,n,o,!0)||ki(e,t,n,-o,i)||!i&&ki(e,t,n,-o,!0);return a||(e.cantEdit=!0,P(e.first,0))}function _i(e,t,n,r){return n<0&&0==t.ch?t.line>e.first?z(e,P(t.line-1)):null:n>0&&t.ch==(r||A(e,t.line)).text.length?t.line=0;--i)Ni(e,{from:r[i].from,to:r[i].to,text:i?[""]:t.text,origin:t.origin});else Ni(e,t)}}function Ni(e,t){if(1!=t.text.length||""!=t.text[0]||0!=M(t.from,t.to)){var n=Vr(e,t);oi(e,t,n,e.cm?e.cm.curOp.id:NaN),Pi(e,t,n,Z(e,t));var r=[];Yr(e,function(e,n){n||-1!=f(r,e.history)||($i(e.history,t),r.push(e.history)),Pi(e,t,null,Z(e,t))})}}function Ii(e,t,n){var r=e.cm&&e.cm.state.suppressEdits;if(!r||n){for(var i,o=e.history,a=e.sel,s="undo"==t?o.done:o.undone,u="undo"==t?o.undone:o.done,c=0;c=0;--d){var h=function(n){var r=i.changes[n];if(r.origin=t,p&&!Oi(e,r,!1))return s.length=0,{};l.push(ni(e,r));var o=n?Vr(e,r):m(s);Pi(e,r,o,fi(e,r)),!n&&e.cm&&e.cm.scrollIntoView({from:r.from,to:zr(r)});var a=[];Yr(e,function(e,t){t||-1!=f(a,e.history)||($i(e.history,r),a.push(e.history)),Pi(e,r,null,fi(e,r))})}(d);if(h)return h.v}}}}function Li(e,t){if(0!=t&&(e.first+=t,e.sel=new Ts(g(e.sel.ranges,function(e){return new Os(P(e.anchor.line+t,e.anchor.ch),P(e.head.line+t,e.head.ch))}),e.sel.primIndex),e.cm)){vr(e.cm,e.first,e.first-t,t);for(var n=e.cm.display,r=n.viewFrom;re.lastLine())){if(t.from.lineo&&(t={from:t.from,to:P(o,A(e,o).text.length),text:[t.text[0]],origin:t.origin}),t.removed=_(e,t.from,t.to),n||(n=Vr(e,t)),e.cm?Mi(e.cm,t,r):Jr(e,t,r),Ei(e,n,qa)}}function Mi(e,t,n){var r=e.doc,i=e.display,o=t.from,a=t.to,s=!1,u=o.line;e.options.lineWrapping||(u=F(fe(A(r,o.line))),r.iter(u,a.line+1,function(e){if(e==i.maxLine)return s=!0,!0})),r.sel.contains(t.from,t.to)>-1&&Te(e),Jr(r,t,n,wn(e)),e.options.lineWrapping||(r.iter(u,o.line+t.text.length,function(e){var t=xe(e);t>i.maxLineLength&&(i.maxLine=e,i.maxLineLength=t,i.maxLineChanged=!0,s=!1)}),s&&(e.curOp.updateMaxLine=!0)),ot(r,o.line),wr(e,400);var c=t.text.length-(a.line-o.line)-1;t.full?vr(e):o.line!=a.line||1!=t.text.length||Kr(e.doc,t)?vr(e,o.line,a.line+1,c):br(e,o.line,"text");var l=Oe(e,"changes"),p=Oe(e,"change");if(p||l){var f={from:o,to:a,text:t.text,removed:t.removed,origin:t.origin};p&&Ct(e,"change",e,f),l&&(e.curOp.changeObjs||(e.curOp.changeObjs=[])).push(f)}e.display.selForContextMenu=null}function ji(e,t,n,r,i){if(r||(r=n),M(r,n)<0){var o;o=[r,n],n=o[0],r=o[1]}"string"==typeof t&&(t=e.splitLines(t)),Fi(e,{from:n,to:r,text:t,origin:i})}function Ri(e,t,n,r){n0||0==s&&!1!==a.clearWhenEmpty)return a;if(a.replacedWith&&(a.collapsed=!0,a.widgetNode=i("span",[a.replacedWith],"CodeMirror-widget"),r.handleMouseEvents||a.widgetNode.setAttribute("cm-ignore-events","true"),r.insertLeft&&(a.widgetNode.insertLeft=!0)),a.collapsed){if(pe(e,t.line,t,n,a)||t.line!=n.line&&pe(e,n.line,t,n,a))throw new Error("Inserting collapsed marker partially overlapping an existing one");H()}a.addToHistory&&oi(e,{from:t,to:n,origin:"markText"},e.sel,NaN);var u,c=t.line,p=e.cm;if(e.iter(c,n.line+1,function(e){p&&a.collapsed&&!p.options.lineWrapping&&fe(e)==p.display.maxLine&&(u=!0),a.collapsed&&c!=t.line&&O(e,0),J(e,new W(a,c==t.line?t.ch:null,c==n.line?n.ch:null)),++c}),a.collapsed&&e.iter(t.line,n.line+1,function(t){ye(e,t)&&O(t,0)}),a.clearOnEnter&&ns(a,"beforeCursorEnter",function(){return a.clear()}),a.readOnly&&(q(),(e.history.done.length||e.history.undone.length)&&e.clearHistory()),a.collapsed&&(a.id=++Ns,a.atomic=!0),p){if(u&&(p.curOp.updateMaxLine=!0),a.collapsed)vr(p,t.line,n.line+1);else if(a.className||a.title||a.startStyle||a.endStyle||a.css)for(var f=t.line;f<=n.line;f++)br(p,f,"text");a.atomic&&wi(p.doc),Ct(p,"markerAdded",p,a)}return a}function Wi(e,t,n,r,i){r=l(r),r.shared=!1;var o=[Hi(e,t,n,r,i)],a=o[0],s=r.widgetNode;return Yr(e,function(e){s&&(r.widgetNode=s.cloneNode(!0)),o.push(Hi(e,z(e,t),z(e,n),r,i));for(var u=0;u-1)return t.state.draggingText(e),void setTimeout(function(){return t.display.input.focus()},20);try{var u=e.dataTransfer.getData("Text");if(u){var c;if(t.state.draggingText&&!t.state.draggingText.copy&&(c=t.listSelections()),Ei(t.doc,Ur(n,n)),c)for(var l=0;l=0;t--)ji(e.doc,"",r[t].from,r[t].to,"+delete");Qn(e)})}function ho(e,t,n){var r=w(e.text,t+n,n);return r<0||r>e.text.length?null:r}function mo(e,t,n){var r=ho(e,t.ch,n);return null==r?null:new P(t.line,r,n<0?"after":"before")}function go(e,t,n,r,i){if(e){var o=we(n,t.doc.direction);if(o){var a,s=i<0?m(o):o[0],u=i<0==(1==s.level),c=u?"after":"before";if(s.level>0||"rtl"==t.doc.direction){var l=Qt(t,n);a=i<0?n.text.length-1:0;var p=Kt(t,l,a).top;a=S(function(e){return Kt(t,l,e).top==p},i<0==(1==s.level)?s.from:s.to-1,a),"before"==c&&(a=ho(n,a,1))}else a=i<0?s.to:s.from;return new P(r,a,c)}}return new P(r,i<0?n.text.length:0,i<0?"before":"after")}function yo(e,t,n,r){var i=we(t,e.doc.direction);if(!i)return mo(t,n,r);n.ch>=t.text.length?(n.ch=t.text.length,n.sticky="before"):n.ch<=0&&(n.ch=0,n.sticky="after");var o=De(i,n.ch,n.sticky),a=i[o];if("ltr"==e.doc.direction&&a.level%2==0&&(r>0?a.to>n.ch:a.from=a.from&&f>=l.begin)){var d=p?"before":"after";return new P(n.line,f,d)}}var h=function(e,t,r){for(var o=function(e,t){return t?new P(n.line,u(e,1),"before"):new P(n.line,e,"after")};e>=0&&e0==(1!=a.level),c=s?r.begin:u(r.end,-1);if(a.from<=c&&c0?l.end:u(l.begin,-1);return null==g||r>0&&g==t.text.length||!(m=h(r>0?0:i.length-1,r,c(g)))?null:m}function vo(e,t){var n=A(e.doc,t),r=fe(n);return r!=n&&(t=F(r)),go(!0,e,r,t,1)}function bo(e,t){var n=A(e.doc,t),r=de(n);return r!=n&&(t=F(r)),go(!0,e,n,t,-1)}function xo(e,t){var n=vo(e,t.line),r=A(e.doc,n.line),i=we(r,e.doc.direction);if(!i||0==i[0].level){var o=Math.max(0,r.text.search(/\S/)),a=t.line==n.line&&t.ch<=o&&t.ch;return P(n.line,a?0:o,n.sticky)}return n}function Co(e,t,n){if("string"==typeof t&&!(t=Vs[t]))return!1;e.display.input.ensurePolled();var r=e.display.shift,i=!1;try{e.isReadOnly()&&(e.state.suppressEdits=!0),n&&(e.display.shift=!1),i=t(e)!=Va}finally{e.display.shift=r,e.state.suppressEdits=!1}return i}function Eo(e,t,n){for(var r=0;r-1&&(M((i=s.ranges[i]).from(),t)<0||t.xRel>0)&&(M(i.to(),t)>0||t.xRel<0)?Mo(e,r,t,o):Ro(e,r,t,o)}function Mo(e,t,n,r){var i=e.display,o=!1,a=mr(e,function(t){Ca&&(i.scroller.draggable=!1),e.state.draggingText=!1,ke(i.wrapper.ownerDocument,"mouseup",a),ke(i.wrapper.ownerDocument,"mousemove",s),ke(i.scroller,"dragstart",u),ke(i.scroller,"drop",a),o||(Ne(t),r.addNew||mi(e.doc,n,null,null,r.extend),Ca||ba&&9==xa?setTimeout(function(){i.wrapper.ownerDocument.body.focus(),i.input.focus()},20):i.input.focus())}),s=function(e){o=o||Math.abs(t.clientX-e.clientX)+Math.abs(t.clientY-e.clientY)>=10},u=function(){return o=!0};Ca&&(i.scroller.draggable=!0),e.state.draggingText=a,a.copy=!r.moveOnDrag,i.scroller.dragDrop&&i.scroller.dragDrop(),ns(i.wrapper.ownerDocument,"mouseup",a),ns(i.wrapper.ownerDocument,"mousemove",s),ns(i.scroller,"dragstart",u),ns(i.scroller,"drop",a),Pn(e),setTimeout(function(){return i.input.focus()},20)}function jo(e,t,n){if("char"==n)return new Os(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new Os(P(t.line,0),z(e.doc,P(t.line+1,0)));var r=n(e,t);return new Os(r.from,r.to)}function Ro(e,t,n,r){function i(t){if(0!=M(y,t))if(y=t,"rectangle"==r.unit){for(var i=[],o=e.options.tabSize,a=p(A(c,n.line).text,n.ch,o),s=p(A(c,t.line).text,t.ch,o),u=Math.min(a,s),m=Math.max(a,s),g=Math.min(n.line,t.line),v=Math.min(e.lastLine(),Math.max(n.line,t.line));g<=v;g++){var b=A(c,g).text,x=d(b,u,o);u==m?i.push(new Os(P(g,x),P(g,x))):b.length>x&&i.push(new Os(P(g,x),P(g,d(b,m,o))))}i.length||i.push(new Os(n,n)),Ci(c,$r(h.ranges.slice(0,f).concat(i),f),{origin:"*mouse",scroll:!1}),e.scrollIntoView(t)}else{var C,E=l,D=jo(e,t,r.unit),w=E.anchor;M(D.anchor,w)>0?(C=D.head,w=$(E.from(),D.anchor)):(C=D.anchor,w=B(E.to(),D.head));var S=h.ranges.slice(0);S[f]=Bo(e,new Os(z(c,w),C)),Ci(c,$r(S,f),Ha)}}function o(t){var n=++b,s=kn(e,t,!0,"rectangle"==r.unit);if(s)if(0!=M(s,y)){e.curOp.focus=a(),i(s);var l=$n(u,c);(s.line>=l.to||s.linev.bottom?20:0;p&&setTimeout(mr(e,function(){b==n&&(u.scroller.scrollTop+=p,o(t))}),50)}}function s(t){e.state.selectingText=!1,b=1/0,Ne(t),u.input.focus(),ke(u.wrapper.ownerDocument,"mousemove",x),ke(u.wrapper.ownerDocument,"mouseup",C),c.history.lastSelOrigin=null}var u=e.display,c=e.doc;Ne(t);var l,f,h=c.sel,m=h.ranges;if(r.addNew&&!r.extend?(f=c.sel.contains(n),l=f>-1?m[f]:new Os(n,n)):(l=c.sel.primary(),f=c.sel.primIndex),"rectangle"==r.unit)r.addNew||(l=new Os(n,n)),n=kn(e,t,!0,!0),f=-1;else{var g=jo(e,n,r.unit);l=r.extend?hi(l,g.anchor,g.head,r.extend):g}r.addNew?-1==f?(f=m.length,Ci(c,$r(m.concat([l]),f),{scroll:!1,origin:"*mouse"})):m.length>1&&m[f].empty()&&"char"==r.unit&&!r.extend?(Ci(c,$r(m.slice(0,f).concat(m.slice(f+1)),0),{scroll:!1,origin:"*mouse"}),h=c.sel):yi(c,f,l,Ha):(f=0,Ci(c,new Ts([l],0),Ha),h=c.sel);var y=n,v=u.wrapper.getBoundingClientRect(),b=0,x=mr(e,function(e){0!==e.buttons&&je(e)?o(e):s(e)}),C=mr(e,s);e.state.selectingText=C,ns(u.wrapper.ownerDocument,"mousemove",x),ns(u.wrapper.ownerDocument,"mouseup",C)}function Bo(e,t){var n=t.anchor,r=t.head,i=A(e.doc,n.line);if(0==M(n,r)&&n.sticky==r.sticky)return t;var o=we(i);if(!o)return t;var a=De(o,n.ch,n.sticky),s=o[a];if(s.from!=n.ch&&s.to!=n.ch)return t;var u=a+(s.from==n.ch==(1!=s.level)?0:1);if(0==u||u==o.length)return t;var c;if(r.line!=n.line)c=(r.line-n.line)*("ltr"==e.doc.direction?1:-1)>0;else{var l=De(o,r.ch,r.sticky),p=l-a||(r.ch-n.ch)*(1==s.level?-1:1);c=l==u-1||l==u?p<0:p>0}var f=o[u+(c?-1:0)],d=c==(1==f.level),h=d?f.from:f.to,m=d?"after":"before";return n.ch==h&&n.sticky==m?t:new Os(new P(n.line,h,m),r)}function $o(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(t){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&Ne(t);var a=e.display,s=a.lineDiv.getBoundingClientRect();if(o>s.bottom||!Oe(e,n))return Le(t);o-=s.top-a.viewOffset;for(var u=0;u=i){return Ae(e,n,e,N(e.doc,o),e.options.gutters[u],t),Le(t)}}}function Uo(e,t){return $o(e,t,"gutterClick",!0)}function zo(e,t){Mt(e.display,t)||Go(e,t)||_e(e,t,"contextmenu")||e.display.input.onContextMenu(t)}function Go(e,t){return!!Oe(e,"gutterContextMenu")&&$o(e,t,"gutterContextMenu",!1)}function Vo(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),nn(e)}function qo(e){Pr(e),vr(e),Un(e)}function Ho(e,t,n){if(!t!=!(n&&n!=Js)){var r=e.display.dragFunctions,i=t?ns:ke;i(e.display.scroller,"dragstart",r.start),i(e.display.scroller,"dragenter",r.enter),i(e.display.scroller,"dragover",r.over),i(e.display.scroller,"dragleave",r.leave),i(e.display.scroller,"drop",r.drop)}}function Wo(e){e.options.lineWrapping?(s(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(Ra(e.display.wrapper,"CodeMirror-wrap"),Ce(e)),Sn(e),vr(e),nn(e),setTimeout(function(){return rr(e)},100)}function Qo(e,t){var n=this;if(!(this instanceof Qo))return new Qo(e,t);this.options=t=t?l(t):{},l(Ys,t,!1),Mr(t);var r=t.value;"string"==typeof r&&(r=new Ms(r,t.mode,null,t.lineSeparator,t.direction)),this.doc=r;var i=new Qo.inputStyles[t.inputStyle](this),o=this.display=new k(e,r,i);o.wrapper.CodeMirror=this,Pr(this),Vo(this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),or(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:!1,cutIncoming:!1,selectingText:!1,draggingText:!1,highlight:new $a,keySeq:null,specialChars:null},t.autofocus&&!Oa&&o.input.focus(),ba&&xa<11&&setTimeout(function(){return n.display.input.reset(!0)},20),Ko(this),no(),ar(this),this.curOp.forceUpdate=!0,Xr(this,r),t.autofocus&&!Oa||this.hasFocus()?setTimeout(c(Mn,this),20):jn(this);for(var a in Xs)Xs.hasOwnProperty(a)&&Xs[a](n,t[a],Js);zn(this),t.finishInit&&t.finishInit(this);for(var s=0;s400}var i=e.display;ns(i.scroller,"mousedown",mr(e,No)),ba&&xa<11?ns(i.scroller,"dblclick",mr(e,function(t){if(!_e(e,t)){var n=kn(e,t);if(n&&!Uo(e,t)&&!Mt(e.display,t)){Ne(t);var r=e.findWordAt(n);mi(e.doc,r.anchor,r.head)}}})):ns(i.scroller,"dblclick",function(t){return _e(e,t)||Ne(t)}),ja||ns(i.scroller,"contextmenu",function(t){return zo(e,t)});var o,a={end:0};ns(i.scroller,"touchstart",function(t){if(!_e(e,t)&&!n(t)&&!Uo(e,t)){i.input.ensurePolled(),clearTimeout(o);var r=+new Date;i.activeTouch={start:r,moved:!1,prev:r-a.end<=300?a:null},1==t.touches.length&&(i.activeTouch.left=t.touches[0].pageX,i.activeTouch.top=t.touches[0].pageY)}}),ns(i.scroller,"touchmove",function(){i.activeTouch&&(i.activeTouch.moved=!0)}),ns(i.scroller,"touchend",function(n){var o=i.activeTouch;if(o&&!Mt(i,n)&&null!=o.left&&!o.moved&&new Date-o.start<300){var a,s=e.coordsChar(i.activeTouch,"page");a=!o.prev||r(o,o.prev)?new Os(s,s):!o.prev.prev||r(o,o.prev.prev)?e.findWordAt(s):new Os(P(s.line,0),z(e.doc,P(s.line+1,0))),e.setSelection(a.anchor,a.head),e.focus(),Ne(n)}t()}),ns(i.scroller,"touchcancel",t),ns(i.scroller,"scroll",function(){i.scroller.clientHeight&&(Zn(e,i.scroller.scrollTop),tr(e,i.scroller.scrollLeft,!0),Ae(e,"scroll",e))}),ns(i.scroller,"mousewheel",function(t){return Br(e,t)}),ns(i.scroller,"DOMMouseScroll",function(t){return Br(e,t)}),ns(i.wrapper,"scroll",function(){return i.wrapper.scrollTop=i.wrapper.scrollLeft=0}),i.dragFunctions={enter:function(t){_e(e,t)||Pe(t)},over:function(t){_e(e,t)||(Zi(e,t),Pe(t))},start:function(t){return Xi(e,t)},drop:mr(e,Yi),leave:function(t){_e(e,t)||eo(e)}};var s=i.input.getField();ns(s,"keyup",function(t){return To.call(e,t)}),ns(s,"keydown",mr(e,Ao)),ns(s,"keypress",mr(e,Oo)),ns(s,"focus",function(t){return Mn(e,t)}),ns(s,"blur",function(t){return jn(e,t)})}function Jo(e,t,n,r){var i,o=e.doc;null==n&&(n="add"),"smart"==n&&(o.mode.indent?i=Ye(e,t).state:n="prev");var a=e.options.tabSize,s=A(o,t),u=p(s.text,null,a);s.stateAfter&&(s.stateAfter=null);var c,l=s.text.match(/^\s*/)[0];if(r||/\S/.test(s.text)){if("smart"==n&&((c=o.mode.indent(i,s.text.slice(l.length),s.text))==Va||c>150)){if(!r)return;n="prev"}}else c=0,n="not";"prev"==n?c=t>o.first?p(A(o,t-1).text,null,a):0:"add"==n?c=u+e.options.indentUnit:"subtract"==n?c=u-e.options.indentUnit:"number"==typeof n&&(c=u+n),c=Math.max(0,c);var f="",d=0;if(e.options.indentWithTabs)for(var m=Math.floor(c/a);m;--m)d+=a,f+="\t";if(d1)if(eu&&eu.text.join("\n")==t){if(r.ranges.length%eu.text.length==0){u=[];for(var c=0;c=0;p--){var f=r.ranges[p],d=f.from(),h=f.to();f.empty()&&(n&&n>0?d=P(d.line,d.ch-n):e.state.overwrite&&!a?h=P(h.line,Math.min(A(o,h.line).text.length,h.ch+m(s).length)):eu&&eu.lineWise&&eu.text.join("\n")==t&&(d=h=P(d.line,0))),l=e.curOp.updateInput;var y={from:d,to:h,text:u?u[p%u.length]:s,origin:i||(a?"paste":e.state.cutIncoming?"cut":"+input")};Fi(e.doc,y),Ct(e,"inputRead",e,y)}t&&!a&&ea(e,t),Qn(e),e.curOp.updateInput=l,e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=!1}function Zo(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");if(n)return e.preventDefault(),t.isReadOnly()||t.options.disableInput||hr(t,function(){return Xo(t,n,0,null,"paste")}),!0}function ea(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;r>=0;r--){var i=n.ranges[r];if(!(i.head.ch>100||r&&n.ranges[r-1].head.line==i.head.line)){var o=e.getModeAt(i.head),a=!1;if(o.electricChars){for(var s=0;s-1){a=Jo(e,i.head.line,"smart");break}}else o.electricInput&&o.electricInput.test(A(e.doc,i.head.line).text.slice(0,i.head.ch))&&(a=Jo(e,i.head.line,"smart"));a&&Ct(e,"electricInput",e,i.head.line)}}}function ta(e){for(var t=[],n=[],r=0;r=e.first+e.size)&&(t=new P(r,t.ch,t.sticky),c=A(e,r))}function a(r){var a;if(null==(a=i?yo(e.cm,c,t,n):mo(c,t,n))){if(r||!o())return!1;t=go(i,e.cm,c,t.line,n)}else t=a;return!0}var s=t,u=n,c=A(e,t.line);if("char"==r)a();else if("column"==r)a(!0);else if("word"==r||"group"==r)for(var l=null,p="group"==r,f=e.cm&&e.cm.getHelper(t,"wordChars"),d=!0;!(n<0)||a(!d);d=!1){var h=c.text.charAt(t.ch)||"\n",m=C(h,f)?"w":p&&"\n"==h?"n":!p||/\s/.test(h)?null:"p";if(!p||d||m||(m="s"),l&&l!=m){n<0&&(n=1,a(),t.sticky="after");break}if(m&&(l=m),n>0&&!a(!d))break}var g=Ai(e,t,s,u,!0);return j(s,g)&&(g.hitSide=!0),g}function oa(e,t,n,r){var i,o=e.doc,a=t.left;if("page"==r){var s=Math.min(e.display.wrapper.clientHeight,window.innerHeight||document.documentElement.clientHeight),u=Math.max(s-.5*xn(e.display),3);i=(n>0?t.bottom:t.top)+n*u}else"line"==r&&(i=n>0?t.bottom+3:t.top-3);for(var c;c=dn(e,a,i),c.outside;){if(n<0?i<=0:i>=o.height){c.hitSide=!0;break}i+=5*n}return c}function aa(e,t){var n=Wt(e,t.line);if(!n||n.hidden)return null;var r=A(e.doc,t.line),i=Vt(n,r,t.line),o=we(r,e.doc.direction),a="left";if(o){a=De(o,t.ch)%2?"right":"left"}var s=Jt(i.map,t.ch,a);return s.offset="right"==s.collapse?s.end:s.start,s}function sa(e){for(var t=e;t;t=t.parentNode)if(/CodeMirror-gutter-wrapper/.test(t.className))return!0;return!1}function ua(e,t){return t&&(e.bad=!0),e}function ca(e,t,n,r,i){function o(e){return function(t){return t.id==e}}function a(){l&&(c+=p,f&&(c+=p),l=f=!1)}function s(e){e&&(a(),c+=e)}function u(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)return void s(n);var c,d=t.getAttribute("cm-marker");if(d){var h=e.findMarks(P(r,0),P(i+1,0),o(+d));return void(h.length&&(c=h[0].find(0))&&s(_(e.doc,c.from,c.to).join(p)))}if("false"==t.getAttribute("contenteditable"))return;var m=/^(pre|div|p|li|table|br)$/i.test(t.nodeName);if(!/^br$/i.test(t.nodeName)&&0==t.textContent.length)return;m&&a();for(var g=0;g=15&&(wa=!1,Ca=!0);var Pa,Ma=Fa&&(Ea||wa&&(null==La||La<12.11)),ja=ma||ba&&xa>=9,Ra=function(t,n){var r=t.className,i=e(n).exec(r);if(i){var o=r.slice(i.index+i[0].length);t.className=r.slice(0,i.index)+(o?i[1]+o:"")}};Pa=document.createRange?function(e,t,n,r){var i=document.createRange();return i.setEnd(r||e,n),i.setStart(e,t),i}:function(e,t,n){var r=document.body.createTextRange();try{r.moveToElementText(e.parentNode)}catch(e){return r}return r.collapse(!0),r.moveEnd("character",n),r.moveStart("character",t),r};var Ba=function(e){e.select()};_a?Ba=function(e){e.selectionStart=0,e.selectionEnd=e.value.length}:ba&&(Ba=function(e){try{e.select()}catch(e){}});var $a=function(){this.id=null};$a.prototype.set=function(e,t){clearTimeout(this.id),this.id=setTimeout(t,e)};var Ua,za,Ga=30,Va={toString:function(){return"CodeMirror.Pass"}},qa={scroll:!1},Ha={origin:"*mouse"},Wa={origin:"+move"},Qa=[""],Ka=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/,Ja=/[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/,Ya=!1,Xa=!1,Za=null,es=function(){function e(e){return e<=247?n.charAt(e):1424<=e&&e<=1524?"R":1536<=e&&e<=1785?r.charAt(e-1536):1774<=e&&e<=2220?"r":8192<=e&&e<=8203?"w":8204==e?"b":"L"}function t(e,t,n){this.level=e,this.from=t,this.to=n}var n="bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN",r="nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111",i=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,o=/[stwN]/,a=/[LRr]/,s=/[Lb1n]/,u=/[1n]/;return function(n,r){var c="ltr"==r?"L":"R";if(0==n.length||"ltr"==r&&!i.test(n))return!1;for(var l=n.length,p=[],f=0;f=this.string.length},ps.prototype.sol=function(){return this.pos==this.lineStart},ps.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},ps.prototype.next=function(){if(this.post},ps.prototype.eatSpace=function(){for(var e=this,t=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++e.pos;return this.pos>t},ps.prototype.skipToEnd=function(){this.pos=this.string.length},ps.prototype.skipTo=function(e){var t=this.string.indexOf(e,this.pos);if(t>-1)return this.pos=t,!0},ps.prototype.backUp=function(e){this.pos-=e},ps.prototype.column=function(){return this.lastColumnPos0?null:(r&&!1!==t&&(this.pos+=r[0].length),r)}var i=function(e){return n?e.toLowerCase():e};if(i(this.string.substr(this.pos,e.length))==i(e))return!1!==t&&(this.pos+=e.length),!0},ps.prototype.current=function(){return this.string.slice(this.start,this.pos)},ps.prototype.hideFirstChars=function(e,t){this.lineStart+=e;try{return t()}finally{this.lineStart-=e}},ps.prototype.lookAhead=function(e){var t=this.lineOracle;return t&&t.lookAhead(e)},ps.prototype.baseToken=function(){var e=this.lineOracle;return e&&e.baseToken(this.pos)};var fs=function(e,t){this.state=e,this.lookAhead=t},ds=function(e,t,n,r){this.state=t,this.doc=e,this.line=n,this.maxLookAhead=r||0,this.baseTokens=null,this.baseTokenPos=1};ds.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},ds.prototype.baseToken=function(e){var t=this;if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)t.baseTokenPos+=2;var n=this.baseTokens[this.baseTokenPos+1];return{type:n&&n.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},ds.prototype.nextLine=function(){this.line++,this.maxLookAhead>0&&this.maxLookAhead--},ds.fromSaved=function(e,t,n){return t instanceof fs?new ds(e,He(e.mode,t.state),n,t.lookAhead):new ds(e,He(e.mode,t),n)},ds.prototype.save=function(e){var t=!1!==e?He(this.doc.mode,this.state):this.state;return this.maxLookAhead>0?new fs(t,this.maxLookAhead):t};var hs=function(e,t,n){this.start=e.start,this.end=e.pos,this.string=e.current(),this.type=t||null,this.state=n},ms=function(e,t,n){this.text=e,re(this,t),this.height=n?n(this):1};ms.prototype.lineNo=function(){return F(this)},Fe(ms);var gs,ys={},vs={},bs=null,xs=null,Cs={left:0,right:0,top:0,bottom:0},Es=function(e,t,n){this.cm=n;var i=this.vert=r("div",[r("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),o=this.horiz=r("div",[r("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");i.tabIndex=o.tabIndex=-1,e(i),e(o),ns(i,"scroll",function(){i.clientHeight&&t(i.scrollTop,"vertical")}),ns(o,"scroll",function(){o.clientWidth&&t(o.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,ba&&xa<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")};Es.prototype.update=function(e){var t=e.scrollWidth>e.clientWidth+1,n=e.scrollHeight>e.clientHeight+1,r=e.nativeBarWidth;if(n){this.vert.style.display="block",this.vert.style.bottom=t?r+"px":"0";var i=e.viewHeight-(t?r:0);this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+i)+"px"}else this.vert.style.display="",this.vert.firstChild.style.height="0";if(t){this.horiz.style.display="block",this.horiz.style.right=n?r+"px":"0",this.horiz.style.left=e.barLeft+"px";var o=e.viewWidth-e.barLeft-(n?r:0);this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+o)+"px"}else this.horiz.style.display="",this.horiz.firstChild.style.width="0";return!this.checkedZeroWidth&&e.clientHeight>0&&(0==r&&this.zeroWidthHack(),this.checkedZeroWidth=!0),{right:n?r:0,bottom:t?r:0}},Es.prototype.setScrollLeft=function(e){this.horiz.scrollLeft!=e&&(this.horiz.scrollLeft=e),this.disableHoriz&&this.enableZeroWidthBar(this.horiz,this.disableHoriz,"horiz")},Es.prototype.setScrollTop=function(e){this.vert.scrollTop!=e&&(this.vert.scrollTop=e),this.disableVert&&this.enableZeroWidthBar(this.vert,this.disableVert,"vert")},Es.prototype.zeroWidthHack=function(){var e=Fa&&!ka?"12px":"18px";this.horiz.style.height=this.vert.style.width=e,this.horiz.style.pointerEvents=this.vert.style.pointerEvents="none",this.disableHoriz=new $a,this.disableVert=new $a},Es.prototype.enableZeroWidthBar=function(e,t,n){function r(){var i=e.getBoundingClientRect();("vert"==n?document.elementFromPoint(i.right-1,(i.top+i.bottom)/2):document.elementFromPoint((i.right+i.left)/2,i.bottom-1))!=e?e.style.pointerEvents="none":t.set(1e3,r)}e.style.pointerEvents="auto",t.set(1e3,r)},Es.prototype.clear=function(){var e=this.horiz.parentNode;e.removeChild(this.horiz),e.removeChild(this.vert)};var Ds=function(){};Ds.prototype.update=function(){return{bottom:0,right:0}},Ds.prototype.setScrollLeft=function(){},Ds.prototype.setScrollTop=function(){},Ds.prototype.clear=function(){};var ws={native:Es,null:Ds},Ss=0,ks=function(e,t,n){var r=e.display;this.viewport=t,this.visible=$n(r,e.doc,t),this.editorIsHidden=!r.wrapper.offsetWidth,this.wrapperHeight=r.wrapper.clientHeight,this.wrapperWidth=r.wrapper.clientWidth,this.oldDisplayWidth=Ut(e),this.force=n,this.dims=En(e),this.events=[]};ks.prototype.signal=function(e,t){Oe(e,t)&&this.events.push(arguments)},ks.prototype.finish=function(){for(var e=this,t=0;t=0&&M(e,i.to())<=0)return r}return-1};var Os=function(e,t){this.anchor=e,this.head=t};Os.prototype.from=function(){return $(this.anchor,this.head)},Os.prototype.to=function(){return B(this.anchor,this.head)},Os.prototype.empty=function(){return this.head.line==this.anchor.line&&this.head.ch==this.anchor.ch},zi.prototype={chunkSize:function(){return this.lines.length},removeInner:function(e,t){for(var n=this,r=e,i=e+t;r1||!(this.children[0]instanceof zi))){var u=[];this.collapse(u),this.children=[new zi(u)],this.children[0].parent=this}},collapse:function(e){for(var t=this,n=0;n50){for(var s=o.lines.length%25+25,u=s;u10);e.parent.maybeSpill()}},iterN:function(e,t,n){for(var r=this,i=0;it.display.maxLineLength&&(t.display.maxLine=l,t.display.maxLineLength=p,t.display.maxLineChanged=!0)}null!=i&&t&&this.collapsed&&vr(t,i,o+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,t&&wi(t.doc)),t&&Ct(t,"markerCleared",t,this,i,o),n&&sr(t),this.parent&&this.parent.clear()}},Is.prototype.find=function(e,t){var n=this;null==e&&"bookmark"==this.type&&(e=1);for(var r,i,o=0;o=0;c--)Fi(r,i[c]);u?xi(this,u):this.cm&&Qn(this.cm)}),undo:yr(function(){Ii(this,"undo")}),redo:yr(function(){Ii(this,"redo")}),undoSelection:yr(function(){Ii(this,"undo",!0)}),redoSelection:yr(function(){Ii(this,"redo",!0)}),setExtending:function(e){this.extend=e},getExtending:function(){return this.extend},historySize:function(){for(var e=this.history,t=0,n=0,r=0;r=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(e,t,n){e=z(this,e),t=z(this,t);var r=[],i=e.line;return this.iter(e.line,t.line+1,function(o){var a=o.markedSpans;if(a)for(var s=0;s=u.to||null==u.from&&i!=e.line||null!=u.from&&i==t.line&&u.from>=t.ch||n&&!n(u.marker)||r.push(u.marker.parent||u.marker)}++i}),r},getAllMarks:function(){var e=[];return this.iter(function(t){var n=t.markedSpans;if(n)for(var r=0;re)return t=e,!0;e-=o,++n}),z(this,P(n,t))},indexFromPos:function(e){e=z(this,e);var t=e.ch;if(e.linet&&(t=e.from),null!=e.to&&e.to0)i=new P(i.line,i.ch+1),e.replaceRange(o.charAt(i.ch-1)+o.charAt(i.ch-2),P(i.line,i.ch-2),i,"+transpose");else if(i.line>e.doc.first){var a=A(e.doc,i.line-1).text;a&&(i=new P(i.line,1),e.replaceRange(o.charAt(0)+e.doc.lineSeparator()+a.charAt(a.length-1),P(i.line-1,a.length-1),i,"+transpose"))}n.push(new Os(i,i))}e.setSelections(n)})},newlineAndIndent:function(e){return hr(e,function(){for(var t=e.listSelections(),n=t.length-1;n>=0;n--)e.replaceRange(e.doc.lineSeparator(),t[n].anchor,t[n].head,"+input");t=e.listSelections();for(var r=0;re&&0==M(t,this.pos)&&n==this.button};var Qs,Ks,Js={toString:function(){return"CodeMirror.Init"}},Ys={},Xs={};Qo.defaults=Ys,Qo.optionHandlers=Xs;var Zs=[];Qo.defineInitHook=function(e){return Zs.push(e)};var eu=null,tu=function(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new $a,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null};tu.prototype.init=function(e){function t(e){if(!_e(i,e)){if(i.somethingSelected())Yo({lineWise:!1,text:i.getSelections()}),"cut"==e.type&&i.replaceSelection("",null,"cut");else{if(!i.options.lineWiseCopyCut)return;var t=ta(i);Yo({lineWise:!0,text:t.text}),"cut"==e.type&&i.operation(function(){i.setSelections(t.ranges,0,qa),i.replaceSelection("",null,"cut")})}if(e.clipboardData){e.clipboardData.clearData();var n=eu.text.join("\n");if(e.clipboardData.setData("Text",n),e.clipboardData.getData("Text")==n)return void e.preventDefault()}var a=ra(),s=a.firstChild;i.display.lineSpace.insertBefore(a,i.display.lineSpace.firstChild),s.value=eu.text.join("\n");var u=document.activeElement;Ba(s),setTimeout(function(){i.display.lineSpace.removeChild(a),u.focus(),u==o&&r.showPrimarySelection()},50)}}var n=this,r=this,i=r.cm,o=r.div=e.lineDiv;na(o,i.options.spellcheck),ns(o,"paste",function(e){_e(i,e)||Zo(e,i)||xa<=11&&setTimeout(mr(i,function(){return n.updateFromDOM()}),20)}),ns(o,"compositionstart",function(e){n.composing={data:e.data,done:!1}}),ns(o,"compositionupdate",function(e){n.composing||(n.composing={data:e.data,done:!1})}),ns(o,"compositionend",function(e){n.composing&&(e.data!=n.composing.data&&n.readFromDOMSoon(),n.composing.done=!0)}),ns(o,"touchstart",function(){return r.forceCompositionEnd()}),ns(o,"input",function(){n.composing||n.readFromDOMSoon()}),ns(o,"copy",t),ns(o,"cut",t)},tu.prototype.prepareSelection=function(){var e=Tn(this.cm,!1);return e.focus=this.cm.state.focused,e},tu.prototype.showSelection=function(e,t){e&&this.cm.display.view.length&&((e.focus||t)&&this.showPrimarySelection(),this.showMultipleSelections(e))},tu.prototype.getSelection=function(){return this.cm.display.wrapper.ownerDocument.getSelection()},tu.prototype.showPrimarySelection=function(){var e=this.getSelection(),t=this.cm,n=t.doc.sel.primary(),r=n.from(),i=n.to();if(t.display.viewTo==t.display.viewFrom||r.line>=t.display.viewTo||i.line=t.display.viewFrom&&aa(t,r)||{node:s[0].measure.map[2],offset:0},c=i.linee.firstLine()&&(r=P(r.line-1,A(e.doc,r.line-1).length)),i.ch==A(e.doc,i.line).text.length&&i.linet.viewTo-1)return!1;var o,a,s;r.line==t.viewFrom||0==(o=An(e,r.line))?(a=F(t.view[0].line),s=t.view[0].node):(a=F(t.view[o].line),s=t.view[o-1].node.nextSibling);var u,c,l=An(e,i.line);if(l==t.view.length-1?(u=t.viewTo-1,c=t.lineDiv.lastChild):(u=F(t.view[l+1].line)-1,c=t.view[l+1].node.previousSibling),!s)return!1;for(var p=e.doc.splitLines(ca(e,s,c,a,u)),f=_(e.doc,P(a,0),P(u,A(e.doc,u).text.length));p.length>1&&f.length>1;)if(m(p)==m(f))p.pop(),f.pop(),u--;else{if(p[0]!=f[0])break;p.shift(),f.shift(),a++}for(var d=0,h=0,g=p[0],y=f[0],v=Math.min(g.length,y.length);dr.ch&&b.charCodeAt(b.length-h-1)==x.charCodeAt(x.length-h-1);)d--,h++;p[p.length-1]=b.slice(0,b.length-h).replace(/^\u200b+/,""),p[0]=p[0].slice(d).replace(/\u200b+$/,"");var E=P(a,d),D=P(u,f.length?m(f).length-h:0);return p.length>1||p[0]||M(E,D)?(ji(e.doc,p,E,D,"+input"),!0):void 0},tu.prototype.ensurePolled=function(){this.forceCompositionEnd()},tu.prototype.reset=function(){this.forceCompositionEnd()},tu.prototype.forceCompositionEnd=function(){this.composing&&(clearTimeout(this.readDOMTimeout),this.composing=null,this.updateFromDOM(),this.div.blur(),this.div.focus())},tu.prototype.readFromDOMSoon=function(){var e=this;null==this.readDOMTimeout&&(this.readDOMTimeout=setTimeout(function(){if(e.readDOMTimeout=null,e.composing){if(!e.composing.done)return;e.composing=null}e.updateFromDOM()},80))},tu.prototype.updateFromDOM=function(){var e=this;!this.cm.isReadOnly()&&this.pollContent()||hr(this.cm,function(){return vr(e.cm)})},tu.prototype.setUneditable=function(e){e.contentEditable="false"},tu.prototype.onKeyPress=function(e){0==e.charCode||this.composing||(e.preventDefault(),this.cm.isReadOnly()||mr(this.cm,Xo)(this.cm,String.fromCharCode(null==e.charCode?e.keyCode:e.charCode),0))},tu.prototype.readOnlyChanged=function(e){this.div.contentEditable=String("nocursor"!=e)},tu.prototype.onContextMenu=function(){},tu.prototype.resetPosition=function(){},tu.prototype.needsContentAttribute=!0;var nu=function(e){this.cm=e,this.prevInput="",this.pollingFast=!1,this.polling=new $a,this.hasSelection=!1,this.composing=null};nu.prototype.init=function(e){function t(e){if(!_e(i,e)){if(i.somethingSelected())Yo({lineWise:!1,text:i.getSelections()});else{if(!i.options.lineWiseCopyCut)return;var t=ta(i);Yo({lineWise:!0,text:t.text}),"cut"==e.type?i.setSelections(t.ranges,null,qa):(r.prevInput="",o.value=t.text.join("\n"),Ba(o))}"cut"==e.type&&(i.state.cutIncoming=!0)}}var n=this,r=this,i=this.cm;this.createField(e);var o=this.textarea;e.wrapper.insertBefore(this.wrapper,e.wrapper.firstChild),_a&&(o.style.width="0px"),ns(o,"input",function(){ba&&xa>=9&&n.hasSelection&&(n.hasSelection=null),r.poll()}),ns(o,"paste",function(e){_e(i,e)||Zo(e,i)||(i.state.pasteIncoming=!0,r.fastPoll())}),ns(o,"cut",t),ns(o,"copy",t),ns(e.scroller,"paste",function(t){Mt(e,t)||_e(i,t)||(i.state.pasteIncoming=!0,r.focus())}),ns(e.lineSpace,"selectstart",function(t){Mt(e,t)||Ne(t)}),ns(o,"compositionstart",function(){var e=i.getCursor("from");r.composing&&r.composing.range.clear(),r.composing={start:e,range:i.markText(e,i.getCursor("to"),{className:"CodeMirror-composing"})}}),ns(o,"compositionend",function(){r.composing&&(r.poll(),r.composing.range.clear(),r.composing=null)})},nu.prototype.createField=function(e){this.wrapper=ra(),this.textarea=this.wrapper.firstChild},nu.prototype.prepareSelection=function(){var e=this.cm,t=e.display,n=e.doc,r=Tn(e);if(e.options.moveInputWithCursor){var i=ln(e,n.sel.primary().head,"div"),o=t.wrapper.getBoundingClientRect(),a=t.lineDiv.getBoundingClientRect();r.teTop=Math.max(0,Math.min(t.wrapper.clientHeight-10,i.top+a.top-o.top)),r.teLeft=Math.max(0,Math.min(t.wrapper.clientWidth-10,i.left+a.left-o.left))}return r},nu.prototype.showSelection=function(e){var t=this.cm,r=t.display;n(r.cursorDiv,e.cursors),n(r.selectionDiv,e.selection),null!=e.teTop&&(this.wrapper.style.top=e.teTop+"px",this.wrapper.style.left=e.teLeft+"px")},nu.prototype.reset=function(e){if(!this.contextMenuPending&&!this.composing){var t=this.cm;if(t.somethingSelected()){this.prevInput="";var n=t.getSelection();this.textarea.value=n,t.state.focused&&Ba(this.textarea),ba&&xa>=9&&(this.hasSelection=n)}else e||(this.prevInput=this.textarea.value="",ba&&xa>=9&&(this.hasSelection=null))}},nu.prototype.getField=function(){return this.textarea},nu.prototype.supportsTouch=function(){return!1},nu.prototype.focus=function(){if("nocursor"!=this.cm.options.readOnly&&(!Oa||a()!=this.textarea))try{this.textarea.focus()}catch(e){}},nu.prototype.blur=function(){this.textarea.blur()},nu.prototype.resetPosition=function(){this.wrapper.style.top=this.wrapper.style.left=0},nu.prototype.receivedFocus=function(){this.slowPoll()},nu.prototype.slowPoll=function(){var e=this;this.pollingFast||this.polling.set(this.cm.options.pollInterval,function(){e.poll(),e.cm.state.focused&&e.slowPoll()})},nu.prototype.fastPoll=function(){function e(){n.poll()||t?(n.pollingFast=!1,n.slowPoll()):(t=!0,n.polling.set(60,e))}var t=!1,n=this;n.pollingFast=!0,n.polling.set(20,e)},nu.prototype.poll=function(){var e=this,t=this.cm,n=this.textarea,r=this.prevInput;if(this.contextMenuPending||!t.state.focused||os(n)&&!r&&!this.composing||t.isReadOnly()||t.options.disableInput||t.state.keySeq)return!1;var i=n.value;if(i==r&&!t.somethingSelected())return!1;if(ba&&xa>=9&&this.hasSelection===i||Fa&&/[\uf700-\uf7ff]/.test(i))return t.display.input.reset(),!1;if(t.doc.sel==t.display.selForContextMenu){var o=i.charCodeAt(0);if(8203!=o||r||(r="\u200b"),8666==o)return this.reset(),this.cm.execCommand("undo")}for(var a=0,s=Math.min(r.length,i.length);a1e3||i.indexOf("\n")>-1?n.value=e.prevInput="":e.prevInput=i,e.composing&&(e.composing.range.clear(),e.composing.range=t.markText(e.composing.start,t.getCursor("to"),{className:"CodeMirror-composing"}))}),!0},nu.prototype.ensurePolled=function(){this.pollingFast&&this.poll()&&(this.pollingFast=!1)},nu.prototype.onKeyPress=function(){ba&&xa>=9&&(this.hasSelection=null),this.fastPoll()},nu.prototype.onContextMenu=function(e){function t(){if(null!=a.selectionStart){var e=i.somethingSelected(),t="\u200b"+(e?a.value:"");a.value="\u21da",a.value=t,r.prevInput=e?"":"\u200b",a.selectionStart=1,a.selectionEnd=t.length,o.selForContextMenu=i.doc.sel}}function n(){if(r.contextMenuPending=!1,r.wrapper.style.cssText=l,a.style.cssText=c,ba&&xa<9&&o.scrollbars.setScrollTop(o.scroller.scrollTop=u),null!=a.selectionStart){(!ba||ba&&xa<9)&&t();var e=0,n=function(){o.selForContextMenu==i.doc.sel&&0==a.selectionStart&&a.selectionEnd>0&&"\u200b"==r.prevInput?mr(i,Ti)(i):e++<10?o.detectingSelectAll=setTimeout(n,500):(o.selForContextMenu=null,o.input.reset())};o.detectingSelectAll=setTimeout(n,200)}}var r=this,i=r.cm,o=i.display,a=r.textarea,s=kn(i,e),u=o.scroller.scrollTop;if(s&&!wa){i.options.resetSelectionOnContextMenu&&-1==i.doc.sel.contains(s)&&mr(i,Ci)(i.doc,Ur(s),qa);var c=a.style.cssText,l=r.wrapper.style.cssText;r.wrapper.style.cssText="position: absolute";var p=r.wrapper.getBoundingClientRect();a.style.cssText="position: absolute; width: 30px; height: 30px;\n top: "+(e.clientY-p.top-5)+"px; left: "+(e.clientX-p.left-5)+"px;\n z-index: 1000; background: "+(ba?"rgba(255, 255, 255, .05)":"transparent")+";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";var f;if(Ca&&(f=window.scrollY),o.input.focus(),Ca&&window.scrollTo(null,f),o.input.reset(),i.somethingSelected()||(a.value=r.prevInput=" "),r.contextMenuPending=!0,o.selForContextMenu=i.doc.sel,clearTimeout(o.detectingSelectAll),ba&&xa>=9&&t(),ja){Pe(e);var d=function(){ke(window,"mouseup",d),setTimeout(n,20)};ns(window,"mouseup",d)}else setTimeout(n,50)}},nu.prototype.readOnlyChanged=function(e){e||this.reset(),this.textarea.disabled="nocursor"==e},nu.prototype.setUneditable=function(){},nu.prototype.needsContentAttribute=!1,function(e){function t(t,r,i,o){e.defaults[t]=r,i&&(n[t]=o?function(e,t,n){n!=Js&&i(e,t,n)}:i)}var n=e.optionHandlers;e.defineOption=t,e.Init=Js,t("value","",function(e,t){return e.setValue(t)},!0),t("mode",null,function(e,t){e.doc.modeOption=t,Wr(e)},!0),t("indentUnit",2,Wr,!0),t("indentWithTabs",!1),t("smartIndent",!0),t("tabSize",4,function(e){Qr(e),nn(e),vr(e)},!0),t("lineSeparator",null,function(e,t){if(e.doc.lineSep=t,t){var n=[],r=e.doc.first;e.doc.iter(function(e){for(var i=0;;){var o=e.text.indexOf(t,i);if(-1==o)break;i=o+t.length,n.push(P(r,o))}r++});for(var i=n.length-1;i>=0;i--)ji(e.doc,t,n[i],P(n[i].line,n[i].ch+t.length))}}),t("specialChars",/[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g,function(e,t,n){e.state.specialChars=new RegExp(t.source+(t.test("\t")?"":"|\t"),"g"),n!=Js&&e.refresh()}),t("specialCharPlaceholder",lt,function(e){return e.refresh()},!0),t("electricChars",!0),t("inputStyle",Oa?"contenteditable":"textarea",function(){throw new Error("inputStyle can not (yet) be changed in a running editor")},!0),t("spellcheck",!1,function(e,t){return e.getInputField().spellcheck=t},!0),t("rtlMoveVisually",!Ia),t("wholeLineUpdateBefore",!0),t("theme","default",function(e){Vo(e),qo(e)},!0),t("keyMap","default",function(e,t,n){var r=po(t),i=n!=Js&&po(n);i&&i.detach&&i.detach(e,r),r.attach&&r.attach(e,i||null)}),t("extraKeys",null),t("configureMouse",null),t("lineWrapping",!1,Wo,!0),t("gutters",[],function(e){Mr(e.options),qo(e)},!0),t("fixedGutter",!0,function(e,t){e.display.gutters.style.left=t?Dn(e.display)+"px":"0",e.refresh()},!0),t("coverGutterNextToScrollbar",!1,function(e){return rr(e)},!0),t("scrollbarStyle","native",function(e){or(e),rr(e),e.display.scrollbars.setScrollTop(e.doc.scrollTop),e.display.scrollbars.setScrollLeft(e.doc.scrollLeft)},!0),t("lineNumbers",!1,function(e){Mr(e.options),qo(e)},!0),t("firstLineNumber",1,qo,!0),t("lineNumberFormatter",function(e){return e},qo,!0),t("showCursorWhenSelecting",!1,_n,!0),t("resetSelectionOnContextMenu",!0),t("lineWiseCopyCut",!0),t("pasteLinesPerSelection",!0),t("readOnly",!1,function(e,t){"nocursor"==t&&(jn(e),e.display.input.blur()),e.display.input.readOnlyChanged(t)}),t("disableInput",!1,function(e,t){t||e.display.input.reset()},!0),t("dragDrop",!0,Ho),t("allowDropFileTypes",null),t("cursorBlinkRate",530),t("cursorScrollMargin",0),t("cursorHeight",1,_n,!0),t("singleCursorHeightPerLine",!0,_n,!0),t("workTime",100),t("workDelay",100),t("flattenSpans",!0,Qr,!0),t("addModeClass",!1,Qr,!0),t("pollInterval",100),t("undoDepth",200,function(e,t){return e.doc.history.undoDepth=t}),t("historyEventDelay",1250),t("viewportMargin",10,function(e){return e.refresh()},!0),t("maxHighlightLength",1e4,Qr,!0),t("moveInputWithCursor",!0,function(e,t){t||e.display.input.resetPosition()}),t("tabindex",null,function(e,t){return e.display.input.getField().tabIndex=t||""}),t("autofocus",null),t("direction","ltr",function(e,t){return e.doc.setDirection(t)},!0)}(Qo),function(e){var t=e.optionHandlers,n=e.helpers={};e.prototype={constructor:e,focus:function(){window.focus(),this.display.input.focus()},setOption:function(e,n){var r=this.options,i=r[e];r[e]==n&&"mode"!=e||(r[e]=n,t.hasOwnProperty(e)&&mr(this,t[e])(this,n,i),Ae(this,"optionChange",this,e))},getOption:function(e){return this.options[e]},getDoc:function(){return this.doc},addKeyMap:function(e,t){this.state.keyMaps[t?"push":"unshift"](po(e))},removeKeyMap:function(e){for(var t=this.state.keyMaps,n=0;nr&&(Jo(t,o.head.line,e,!0),r=o.head.line,i==t.doc.sel.primIndex&&Qn(t));else{var a=o.from(),s=o.to(),u=Math.max(r,a.line);r=Math.min(t.lastLine(),s.line-(s.ch?0:1))+1;for(var c=u;c0&&yi(t.doc,i,new Os(a,l[i].to()),qa)}}}),getTokenAt:function(e,t){return tt(this,e,t)},getLineTokens:function(e,t){return tt(this,P(e),t,!0)},getTokenTypeAt:function(e){e=z(this.doc,e);var t,n=Je(this,A(this.doc,e.line)),r=0,i=(n.length-1)/2,o=e.ch;if(0==o)t=n[2];else for(;;){var a=r+i>>1;if((a?n[2*a-1]:0)>=o)i=a;else{if(!(n[2*a+1]o&&(e=o,i=!0),r=A(this.doc,e)}else r=e;return sn(this,r,{top:0,left:0},t||"page",n||i).top+(i?this.doc.height-be(r):0)},defaultTextHeight:function(){return xn(this.display)},defaultCharWidth:function(){return Cn(this.display)},getViewport:function(){return{from:this.display.viewFrom,to:this.display.viewTo}},addWidget:function(e,t,n,r,i){var o=this.display;e=ln(this,z(this.doc,e));var a=e.bottom,s=e.left;if(t.style.position="absolute",t.setAttribute("cm-ignore-events","true"),this.display.input.setUneditable(t),o.sizer.appendChild(t),"over"==r)a=e.top;else if("above"==r||"near"==r){var u=Math.max(o.wrapper.clientHeight,this.doc.height),c=Math.max(o.sizer.clientWidth,o.lineSpace.clientWidth);("above"==r||e.bottom+t.offsetHeight>u)&&e.top>t.offsetHeight?a=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=u&&(a=e.bottom),s+t.offsetWidth>c&&(s=c-t.offsetWidth)}t.style.top=a+"px",t.style.left=t.style.right="","right"==i?(s=o.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?s=0:"middle"==i&&(s=(o.sizer.clientWidth-t.offsetWidth)/2),t.style.left=s+"px"),n&&qn(this,{left:s,top:a,right:s+t.offsetWidth,bottom:a+t.offsetHeight})},triggerOnKeyDown:gr(Ao),triggerOnKeyPress:gr(Oo),triggerOnKeyUp:To,triggerOnMouseDown:gr(No),execCommand:function(e){if(Vs.hasOwnProperty(e))return Vs[e].call(null,this)},triggerElectric:gr(function(e){ea(this,e)}),findPosH:function(e,t,n,r){var i=this,o=1;t<0&&(o=-1,t=-t);for(var a=z(this.doc,e),s=0;s0&&s(n.charAt(r-1));)--r;for(;i.5)&&Sn(this),Ae(this,"refresh",this)}),swapDoc:gr(function(e){var t=this.doc;return t.cm=null,Xr(this,e),nn(this),this.display.input.reset(),Kn(this,e.scrollLeft,e.scrollTop),this.curOp.forceScroll=!0,Ct(this,"swapDoc",this,t),t}),getInputField:function(){return this.display.input.getField()},getWrapperElement:function(){return this.display.wrapper},getScrollerElement:function(){return this.display.scroller},getGutterElement:function(){return this.display.gutters}},Fe(e),e.registerHelper=function(t,r,i){n.hasOwnProperty(t)||(n[t]=e[t]={_global:[]}),n[t][r]=i},e.registerGlobalHelper=function(t,r,i,o){e.registerHelper(t,r,o),n[t]._global.push({pred:i,val:o})}}(Qo);var ru="iter insert remove copy getEditor constructor".split(" ");for(var iu in Ms.prototype)Ms.prototype.hasOwnProperty(iu)&&f(ru,iu)<0&&(Qo.prototype[iu]=function(e){return function(){return e.apply(this.doc,arguments)}}(Ms.prototype[iu]));return Fe(Ms),Qo.inputStyles={textarea:nu,contenteditable:tu},Qo.defineMode=function(e){Qo.defaults.mode||"null"==e||(Qo.defaults.mode=e),Ue.apply(this,arguments)},Qo.defineMIME=ze,Qo.defineMode("null",function(){return{token:function(e){return e.skipToEnd()}}}),Qo.defineMIME("text/plain","null"),Qo.defineExtension=function(e,t){Qo.prototype[e]=t},Qo.defineDocExtension=function(e,t){Ms.prototype[e]=t},Qo.fromTextArea=fa,function(e){e.off=ke,e.on=ns,e.wheelEventPixels=Rr,e.Doc=Ms,e.splitLines=is,e.countColumn=p,e.findColumn=d,e.isWordChar=x,e.Pass=Va,e.signal=Ae,e.Line=ms,e.changeEnd=zr,e.scrollbarModel=ws,e.Pos=P,e.cmpPos=M,e.modes=us,e.mimeModes=cs,e.resolveMode=Ge,e.getMode=Ve,e.modeExtensions=ls,e.extendMode=qe,e.copyState=He,e.startState=Qe,e.innerMode=We,e.commands=Vs,e.keyMap=Gs,e.keyName=lo,e.isModifierKey=uo,e.lookupKey=so,e.normalizeKeyMap=ao,e.StringStream=ps,e.SharedTextMarker=Ls,e.TextMarker=Is,e.LineWidget=Fs,e.e_preventDefault=Ne,e.e_stopPropagation=Ie,e.e_stop=Pe,e.addClass=s,e.contains=o,e.rmClass=Ra,e.keyNames=Bs}(Qo),Qo.version="5.38.0",Qo})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(43);Object.defineProperty(t,"GraphQLError",{enumerable:!0,get:function(){return r.GraphQLError}});var i=n(391);Object.defineProperty(t,"syntaxError",{enumerable:!0,get:function(){return i.syntaxError}});var o=n(180);Object.defineProperty(t,"locatedError",{enumerable:!0,get:function(){return o.locatedError}});var a=n(392);Object.defineProperty(t,"formatError",{enumerable:!0,get:function(){return a.formatError}})},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e)}function i(e){return"[object String]"===r(e)}function o(e,t){return C.call(e,t)}function a(e){return Array.prototype.slice.call(arguments,1).forEach(function(t){if(t){if("object"!==typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e}function s(e,t,n){return[].concat(e.slice(0,t),n,e.slice(t+1))}function u(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!==(65535&e)&&65534!==(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function c(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function l(e,t){var n=0;return o(k,t)?k[t]:35===t.charCodeAt(0)&&S.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?c(n):e}function p(e){return e.indexOf("\\")<0?e:e.replace(E,"$1")}function f(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(w,function(e,t,n){return t||l(e,n)})}function d(e){return T[e]}function h(e){return A.test(e)?e.replace(_,d):e}function m(e){return e.replace(O,"\\$&")}function g(e){switch(e){case 9:case 32:return!0}return!1}function y(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1}function v(e){return F.test(e)}function b(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}}function x(e){return e.trim().replace(/\s+/g," ").toUpperCase()}var C=Object.prototype.hasOwnProperty,E=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,D=/&([a-z#][a-z0-9]{1,31});/gi,w=new RegExp(E.source+"|"+D.source,"gi"),S=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,k=n(261),A=/[&<>"]/,_=/[&<>"]/g,T={"&":"&","<":"<",">":">",'"':"""},O=/[.?*+^$[\]\\(){}|-]/g,F=n(263);t.lib={},t.lib.mdurl=n(88),t.lib.ucmicro=n(543),t.assign=a,t.isString=i,t.has=o,t.unescapeMd=p,t.unescapeAll=f,t.isValidEntityCode=u,t.fromCodePoint=c,t.escapeHtml=h,t.arrayReplaceAt=s,t.isSpace=g,t.isWhiteSpace=y,t.isMdAsciiPunct=b,t.isPunctChar=v,t.escapeRE=m,t.normalizeReference=x},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e)}function i(e){return"[object String]"===r(e)}function o(e,t){return C.call(e,t)}function a(e){return Array.prototype.slice.call(arguments,1).forEach(function(t){if(t){if("object"!==typeof t)throw new TypeError(t+"must be object");Object.keys(t).forEach(function(n){e[n]=t[n]})}}),e}function s(e,t,n){return[].concat(e.slice(0,t),n,e.slice(t+1))}function u(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!==(65535&e)&&65534!==(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function c(e){if(e>65535){e-=65536;var t=55296+(e>>10),n=56320+(1023&e);return String.fromCharCode(t,n)}return String.fromCharCode(e)}function l(e,t){var n=0;return o(k,t)?k[t]:35===t.charCodeAt(0)&&S.test(t)&&(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10),u(n))?c(n):e}function p(e){return e.indexOf("\\")<0?e:e.replace(E,"$1")}function f(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(w,function(e,t,n){return t||l(e,n)})}function d(e){return T[e]}function h(e){return A.test(e)?e.replace(_,d):e}function m(e){return e.replace(O,"\\$&")}function g(e){switch(e){case 9:case 32:return!0}return!1}function y(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1}function v(e){return F.test(e)}function b(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}}function x(e){return e.trim().replace(/\s+/g," ").toUpperCase()}var C=Object.prototype.hasOwnProperty,E=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,D=/&([a-z#][a-z0-9]{1,31});/gi,w=new RegExp(E.source+"|"+D.source,"gi"),S=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i,k=n(294),A=/[&<>"]/,_=/[&<>"]/g,T={"&":"&","<":"<",">":">",'"':"""},O=/[.?*+^$[\]\\(){}|-]/g,F=n(136);t.lib={},t.lib.mdurl=n(88),t.lib.ucmicro=n(647),t.assign=a,t.isString=i,t.has=o,t.unescapeMd=p,t.unescapeAll=f,t.isValidEntityCode=u,t.fromCodePoint=c,t.escapeHtml=h,t.arrayReplaceAt=s,t.isSpace=g,t.isWhiteSpace=y,t.isMdAsciiPunct=b,t.isPunctChar=v,t.escapeRE=m,t.normalizeReference=x},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e){return e instanceof j||e instanceof R||e instanceof B||e instanceof $||e instanceof U||e instanceof z||e instanceof G||e instanceof V}function a(e){return o(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL type."),e}function s(e){return e instanceof j||e instanceof U||e instanceof z||e instanceof V&&s(e.ofType)||e instanceof G&&s(e.ofType)}function u(e){return s(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL input type."),e}function c(e){return e instanceof j||e instanceof R||e instanceof B||e instanceof $||e instanceof U||e instanceof V&&c(e.ofType)||e instanceof G&&c(e.ofType)}function l(e){return c(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL output type."),e}function p(e){return e instanceof j||e instanceof U}function f(e){return p(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL leaf type."),e}function d(e){return e instanceof R||e instanceof B||e instanceof $}function h(e){return d(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL composite type."),e}function m(e){return e instanceof B||e instanceof $}function g(e){return m(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL abstract type."),e}function y(e){return e instanceof V?e.ofType:e}function v(e){return e instanceof j||e instanceof R||e instanceof B||e instanceof $||e instanceof U||e instanceof z}function b(e){return v(e)||(0,F.default)(0,"Expected "+String(e)+" to be a GraphQL named type."),e}function x(e){if(e){for(var t=e;t instanceof G||t instanceof V;)t=t.ofType;return t}}function C(e){return"function"===typeof e?e():e}function E(e,t){var n=C(t);if(!n)return[];Array.isArray(n)||(0,F.default)(0,e.name+" interfaces must be an Array or a function which returns an Array.");var r=Object.create(null);return n.forEach(function(t){t instanceof B||(0,F.default)(0,e.name+" may only implement Interface types, it cannot implement: "+String(t)+"."),r[t.name]&&(0,F.default)(0,e.name+" may declare it implements "+t.name+" only once."),r[t.name]=!0,"function"!==typeof t.resolveType&&"function"!==typeof e.isTypeOf&&(0,F.default)(0,"Interface Type "+t.name+' does not provide a "resolveType" function and implementing Type '+e.name+' does not provide a "isTypeOf" function. There is no way to resolve this implementing type during execution.')}),n}function D(e,t){var n=C(t);w(n)||(0,F.default)(0,e.name+" fields must be an object with field names as keys or a function which returns such an object.");var r=Object.keys(n);r.length>0||(0,F.default)(0,e.name+" fields must be an object with field names as keys or a function which returns such an object.");var i=Object.create(null);return r.forEach(function(t){(0,M.assertValidName)(t);var r=n[t];w(r)||(0,F.default)(0,e.name+"."+t+" field config must be an object"),r.hasOwnProperty("isDeprecated")&&(0,F.default)(0,e.name+"."+t+' should provide "deprecationReason" instead of "isDeprecated".');var o=T({},r,{isDeprecated:Boolean(r.deprecationReason),name:t});c(o.type)||(0,F.default)(0,e.name+"."+t+" field type must be Output Type but got: "+String(o.type)+"."),S(o.resolve)||(0,F.default)(0,e.name+"."+t+" field resolver must be a function if provided, but got: "+String(o.resolve)+".");var a=r.args;a?(w(a)||(0,F.default)(0,e.name+"."+t+" args must be an object with argument names as keys."),o.args=Object.keys(a).map(function(n){(0,M.assertValidName)(n);var r=a[n];return s(r.type)||(0,F.default)(0,e.name+"."+t+"("+n+":) argument type must be Input Type but got: "+String(r.type)+"."),{name:n,description:void 0===r.description?null:r.description,type:r.type,defaultValue:r.defaultValue,astNode:r.astNode}})):o.args=[],i[t]=o}),i}function w(e){return e&&"object"===("undefined"===typeof e?"undefined":_(e))&&!Array.isArray(e)}function S(e){return null==e||"function"===typeof e}function k(e,t){var n=C(t);Array.isArray(n)&&n.length>0||(0,F.default)(0,"Must provide Array of types or a function which returns such an array for Union "+e.name+".");var r=Object.create(null);return n.forEach(function(t){t instanceof R||(0,F.default)(0,e.name+" may only contain Object types, it cannot contain: "+String(t)+"."),r[t.name]&&(0,F.default)(0,e.name+" can include "+t.name+" type only once."),r[t.name]=!0,"function"!==typeof e.resolveType&&"function"!==typeof t.isTypeOf&&(0,F.default)(0,'Union type "'+e.name+'" does not provide a "resolveType" function and possible type "'+t.name+'" does not provide an "isTypeOf" function. There is no way to resolve this possible type during execution.')}),n}function A(e,t){w(t)||(0,F.default)(0,e.name+" values must be an object with value names as keys.");var n=Object.keys(t);return n.length>0||(0,F.default)(0,e.name+" values must be an object with value names as keys."),n.map(function(n){(0,M.assertValidName)(n),-1!==["true","false","null"].indexOf(n)&&(0,F.default)(0,'Name "'+n+'" can not be used as an Enum value.');var r=t[n];return w(r)||(0,F.default)(0,e.name+"."+n+' must refer to an object with a "value" key representing an internal value but got: '+String(r)+"."),r.hasOwnProperty("isDeprecated")&&(0,F.default)(0,e.name+"."+n+' should provide "deprecationReason" instead of "isDeprecated".'),{name:n,description:r.description,isDeprecated:Boolean(r.deprecationReason),deprecationReason:r.deprecationReason,astNode:r.astNode,value:r.hasOwnProperty("value")?r.value:n}})}Object.defineProperty(t,"__esModule",{value:!0}),t.GraphQLNonNull=t.GraphQLList=t.GraphQLInputObjectType=t.GraphQLEnumType=t.GraphQLUnionType=t.GraphQLInterfaceType=t.GraphQLObjectType=t.GraphQLScalarType=void 0;var _="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},T=Object.assign||function(e){for(var t=1;t0||(0,F.default)(0,this.name+" fields must be an object with field names as keys or a function which returns such an object.");var r=Object.create(null);return n.forEach(function(n){(0,M.assertValidName)(n);var i=T({},t[n],{name:n});s(i.type)||(0,F.default)(0,e.name+"."+n+" field type must be Input Type but got: "+String(i.type)+"."),null!=i.resolve&&(0,F.default)(0,e.name+"."+n+" field type has a resolve property, but Input Types cannot define resolvers."),r[n]=i}),r},e.prototype.toString=function(){return this.name},e}();z.prototype.toJSON=z.prototype.inspect=z.prototype.toString;var G=t.GraphQLList=function(){function e(t){i(this,e),o(t)||(0,F.default)(0,"Can only create List of a GraphQLType but got: "+String(t)+"."),this.ofType=t}return e.prototype.toString=function(){return"["+String(this.ofType)+"]"},e}();G.prototype.toJSON=G.prototype.inspect=G.prototype.toString;var V=t.GraphQLNonNull=function(){function e(t){i(this,e),(!o(t)||t instanceof e)&&(0,F.default)(0,"Can only create NonNull of a Nullable GraphQLType but got: "+String(t)+"."),this.ofType=t}return e.prototype.toString=function(){return this.ofType.toString()+"!"},e}();V.prototype.toJSON=V.prototype.inspect=V.prototype.toString},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(390);Object.defineProperty(t,"graphql",{enumerable:!0,get:function(){return r.graphql}});var i=n(393);Object.defineProperty(t,"GraphQLSchema",{enumerable:!0,get:function(){return i.GraphQLSchema}}),Object.defineProperty(t,"GraphQLScalarType",{enumerable:!0,get:function(){return i.GraphQLScalarType}}),Object.defineProperty(t,"GraphQLObjectType",{enumerable:!0,get:function(){return i.GraphQLObjectType}}),Object.defineProperty(t,"GraphQLInterfaceType",{enumerable:!0,get:function(){return i.GraphQLInterfaceType}}),Object.defineProperty(t,"GraphQLUnionType",{enumerable:!0,get:function(){return i.GraphQLUnionType}}),Object.defineProperty(t,"GraphQLEnumType",{enumerable:!0,get:function(){return i.GraphQLEnumType}}),Object.defineProperty(t,"GraphQLInputObjectType",{enumerable:!0,get:function(){return i.GraphQLInputObjectType}}),Object.defineProperty(t,"GraphQLList",{enumerable:!0,get:function(){return i.GraphQLList}}),Object.defineProperty(t,"GraphQLNonNull",{enumerable:!0,get:function(){return i.GraphQLNonNull}}),Object.defineProperty(t,"GraphQLDirective",{enumerable:!0,get:function(){return i.GraphQLDirective}}),Object.defineProperty(t,"TypeKind",{enumerable:!0,get:function(){return i.TypeKind}}),Object.defineProperty(t,"DirectiveLocation",{enumerable:!0,get:function(){return i.DirectiveLocation}}),Object.defineProperty(t,"GraphQLInt",{enumerable:!0,get:function(){return i.GraphQLInt}}),Object.defineProperty(t,"GraphQLFloat",{enumerable:!0,get:function(){return i.GraphQLFloat}}),Object.defineProperty(t,"GraphQLString",{enumerable:!0,get:function(){return i.GraphQLString}}),Object.defineProperty(t,"GraphQLBoolean",{enumerable:!0,get:function(){return i.GraphQLBoolean}}),Object.defineProperty(t,"GraphQLID",{enumerable:!0,get:function(){return i.GraphQLID}}),Object.defineProperty(t,"specifiedDirectives",{enumerable:!0,get:function(){return i.specifiedDirectives}}),Object.defineProperty(t,"GraphQLIncludeDirective",{enumerable:!0,get:function(){return i.GraphQLIncludeDirective}}),Object.defineProperty(t,"GraphQLSkipDirective",{enumerable:!0,get:function(){return i.GraphQLSkipDirective}}),Object.defineProperty(t,"GraphQLDeprecatedDirective",{enumerable:!0,get:function(){return i.GraphQLDeprecatedDirective}}),Object.defineProperty(t,"DEFAULT_DEPRECATION_REASON",{enumerable:!0,get:function(){return i.DEFAULT_DEPRECATION_REASON}}),Object.defineProperty(t,"SchemaMetaFieldDef",{enumerable:!0,get:function(){return i.SchemaMetaFieldDef}}),Object.defineProperty(t,"TypeMetaFieldDef",{enumerable:!0,get:function(){return i.TypeMetaFieldDef}}),Object.defineProperty(t,"TypeNameMetaFieldDef",{enumerable:!0,get:function(){return i.TypeNameMetaFieldDef}}),Object.defineProperty(t,"__Schema",{enumerable:!0,get:function(){return i.__Schema}}),Object.defineProperty(t,"__Directive",{enumerable:!0,get:function(){return i.__Directive}}),Object.defineProperty(t,"__DirectiveLocation",{enumerable:!0,get:function(){return i.__DirectiveLocation}}),Object.defineProperty(t,"__Type",{enumerable:!0,get:function(){return i.__Type}}),Object.defineProperty(t,"__Field",{enumerable:!0,get:function(){return i.__Field}}),Object.defineProperty(t,"__InputValue",{enumerable:!0,get:function(){return i.__InputValue}}),Object.defineProperty(t,"__EnumValue",{enumerable:!0,get:function(){return i.__EnumValue}}),Object.defineProperty(t,"__TypeKind",{enumerable:!0,get:function(){return i.__TypeKind}}),Object.defineProperty(t,"isType",{enumerable:!0,get:function(){return i.isType}}),Object.defineProperty(t,"isInputType",{enumerable:!0,get:function(){return i.isInputType}}),Object.defineProperty(t,"isOutputType",{enumerable:!0,get:function(){return i.isOutputType}}),Object.defineProperty(t,"isLeafType",{enumerable:!0,get:function(){return i.isLeafType}}),Object.defineProperty(t,"isCompositeType",{enumerable:!0,get:function(){return i.isCompositeType}}),Object.defineProperty(t,"isAbstractType",{enumerable:!0,get:function(){return i.isAbstractType}}),Object.defineProperty(t,"isNamedType",{enumerable:!0,get:function(){return i.isNamedType}}),Object.defineProperty(t,"assertType",{enumerable:!0,get:function(){return i.assertType}}),Object.defineProperty(t,"assertInputType",{enumerable:!0,get:function(){return i.assertInputType}}),Object.defineProperty(t,"assertOutputType",{enumerable:!0,get:function(){return i.assertOutputType}}),Object.defineProperty(t,"assertLeafType",{enumerable:!0,get:function(){return i.assertLeafType}}),Object.defineProperty(t,"assertCompositeType",{enumerable:!0,get:function(){return i.assertCompositeType}}),Object.defineProperty(t,"assertAbstractType",{enumerable:!0,get:function(){return i.assertAbstractType}}),Object.defineProperty(t,"assertNamedType",{enumerable:!0,get:function(){return i.assertNamedType}}),Object.defineProperty(t,"getNullableType",{enumerable:!0,get:function(){return i.getNullableType}}),Object.defineProperty(t,"getNamedType",{enumerable:!0,get:function(){return i.getNamedType}});var o=n(394);Object.defineProperty(t,"Source",{enumerable:!0,get:function(){return o.Source}}),Object.defineProperty(t,"getLocation",{enumerable:!0,get:function(){return o.getLocation}}),Object.defineProperty(t,"parse",{enumerable:!0,get:function(){return o.parse}}),Object.defineProperty(t,"parseValue",{enumerable:!0,get:function(){return o.parseValue}}),Object.defineProperty(t,"parseType",{enumerable:!0,get:function(){return o.parseType}}),Object.defineProperty(t,"print",{enumerable:!0,get:function(){return o.print}}),Object.defineProperty(t,"visit",{enumerable:!0,get:function(){return o.visit}}),Object.defineProperty(t,"visitInParallel",{enumerable:!0,get:function(){return o.visitInParallel}}),Object.defineProperty(t,"visitWithTypeInfo",{enumerable:!0,get:function(){return o.visitWithTypeInfo}}),Object.defineProperty(t,"getVisitFn",{enumerable:!0,get:function(){return o.getVisitFn}}),Object.defineProperty(t,"Kind",{enumerable:!0,get:function(){return o.Kind}}),Object.defineProperty(t,"TokenKind",{enumerable:!0,get:function(){return o.TokenKind}}),Object.defineProperty(t,"BREAK",{enumerable:!0,get:function(){return o.BREAK}});var a=n(395);Object.defineProperty(t,"execute",{enumerable:!0,get:function(){return a.execute}}),Object.defineProperty(t,"defaultFieldResolver",{enumerable:!0,get:function(){return a.defaultFieldResolver}}),Object.defineProperty(t,"responsePathAsArray",{enumerable:!0,get:function(){return a.responsePathAsArray}}),Object.defineProperty(t,"getDirectiveValues",{enumerable:!0,get:function(){return a.getDirectiveValues}});var s=n(396);Object.defineProperty(t,"subscribe",{enumerable:!0,get:function(){return s.subscribe}}),Object.defineProperty(t,"createSourceEventStream",{enumerable:!0,get:function(){return s.createSourceEventStream}});var u=n(399);Object.defineProperty(t,"validate",{enumerable:!0,get:function(){return u.validate}}),Object.defineProperty(t,"ValidationContext",{enumerable:!0,get:function(){return u.ValidationContext}}),Object.defineProperty(t,"specifiedRules",{enumerable:!0,get:function(){return u.specifiedRules}}),Object.defineProperty(t,"ArgumentsOfCorrectTypeRule",{enumerable:!0,get:function(){return u.ArgumentsOfCorrectTypeRule}}),Object.defineProperty(t,"DefaultValuesOfCorrectTypeRule",{enumerable:!0,get:function(){return u.DefaultValuesOfCorrectTypeRule}}),Object.defineProperty(t,"FieldsOnCorrectTypeRule",{enumerable:!0,get:function(){return u.FieldsOnCorrectTypeRule}}),Object.defineProperty(t,"FragmentsOnCompositeTypesRule",{enumerable:!0,get:function(){return u.FragmentsOnCompositeTypesRule}}),Object.defineProperty(t,"KnownArgumentNamesRule",{enumerable:!0,get:function(){return u.KnownArgumentNamesRule}}),Object.defineProperty(t,"KnownDirectivesRule",{enumerable:!0,get:function(){return u.KnownDirectivesRule}}),Object.defineProperty(t,"KnownFragmentNamesRule",{enumerable:!0,get:function(){return u.KnownFragmentNamesRule}}),Object.defineProperty(t,"KnownTypeNamesRule",{enumerable:!0,get:function(){return u.KnownTypeNamesRule}}),Object.defineProperty(t,"LoneAnonymousOperationRule",{enumerable:!0,get:function(){return u.LoneAnonymousOperationRule}}),Object.defineProperty(t,"NoFragmentCyclesRule",{enumerable:!0,get:function(){return u.NoFragmentCyclesRule}}),Object.defineProperty(t,"NoUndefinedVariablesRule",{enumerable:!0,get:function(){return u.NoUndefinedVariablesRule}}),Object.defineProperty(t,"NoUnusedFragmentsRule",{enumerable:!0,get:function(){return u.NoUnusedFragmentsRule}}),Object.defineProperty(t,"NoUnusedVariablesRule",{enumerable:!0,get:function(){return u.NoUnusedVariablesRule}}),Object.defineProperty(t,"OverlappingFieldsCanBeMergedRule",{enumerable:!0,get:function(){return u.OverlappingFieldsCanBeMergedRule}}),Object.defineProperty(t,"PossibleFragmentSpreadsRule",{enumerable:!0,get:function(){return u.PossibleFragmentSpreadsRule}}),Object.defineProperty(t,"ProvidedNonNullArgumentsRule",{enumerable:!0,get:function(){return u.ProvidedNonNullArgumentsRule}}),Object.defineProperty(t,"ScalarLeafsRule",{enumerable:!0,get:function(){return u.ScalarLeafsRule}}),Object.defineProperty(t,"SingleFieldSubscriptionsRule",{enumerable:!0,get:function(){return u.SingleFieldSubscriptionsRule}}),Object.defineProperty(t,"UniqueArgumentNamesRule",{enumerable:!0,get:function(){return u.UniqueArgumentNamesRule}}),Object.defineProperty(t,"UniqueDirectivesPerLocationRule",{enumerable:!0,get:function(){return u.UniqueDirectivesPerLocationRule}}),Object.defineProperty(t,"UniqueFragmentNamesRule",{enumerable:!0,get:function(){return u.UniqueFragmentNamesRule}}),Object.defineProperty(t,"UniqueInputFieldNamesRule",{enumerable:!0,get:function(){return u.UniqueInputFieldNamesRule}}),Object.defineProperty(t,"UniqueOperationNamesRule",{enumerable:!0,get:function(){return u.UniqueOperationNamesRule}}),Object.defineProperty(t,"UniqueVariableNamesRule",{enumerable:!0,get:function(){return u.UniqueVariableNamesRule}}),Object.defineProperty(t,"VariablesAreInputTypesRule",{enumerable:!0,get:function(){return u.VariablesAreInputTypesRule}}),Object.defineProperty(t,"VariablesInAllowedPositionRule",{enumerable:!0,get:function(){return u.VariablesInAllowedPositionRule}});var c=n(3);Object.defineProperty(t,"GraphQLError",{enumerable:!0,get:function(){return c.GraphQLError}}),Object.defineProperty(t,"formatError",{enumerable:!0,get:function(){return c.formatError}});var l=n(400);Object.defineProperty(t,"introspectionQuery",{enumerable:!0,get:function(){return l.introspectionQuery}}),Object.defineProperty(t,"getOperationAST",{enumerable:!0,get:function(){return l.getOperationAST}}),Object.defineProperty(t,"buildClientSchema",{enumerable:!0,get:function(){return l.buildClientSchema}}),Object.defineProperty(t,"buildASTSchema",{enumerable:!0,get:function(){return l.buildASTSchema}}),Object.defineProperty(t,"buildSchema",{enumerable:!0,get:function(){return l.buildSchema}}),Object.defineProperty(t,"extendSchema",{enumerable:!0,get:function(){return l.extendSchema}}),Object.defineProperty(t,"printSchema",{enumerable:!0,get:function(){return l.printSchema}}),Object.defineProperty(t,"printIntrospectionSchema",{enumerable:!0,get:function(){return l.printIntrospectionSchema}}),Object.defineProperty(t,"printType",{enumerable:!0,get:function(){return l.printType}}),Object.defineProperty(t,"typeFromAST",{enumerable:!0,get:function(){return l.typeFromAST}}),Object.defineProperty(t,"valueFromAST",{enumerable:!0,get:function(){return l.valueFromAST}}),Object.defineProperty(t,"astFromValue",{enumerable:!0,get:function(){return l.astFromValue}}),Object.defineProperty(t,"TypeInfo",{enumerable:!0,get:function(){return l.TypeInfo}}),Object.defineProperty(t,"isValidJSValue",{enumerable:!0,get:function(){return l.isValidJSValue}}),Object.defineProperty(t,"isValidLiteralValue",{enumerable:!0,get:function(){return l.isValidLiteralValue}}),Object.defineProperty(t,"concatAST",{enumerable:!0,get:function(){return l.concatAST}}),Object.defineProperty(t,"separateOperations",{enumerable:!0,get:function(){return l.separateOperations}}),Object.defineProperty(t,"isEqualType",{enumerable:!0,get:function(){return l.isEqualType}}),Object.defineProperty(t,"isTypeSubTypeOf",{enumerable:!0,get:function(){return l.isTypeSubTypeOf}}),Object.defineProperty(t,"doTypesOverlap",{enumerable:!0,get:function(){return l.doTypesOverlap}}),Object.defineProperty(t,"assertValidName",{enumerable:!0,get:function(){return l.assertValidName}}),Object.defineProperty(t,"findBreakingChanges",{enumerable:!0,get:function(){return l.findBreakingChanges}}),Object.defineProperty(t,"findDangerousChanges",{enumerable:!0,get:function(){return l.findDangerousChanges}}),Object.defineProperty(t,"BreakingChangeType",{enumerable:!0,get:function(){return l.BreakingChangeType}}),Object.defineProperty(t,"DangerousChangeType",{enumerable:!0,get:function(){return l.DangerousChangeType}}),Object.defineProperty(t,"findDeprecatedUsages",{enumerable:!0,get:function(){return l.findDeprecatedUsages}})},function(e,t,n){"use strict";function r(e,t){return e===t}function i(e,t,n){if(null===t||null===n||t.length!==n.length)return!1;for(var r=t.length,i=0;i1&&void 0!==arguments[1]?arguments[1]:r,n=null,o=null;return function(){return i(t,n,arguments)||(o=e.apply(null,arguments)),n=arguments,o}}function a(e){var t=Array.isArray(e[0])?e[0]:e;if(!t.every(function(e){return"function"===typeof e})){var n=t.map(function(e){return typeof e}).join(", ");throw new Error("Selector creators expect all input-selectors to be functions, instead received the following types: ["+n+"]")}return t}function s(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:c;if("object"!==typeof e)throw new Error("createStructuredSelector expects first argument to be an object where each property is a selector, instead received a "+typeof e);var n=Object.keys(e);return t(n.map(function(t){return e[t]}),function(){for(var e=arguments.length,t=Array(e),r=0;r>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?a(e)+t:t}function u(){return!0}function c(e,t,n){return(0===e&&!d(e)||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function l(e,t){return f(e,t,0)}function p(e,t){return f(e,t,t)}function f(e,t,n){return void 0===e?n:d(e)?t===1/0?t:0|Math.max(0,t+e):void 0===t||t===e?e:0|Math.min(t,e)}function d(e){return e<0||0===e&&1/e===-1/0}function h(e){return m(e)||x(e)}function m(e){return!(!e||!e[hn])}function g(e){return!(!e||!e[mn])}function y(e){return!(!e||!e[gn])}function v(e){return g(e)||y(e)}function b(e){return!(!e||!e[yn])}function x(e){return!(!e||!e[vn])}function C(e){return!(!e||"function"!==typeof e.equals||"function"!==typeof e.hashCode)}function E(e,t,n,r){var i=0===e?t:1===e?n:[t,n];return r?r.value=i:r={value:i,done:!1},r}function D(){return{value:void 0,done:!0}}function w(e){return!!A(e)}function S(e){return e&&"function"===typeof e.next}function k(e){var t=A(e);return t&&t.call(e)}function A(e){var t=e&&(kn&&e[kn]||e[An]);if("function"===typeof t)return t}function _(e){return e&&"number"===typeof e.length}function T(e){return!(!e||!e[Pn])}function O(){return Rn||(Rn=new Mn([]))}function F(e){var t=Array.isArray(e)?new Mn(e):S(e)?new Un(e):w(e)?new $n(e):void 0;if(t)return t.fromEntrySeq();if("object"===typeof e)return new jn(e);throw new TypeError("Expected Array or collection object of [k, v] entries, or keyed object: "+e)}function N(e){var t=L(e);if(t)return t;throw new TypeError("Expected Array or collection object of values: "+e)}function I(e){var t=L(e);if(t)return t;if("object"===typeof e)return new jn(e);throw new TypeError("Expected Array or collection object of values, or keyed object: "+e)}function L(e){return _(e)?new Mn(e):S(e)?new Un(e):w(e)?new $n(e):void 0}function P(e,t){if(e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1;if("function"===typeof e.valueOf&&"function"===typeof t.valueOf){if(e=e.valueOf(),t=t.valueOf(),e===t||e!==e&&t!==t)return!0;if(!e||!t)return!1}return!!(C(e)&&C(t)&&e.equals(t))}function M(e){return e>>>1&1073741824|3221225471&e}function j(e){if(!1===e||null===e||void 0===e)return 0;if("function"===typeof e.valueOf&&(!1===(e=e.valueOf())||null===e||void 0===e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!==e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)e/=4294967295,n^=e;return M(n)}if("string"===t)return e.length>Qn?R(e):B(e);if("function"===typeof e.hashCode)return M(e.hashCode());if("object"===t)return $(e);if("function"===typeof e.toString)return B(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function R(e){var t=Yn[e];return void 0===t&&(t=B(e),Jn===Kn&&(Jn=0,Yn={}),Jn++,Yn[e]=t),t}function B(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}function z(e){var t=ue(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=ce,t.__iterateUncached=function(t,n){var r=this;return e.__iterate(function(e,n){return!1!==t(n,e,r)},n)},t.__iteratorUncached=function(t,n){if(t===Sn){var r=e.__iterator(t,n);return new Tn(function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e})}return e.__iterator(t===wn?Dn:wn,n)},t}function G(e,t,n){var r=ue(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,i){var o=e.get(r,pn);return o===pn?i:t.call(n,o,r,e)},r.__iterateUncached=function(r,i){var o=this;return e.__iterate(function(e,i,a){return!1!==r(t.call(n,e,i,a),i,o)},i)},r.__iteratorUncached=function(r,i){var o=e.__iterator(Sn,i);return new Tn(function(){var i=o.next();if(i.done)return i;var a=i.value,s=a[0];return E(r,s,t.call(n,a[1],s,e),i)})},r}function V(e,t){var n=this,r=ue(e);return r._iter=e,r.size=e.size,r.reverse=function(){return e},e.flip&&(r.flip=function(){var t=z(e);return t.reverse=function(){return e.flip()},t}),r.get=function(n,r){return e.get(t?n:-1-n,r)},r.has=function(n){return e.has(t?n:-1-n)},r.includes=function(t){return e.includes(t)},r.cacheResult=ce,r.__iterate=function(n,r){var i=this,o=0;return r&&a(e),e.__iterate(function(e,a){return n(e,t?a:r?i.size-++o:o++,i)},!r)},r.__iterator=function(r,i){var o=0;i&&a(e);var s=e.__iterator(Sn,!i);return new Tn(function(){var e=s.next();if(e.done)return e;var a=e.value;return E(r,t?a[0]:i?n.size-++o:o++,a[1],e)})},r}function q(e,t,n,r){var i=ue(e);return r&&(i.has=function(r){var i=e.get(r,pn);return i!==pn&&!!t.call(n,i,r,e)},i.get=function(r,i){var o=e.get(r,pn);return o!==pn&&t.call(n,o,r,e)?o:i}),i.__iterateUncached=function(i,o){var a=this,s=0;return e.__iterate(function(e,o,u){if(t.call(n,e,o,u))return s++,i(e,r?o:s-1,a)},o),s},i.__iteratorUncached=function(i,o){var a=e.__iterator(Sn,o),s=0;return new Tn(function(){for(;;){var o=a.next();if(o.done)return o;var u=o.value,c=u[0],l=u[1];if(t.call(n,l,c,e))return E(i,r?c:s++,l,o)}})},i}function H(e,t,n){var r=nr().asMutable();return e.__iterate(function(i,o){r.update(t.call(n,i,o,e),0,function(e){return e+1})}),r.asImmutable()}function W(e,t,n){var r=g(e),i=(b(e)?Cr():nr()).asMutable();e.__iterate(function(o,a){i.update(t.call(n,o,a,e),function(e){return e=e||[],e.push(r?[a,o]:o),e})});var o=se(e);return i.map(function(t){return oe(e,o(t))})}function Q(e,t,n,r){var i=e.size;if(c(t,n,i))return e;var o=l(t,i),a=p(n,i);if(o!==o||a!==a)return Q(e.toSeq().cacheResult(),t,n,r);var u,f=a-o;f===f&&(u=f<0?0:f);var d=ue(e);return d.size=0===u?u:e.size&&u||void 0,!r&&T(e)&&u>=0&&(d.get=function(t,n){return t=s(this,t),t>=0&&tu)return D();var e=i.next();return r||t===wn||e.done?e:t===Dn?E(t,s-1,void 0,e):E(t,s-1,e.value[1],e)})},d}function K(e,t,n){var r=ue(e);return r.__iterateUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterate(r,i);var a=0;return e.__iterate(function(e,i,s){return t.call(n,e,i,s)&&++a&&r(e,i,o)}),a},r.__iteratorUncached=function(r,i){var o=this;if(i)return this.cacheResult().__iterator(r,i);var a=e.__iterator(Sn,i),s=!0;return new Tn(function(){if(!s)return D();var e=a.next();if(e.done)return e;var i=e.value,u=i[0],c=i[1];return t.call(n,c,u,o)?r===Sn?e:E(r,u,c,e):(s=!1,D())})},r}function J(e,t,n,r){var i=ue(e);return i.__iterateUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterate(i,o);var s=!0,u=0;return e.__iterate(function(e,o,c){if(!s||!(s=t.call(n,e,o,c)))return u++,i(e,r?o:u-1,a)}),u},i.__iteratorUncached=function(i,o){var a=this;if(o)return this.cacheResult().__iterator(i,o);var s=e.__iterator(Sn,o),u=!0,c=0;return new Tn(function(){var e,o,l;do{if(e=s.next(),e.done)return r||i===wn?e:i===Dn?E(i,c++,void 0,e):E(i,c++,e.value[1],e);var p=e.value;o=p[0],l=p[1],u&&(u=t.call(n,l,o,a))}while(u);return i===Sn?e:E(i,o,l,e)})},i}function Y(e,t){var n=g(e),r=[e].concat(t).map(function(e){return m(e)?n&&(e=xn(e)):e=n?F(e):N(Array.isArray(e)?e:[e]),e}).filter(function(e){return 0!==e.size});if(0===r.length)return e;if(1===r.length){var i=r[0];if(i===e||n&&g(i)||y(e)&&y(i))return i}var o=new Mn(r);return n?o=o.toKeyedSeq():y(e)||(o=o.toSetSeq()),o=o.flatten(!0),o.size=r.reduce(function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}},0),o}function X(e,t,n){var r=ue(e);return r.__iterateUncached=function(i,o){function a(e,c){e.__iterate(function(e,o){return(!t||c0}function ie(e,t,n,r){var i=ue(e),o=new Mn(n).map(function(e){return e.size});return i.size=r?o.max():o.min(),i.__iterate=function(e,t){for(var n,r=this,i=this.__iterator(wn,t),o=0;!(n=i.next()).done&&!1!==e(n.value,o++,r););return o},i.__iteratorUncached=function(e,i){var o=n.map(function(e){return e=bn(e),k(i?e.reverse():e)}),a=0,s=!1;return new Tn(function(){var n;return s||(n=o.map(function(e){return e.next()}),s=r?n.every(function(e){return e.done}):n.some(function(e){return e.done})),s?D():E(e,a++,t.apply(null,n.map(function(e){return e.value})))})},i}function oe(e,t){return e===t?e:T(e)?t:e.constructor(t)}function ae(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function se(e){return g(e)?xn:y(e)?Cn:En}function ue(e){return Object.create((g(e)?Nn:y(e)?In:Ln).prototype)}function ce(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):Fn.prototype.cacheResult.call(this)}function le(e,t){return void 0===e&&void 0===t?0:void 0===e?1:void 0===t?-1:e>t?1:e0;)t[n]=arguments[n+1];return Le(this,t,e)}function Le(e,t,n){for(var r=[],i=0;i0;)t[n]=arguments[n+1];return $e(e,t)}function Me(e,t){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];return $e(t,n,e)}function je(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return Be(e,t)}function Re(e,t){for(var n=[],r=arguments.length-2;r-- >0;)n[r]=arguments[r+2];return Be(t,n,e)}function Be(e,t,n){return $e(e,t,Ue(n))}function $e(e,t,n){if(!ge(e))throw new TypeError("Cannot merge into non-data-structure value: "+e);if(h(e))return e.mergeWith?e.mergeWith.apply(e,[n].concat(t)):e.concat.apply(e,t);for(var r=Array.isArray(e),i=e,o=r?Cn:xn,a=r?function(t){i===e&&(i=xe(i)),i.push(t)}:function(t,r){var o=On.call(i,r),a=o&&n?n(i[r],t,r):t;o&&a===i[r]||(i===e&&(i=xe(i)),i[r]=a)},s=0;s0;)t[n]=arguments[n+1];return Be(this,t,e)}function Ve(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return De(this,e,et(),function(e){return $e(e,t)})}function qe(e){for(var t=[],n=arguments.length-1;n-- >0;)t[n]=arguments[n+1];return De(this,e,et(),function(e){return Be(e,t)})}function He(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this}function We(){return this.__ownerID?this:this.__ensureOwner(new o)}function Qe(){return this.__ensureOwner()}function Ke(){return this.__altered}function Je(e){return!(!e||!e[rr])}function Ye(e,t){return E(e,t[0],t[1])}function Xe(e,t){return{node:e,index:0,__prev:t}}function Ze(e,t,n,r){var i=Object.create(ir);return i.size=e,i._root=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function et(){return lr||(lr=Ze(0))}function tt(e,t,n){var i,o;if(e._root){var a=r(fn),s=r(dn);if(i=nt(e._root,e.__ownerID,0,void 0,t,n,a,s),!s.value)return e;o=e.size+(a.value?n===pn?-1:1:0)}else{if(n===pn)return e;o=1,i=new or(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=i,e.__hash=void 0,e.__altered=!0,e):i?Ze(o,i):et()}function nt(e,t,n,r,o,a,s,u){return e?e.update(t,n,r,o,a,s,u):a===pn?e:(i(u),i(s),new cr(t,r,[o,a]))}function rt(e){return e.constructor===cr||e.constructor===ur}function it(e,t,n,r,i){if(e.keyHash===r)return new ur(t,r,[e.entry,i]);var o,a=(0===n?e.keyHash:e.keyHash>>>n)&ln,s=(0===n?r:r>>>n)&ln,u=a===s?[it(e,t,n+un,r,i)]:(o=new cr(t,r,i),a>>=1)a[s]=1&n?t[o++]:void 0;return a[r]=i,new sr(e,o+1,a)}function ut(e){return e-=e>>1&1431655765,e=(858993459&e)+(e>>2&858993459),e=e+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function ct(e,t,n,r){var i=r?e:pe(e);return i[t]=n,i}function lt(e,t,n,r){var i=e.length+1;if(r&&t+1===i)return e[t]=n,e;for(var o=new Array(i),a=0,s=0;so?0:o-n,c=a-n;return c>cn&&(c=cn),function(){if(i===c)return xr;var e=t?--c:i++;return r&&r[e]}}function i(e,r,i){var s,u=e&&e.array,c=i>o?0:o-i>>r,l=1+(a-i>>r);return l>cn&&(l=cn),function(){for(;;){if(s){var e=s();if(e!==xr)return e;s=null}if(c===l)return xr;var o=t?--l:c++;s=n(u&&u[o],r-un,i+(o<=e.size||t<0)return e.withMutations(function(e){t<0?xt(e,t).set(0,n):xt(e,0,t+1).set(t,n)});t+=e._origin;var i=e._tail,o=e._root,a=r(dn);return t>=Ct(e._capacity)?i=yt(i,e.__ownerID,0,t,n,a):o=yt(o,e.__ownerID,e._level,t,n,a),a.value?e.__ownerID?(e._root=o,e._tail=i,e.__hash=void 0,e.__altered=!0,e):ht(e._origin,e._capacity,e._level,o,i):e}function yt(e,t,n,r,o,a){var s=r>>>n&ln,u=e&&s0){var l=e&&e.array[s],p=yt(l,t,n-un,r,o,a);return p===l?e:(c=vt(e,t),c.array[s]=p,c)}return u&&e.array[s]===o?e:(i(a),c=vt(e,t),void 0===o&&s===c.array.length-1?c.array.pop():c.array[s]=o,c)}function vt(e,t){return t&&e&&t===e.ownerID?e:new vr(e?e.array.slice():[],t)}function bt(e,t){if(t>=Ct(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&ln],r-=un;return n}}function xt(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new o,i=e._origin,a=e._capacity,s=i+t,u=void 0===n?a:n<0?a+n:i+n;if(s===i&&u===a)return e;if(s>=u)return e.clear();for(var c=e._level,l=e._root,p=0;s+p<0;)l=new vr(l&&l.array.length?[void 0,l]:[],r),c+=un,p+=1<=1<f?new vr([],r):h;if(h&&d>f&&sun;y-=un){var v=f>>>y&ln;g=g.array[v]=vt(g.array[v],r)}g.array[f>>>un&ln]=h}if(u=d)s-=d,u-=d,c=un,l=null,m=m&&m.removeBefore(r,0,s);else if(s>i||d>>c&ln;if(b!==d>>>c&ln)break;b&&(p+=(1<i&&(l=l.removeBefore(r,c,s-p)),l&&d>>un<=cn&&a.size>=2*o.size?(i=a.filter(function(e,t){return void 0!==e&&s!==t}),r=i.toKeyedSeq().map(function(e){return e[0]}).flip().toMap(),e.__ownerID&&(r.__ownerID=i.__ownerID=e.__ownerID)):(r=o.remove(t),i=s===a.size-1?a.pop():a.set(s,void 0))}else if(u){if(n===a.get(s)[1])return e;r=o,i=a.set(s,[t,n])}else r=o.set(t,a.size),i=a.set(a.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=i,e.__hash=void 0,e):Dt(r,i)}function kt(e){return!(!e||!e[wr])}function At(e,t,n,r){var i=Object.create(Sr);return i.size=e,i._head=t,i.__ownerID=n,i.__hash=r,i.__altered=!1,i}function _t(){return kr||(kr=At(0))}function Tt(e,t){if(e===t)return!0;if(!m(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||g(e)!==g(t)||y(e)!==y(t)||b(e)!==b(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!v(e);if(b(e)){var r=e.entries();return t.every(function(e,t){var i=r.next().value;return i&&P(i[1],e)&&(n||P(i[0],t))})&&r.next().done}var i=!1;if(void 0===e.size)if(void 0===t.size)"function"===typeof e.cacheResult&&e.cacheResult();else{i=!0;var o=e;e=t,t=o}var a=!0,s=t.__iterate(function(t,r){if(n?!e.has(t):i?!P(t,e.get(r,pn)):!P(e.get(r,pn),t))return a=!1,!1});return a&&e.size===s}function Ot(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}function Ft(e){return ge(e)?Fn(e).map(Ft).toJSON():e}function Nt(e){return!(!e||!e[_r])}function It(e,t){return e.__ownerID?(e.size=t.size,e._map=t,e):t===e._map?e:0===t.size?e.__empty():e.__make(t)}function Lt(e,t){var n=Object.create(Tr);return n.size=e?e.size:0,n._map=e,n.__ownerID=t,n}function Pt(){return Or||(Or=Lt(et()))}function Mt(e,t,n){for(var r=he(t),i=0;i!==r.length;)if((e=be(e,r[i++],pn))===pn)return n;return e}function jt(e,t){return Mt(this,e,t)}function Rt(e,t){return Mt(e,t,pn)!==pn}function Bt(e){return Rt(this,e)}function $t(){de(this.size);var e={};return this.__iterate(function(t,n){e[n]=t}),e}function Ut(e,t,n,r,i,o){return de(e.size),e.__iterate(function(e,o,a){i?(i=!1,n=e):n=t.call(r,n,e,o,a)},o),n}function zt(e,t){return t}function Gt(e,t){return[t,e]}function Vt(e){return function(){return!e.apply(this,arguments)}}function qt(e){return function(){return-e.apply(this,arguments)}}function Ht(){return pe(arguments)}function Wt(e,t){return et?-1:0}function Qt(e){if(e.size===1/0)return 0;var t=b(e),n=g(e),r=t?1:0;return Kt(e.__iterate(n?t?function(e,t){r=31*r+Jt(j(e),j(t))|0}:function(e,t){r=r+Jt(j(e),j(t))|0}:t?function(e){r=31*r+j(e)|0}:function(e){r=r+j(e)|0}),r)}function Kt(e,t){return t=zn(t,3432918353),t=zn(t<<15|t>>>-15,461845907),t=zn(t<<13|t>>>-13,5),t=(t+3864292196|0)^e,t=zn(t^t>>>16,2246822507),t=zn(t^t>>>13,3266489909),t=M(t^t>>>16)}function Jt(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}function Yt(e){return Nt(e)&&b(e)}function Xt(e,t){var n=Object.create(jr);return n.size=e?e.size:0,n._map=e,n.__ownerID=t,n}function Zt(){return Rr||(Rr=Xt(wt()))}function en(e,t,n){var r=Object.create(Object.getPrototypeOf(e));return r._values=t,r.__ownerID=n,r}function tn(e){return e._name||e.constructor.name||"Record"}function nn(e){return F(e._keys.map(function(t){return[t,e.get(t)]}))}function rn(e,t){try{Object.defineProperty(e,t,{get:function(){return this.get(t)},set:function(e){fe(this.__ownerID,"Cannot set on an immutable record."),this.set(t,e)}})}catch(e){}}function on(e,t){return an([],t||sn,e,"",t&&t.length>2?[]:void 0,{"":e})}function an(e,t,n,r,i,o){var a=Array.isArray(n)?In:me(n)?Nn:null;if(a){if(~e.indexOf(n))throw new TypeError("Cannot convert circular structure to Immutable");e.push(n),i&&""!==r&&i.push(r);var s=t.call(o,r,a(n).map(function(r,o){return an(e,t,r,o,i,n)}),i&&i.slice());return e.pop(),i&&i.pop(),s}return n}function sn(e,t){return g(t)?t.toMap():t.toList()}Object.defineProperty(t,"__esModule",{value:!0}),n.d(t,"version",function(){return Gr}),n.d(t,"Collection",function(){return bn}),n.d(t,"Iterable",function(){return qr}),n.d(t,"Seq",function(){return Fn}),n.d(t,"Map",function(){return nr}),n.d(t,"OrderedMap",function(){return Cr}),n.d(t,"List",function(){return mr}),n.d(t,"Stack",function(){return Dr}),n.d(t,"Set",function(){return Ar}),n.d(t,"OrderedSet",function(){return Mr}),n.d(t,"Record",function(){return Br}),n.d(t,"Range",function(){return Nr}),n.d(t,"Repeat",function(){return zr}),n.d(t,"is",function(){return P}),n.d(t,"fromJS",function(){return on}),n.d(t,"hash",function(){return j}),n.d(t,"isImmutable",function(){return h}),n.d(t,"isCollection",function(){return m}),n.d(t,"isKeyed",function(){return g}),n.d(t,"isIndexed",function(){return y}),n.d(t,"isAssociative",function(){return v}),n.d(t,"isOrdered",function(){return b}),n.d(t,"isValueObject",function(){return C}),n.d(t,"get",function(){return be}),n.d(t,"getIn",function(){return Mt}),n.d(t,"has",function(){return ve}),n.d(t,"hasIn",function(){return Rt}),n.d(t,"merge",function(){return Pe}),n.d(t,"mergeDeep",function(){return je}),n.d(t,"mergeWith",function(){return Me}),n.d(t,"mergeDeepWith",function(){return Re}),n.d(t,"remove",function(){return Ce}),n.d(t,"removeIn",function(){return Ae}),n.d(t,"set",function(){return Ee}),n.d(t,"setIn",function(){return Se}),n.d(t,"update",function(){return Te}),n.d(t,"updateIn",function(){return De});var un=5,cn=1<=r.length){var t=n.next();if(t.done)return t;r[i]=t.value}return E(e,i,r[i++])})},t}(In),zn="function"===typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){e|=0,t|=0;var n=65535&e,r=65535&t;return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0},Gn=Object.isExtensible,Vn=function(){try{return Object.defineProperty({},"@",{}),!0}catch(e){return!1}}(),qn="function"===typeof WeakMap;qn&&(Bn=new WeakMap);var Hn=0,Wn="__immutablehash__";"function"===typeof Symbol&&(Wn=Symbol(Wn));var Qn=16,Kn=255,Jn=0,Yn={},Xn=function(e){function t(e,t){this._iter=e,this._useKeys=t,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.get=function(e,t){return this._iter.get(e,t)},t.prototype.has=function(e){return this._iter.has(e)},t.prototype.valueSeq=function(){return this._iter.valueSeq()},t.prototype.reverse=function(){var e=this,t=V(this,!0);return this._useKeys||(t.valueSeq=function(){return e._iter.toSeq().reverse()}),t},t.prototype.map=function(e,t){var n=this,r=G(this,e,t);return this._useKeys||(r.valueSeq=function(){return n._iter.toSeq().map(e,t)}),r},t.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t,r){return e(t,r,n)},t)},t.prototype.__iterator=function(e,t){return this._iter.__iterator(e,t)},t}(Nn);Xn.prototype[yn]=!0;var Zn=function(e){function t(e){this._iter=e,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.includes=function(e){return this._iter.includes(e)},t.prototype.__iterate=function(e,t){var n=this,r=0;return t&&a(this),this._iter.__iterate(function(i){return e(i,t?n.size-++r:r++,n)},t)},t.prototype.__iterator=function(e,t){var n=this,r=this._iter.__iterator(wn,t),i=0;return t&&a(this),new Tn(function(){var o=r.next();return o.done?o:E(e,t?n.size-++i:i++,o.value,o)})},t}(In),er=function(e){function t(e){this._iter=e,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.has=function(e){return this._iter.includes(e)},t.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){return e(t,t,n)},t)},t.prototype.__iterator=function(e,t){var n=this._iter.__iterator(wn,t);return new Tn(function(){var t=n.next();return t.done?t:E(e,t.value,t.value,t)})},t}(Ln),tr=function(e){function t(e){this._iter=e,this.size=e.size}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.prototype.entrySeq=function(){return this._iter.toSeq()},t.prototype.__iterate=function(e,t){var n=this;return this._iter.__iterate(function(t){if(t){ae(t);var r=m(t);return e(r?t.get(1):t[1],r?t.get(0):t[0],n)}},t)},t.prototype.__iterator=function(e,t){var n=this._iter.__iterator(wn,t);return new Tn(function(){for(;;){var t=n.next();if(t.done)return t;var r=t.value;if(r){ae(r);var i=m(r);return E(e,i?r.get(0):r[0],i?r.get(1):r[1],t)}}})},t}(Nn);Zn.prototype.cacheResult=Xn.prototype.cacheResult=er.prototype.cacheResult=tr.prototype.cacheResult=ce;var nr=function(e){function t(t){return null===t||void 0===t?et():Je(t)&&!b(t)?t:et().withMutations(function(n){var r=e(t);de(r.size),r.forEach(function(e,t){return n.set(t,e)})})}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){for(var e=[],t=arguments.length;t--;)e[t]=arguments[t];return et().withMutations(function(t){for(var n=0;n=e.length)throw new Error("Missing value for key: "+e[n]);t.set(e[n],e[n+1])}})},t.prototype.toString=function(){return this.__toString("Map {","}")},t.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},t.prototype.set=function(e,t){return tt(this,e,t)},t.prototype.remove=function(e){return tt(this,e,pn)},t.prototype.deleteAll=function(e){var t=bn(e);return 0===t.size?this:this.withMutations(function(e){t.forEach(function(t){return e.remove(t)})})},t.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):et()},t.prototype.sort=function(e){return Cr(te(this,e))},t.prototype.sortBy=function(e,t){return Cr(te(this,t,e))},t.prototype.__iterator=function(e,t){return new pr(this,e,t)},t.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate(function(t){return r++,e(t[1],t[0],n)},t),r},t.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Ze(this.size,this._root,e,this.__hash):0===this.size?et():(this.__ownerID=e,this.__altered=!1,this)},t}(xn);nr.isMap=Je;var rr="@@__IMMUTABLE_MAP__@@",ir=nr.prototype;ir[rr]=!0,ir.delete=ir.remove,ir.removeAll=ir.deleteAll,ir.concat=ir.merge,ir.setIn=ke,ir.removeIn=ir.deleteIn=_e,ir.update=Oe,ir.updateIn=Fe,ir.merge=Ne,ir.mergeWith=Ie,ir.mergeDeep=ze,ir.mergeDeepWith=Ge,ir.mergeIn=Ve,ir.mergeDeepIn=qe,ir.withMutations=He,ir.wasAltered=Ke,ir.asImmutable=Qe,ir["@@transducer/init"]=ir.asMutable=We,ir["@@transducer/step"]=function(e,t){return e.set(t[0],t[1])},ir["@@transducer/result"]=function(e){return e.asImmutable()};var or=function(e,t){this.ownerID=e,this.entries=t};or.prototype.get=function(e,t,n,r){for(var i=this.entries,o=0,a=i.length;o=fr)return ot(e,c,r,o);var d=e&&e===this.ownerID,h=d?c:pe(c);return f?u?l===p-1?h.pop():h[l]=h.pop():h[l]=[r,o]:h.push([r,o]),d?(this.entries=h,this):new or(e,h)}};var ar=function(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n};ar.prototype.get=function(e,t,n,r){void 0===t&&(t=j(n));var i=1<<((0===e?t:t>>>e)&ln),o=this.bitmap;return 0===(o&i)?r:this.nodes[ut(o&i-1)].get(e+un,t,n,r)},ar.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=j(r));var s=(0===t?n:n>>>t)&ln,u=1<=dr)return st(e,f,c,s,h);if(l&&!h&&2===f.length&&rt(f[1^p]))return f[1^p];if(l&&h&&1===f.length&&rt(h))return h;var m=e&&e===this.ownerID,g=l?h?c:c^u:c|u,y=l?h?ct(f,p,h,m):pt(f,p,m):lt(f,p,h,m);return m?(this.bitmap=g,this.nodes=y,this):new ar(e,g,y)};var sr=function(e,t,n){this.ownerID=e,this.count=t,this.nodes=n};sr.prototype.get=function(e,t,n,r){void 0===t&&(t=j(n));var i=(0===e?t:t>>>e)&ln,o=this.nodes[i];return o?o.get(e+un,t,n,r):r},sr.prototype.update=function(e,t,n,r,i,o,a){void 0===n&&(n=j(r));var s=(0===t?n:n>>>t)&ln,u=i===pn,c=this.nodes,l=c[s];if(u&&!l)return this;var p=nt(l,e,t+un,n,r,i,o,a);if(p===l)return this;var f=this.count;if(l){if(!p&&--f0&&i=0&&e>>t&ln;if(r>=this.array.length)return new vr([],e);var i,o=0===r;if(t>0){var a=this.array[r];if((i=a&&a.removeBefore(e,t-un,n))===a&&o)return this}if(o&&!i)return this;var s=vt(this,e);if(!o)for(var u=0;u>>t&ln;if(r>=this.array.length)return this;var i;if(t>0){var o=this.array[r];if((i=o&&o.removeAfter(e,t-un,n))===o&&r===this.array.length-1)return this}var a=vt(this,e);return a.array.splice(r+1),i&&(a.array[r]=i),a};var br,xr={},Cr=function(e){function t(e){return null===e||void 0===e?wt():Et(e)?e:wt().withMutations(function(t){var n=xn(e);de(n.size),n.forEach(function(e,n){return t.set(n,e)})})}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){return this(arguments)},t.prototype.toString=function(){return this.__toString("OrderedMap {","}")},t.prototype.get=function(e,t){var n=this._map.get(e);return void 0!==n?this._list.get(n)[1]:t},t.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._map.clear(),this._list.clear(),this):wt()},t.prototype.set=function(e,t){return St(this,e,t)},t.prototype.remove=function(e){return St(this,e,pn)},t.prototype.wasAltered=function(){return this._map.wasAltered()||this._list.wasAltered()},t.prototype.__iterate=function(e,t){var n=this;return this._list.__iterate(function(t){return t&&e(t[1],t[0],n)},t)},t.prototype.__iterator=function(e,t){return this._list.fromEntrySeq().__iterator(e,t)},t.prototype.__ensureOwner=function(e){if(e===this.__ownerID)return this;var t=this._map.__ensureOwner(e),n=this._list.__ensureOwner(e);return e?Dt(t,n,e,this.__hash):0===this.size?wt():(this.__ownerID=e,this._map=t,this._list=n,this)},t}(nr);Cr.isOrderedMap=Et,Cr.prototype[yn]=!0,Cr.prototype.delete=Cr.prototype.remove;var Er,Dr=function(e){function t(e){return null===e||void 0===e?_t():kt(e)?e:_t().pushAll(e)}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){return this(arguments)},t.prototype.toString=function(){return this.__toString("Stack [","]")},t.prototype.get=function(e,t){var n=this._head;for(e=s(this,e);n&&e--;)n=n.next;return n?n.value:t},t.prototype.peek=function(){return this._head&&this._head.value},t.prototype.push=function(){var e=arguments;if(0===arguments.length)return this;for(var t=this.size+arguments.length,n=this._head,r=arguments.length-1;r>=0;r--)n={value:e[r],next:n};return this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):At(t,n)},t.prototype.pushAll=function(t){if(t=e(t),0===t.size)return this;if(0===this.size&&kt(t))return t;de(t.size);var n=this.size,r=this._head;return t.__iterate(function(e){n++,r={value:e,next:r}},!0),this.__ownerID?(this.size=n,this._head=r,this.__hash=void 0,this.__altered=!0,this):At(n,r)},t.prototype.pop=function(){return this.slice(1)},t.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):_t()},t.prototype.slice=function(t,n){if(c(t,n,this.size))return this;var r=l(t,this.size);if(p(n,this.size)!==this.size)return e.prototype.slice.call(this,t,n);for(var i=this.size-r,o=this._head;r--;)o=o.next;return this.__ownerID?(this.size=i,this._head=o,this.__hash=void 0,this.__altered=!0,this):At(i,o)},t.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?At(this.size,this._head,e,this.__hash):0===this.size?_t():(this.__ownerID=e,this.__altered=!1,this)},t.prototype.__iterate=function(e,t){var n=this;if(t)return new Mn(this.toArray()).__iterate(function(t,r){return e(t,r,n)},t);for(var r=0,i=this._head;i&&!1!==e(i.value,r++,n);)i=i.next;return r},t.prototype.__iterator=function(e,t){if(t)return new Mn(this.toArray()).__iterator(e,t);var n=0,r=this._head;return new Tn(function(){if(r){var t=r.value;return r=r.next,E(e,n++,t)}return D()})},t}(Cn);Dr.isStack=kt;var wr="@@__IMMUTABLE_STACK__@@",Sr=Dr.prototype;Sr[wr]=!0,Sr.shift=Sr.pop,Sr.unshift=Sr.push,Sr.unshiftAll=Sr.pushAll,Sr.withMutations=He,Sr.wasAltered=Ke,Sr.asImmutable=Qe,Sr["@@transducer/init"]=Sr.asMutable=We,Sr["@@transducer/step"]=function(e,t){return e.unshift(t)},Sr["@@transducer/result"]=function(e){return e.asImmutable()};var kr,Ar=function(e){function t(t){return null===t||void 0===t?Pt():Nt(t)&&!b(t)?t:Pt().withMutations(function(n){var r=e(t);de(r.size),r.forEach(function(e){return n.add(e)})})}return e&&(t.__proto__=e),t.prototype=Object.create(e&&e.prototype),t.prototype.constructor=t,t.of=function(){return this(arguments)},t.fromKeys=function(e){return this(xn(e).keySeq())},t.intersect=function(e){return e=bn(e).toArray(),e.length?Tr.intersect.apply(t(e.pop()),e):Pt()},t.union=function(e){return e=bn(e).toArray(),e.length?Tr.union.apply(t(e.pop()),e):Pt()},t.prototype.toString=function(){return this.__toString("Set {","}")},t.prototype.has=function(e){return this._map.has(e)},t.prototype.add=function(e){return It(this,this._map.set(e,e))},t.prototype.remove=function(e){return It(this,this._map.remove(e))},t.prototype.clear=function(){return It(this,this._map.clear())},t.prototype.union=function(){for(var t=[],n=arguments.length;n--;)t[n]=arguments[n];return t=t.filter(function(e){return 0!==e.size}),0===t.length?this:0!==this.size||this.__ownerID||1!==t.length?this.withMutations(function(n){for(var r=0;r=0&&t=0&&nthis.size?t:this.find(function(t,n){return n===e},void 0,t)},has:function(e){return(e=s(this,e))>=0&&(void 0!==this.size?this.size===1/0||e=0&&e.splice(n,1)}function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=d({},e),n=new Promise(function(e,n){t.resolve=e,t.reject=n});return t.promise=n,t}function s(e){for(var t=[],n=0;n1&&void 0!==arguments[1])||arguments[1],n=void 0,r=new Promise(function(r){n=setTimeout(function(){return r(t)},e)});return r[b]=function(){return clearTimeout(n)},r}function c(){var e,t=!0,n=void 0,r=void 0;return e={},e[g]=!0,e.isRunning=function(){return t},e.result=function(){return n},e.error=function(){return r},e.setRunning=function(e){return t=e},e.setResult=function(e){return n=e},e.setError=function(e){return r=e},e}function l(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:F,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments[3],i={name:n,next:e,throw:t,return:N};return r&&(i[y]=!0),"undefined"!==typeof Symbol&&(i[Symbol.iterator]=function(){return i}),i}function p(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";"undefined"===typeof window?console.log("redux-saga "+e+": "+t+"\n"+(n&&n.stack||n)):console[e](t,n)}function f(e,t){return function(){return e.apply(void 0,arguments)}}n.d(t,"x",function(){return m}),n.d(t,"e",function(){return g}),n.d(t,"b",function(){return v}),n.d(t,"a",function(){return b}),n.d(t,"c",function(){return x}),n.d(t,"d",function(){return C}),n.d(t,"r",function(){return D}),n.d(t,"u",function(){return w}),n.d(t,"o",function(){return S}),t.h=r,n.d(t,"q",function(){return A}),n.d(t,"v",function(){return _}),t.w=o,n.d(t,"f",function(){return T}),t.l=a,t.g=s,t.m=u,t.j=c,n.d(t,"y",function(){return O}),t.t=l,t.s=p,t.n=f,n.d(t,"z",function(){return I}),n.d(t,"p",function(){return L}),n.d(t,"k",function(){return P}),n.d(t,"A",function(){return M}),n.d(t,"i",function(){return j});var d=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:0;return function(){return++e}}(),F=function(e){throw e},N=function(e){return{value:e,done:!0}},I=function(e,t){return e+" has been deprecated in favor of "+t+", please update your code"},L=function(e){return new Error("\n redux-saga: Error checking hooks detected an inconsistent state. This is likely a bug\n in redux-saga code and not yours. Thanks for reporting this in the project's github repo.\n Error: "+e+"\n")},P=function(e,t){return(e?e+".":"")+"setContext(props): argument "+t+" is not a plain object"},M=function(e){return function(t){return e(Object.defineProperty(t,x,{value:!0}))}},j=function e(t){return function(){for(var n=arguments.length,r=Array(n),i=0;i if provided but got: "+String(t.directives)+"."),this._directives=t.directives||c.specifiedDirectives,this.astNode=t.astNode||null;var r=[this.getQueryType(),this.getMutationType(),this.getSubscriptionType(),l.__Schema],p=t.types;p&&(r=r.concat(p)),this._typeMap=r.reduce(o,Object.create(null)),this._implementations=Object.create(null),Object.keys(this._typeMap).forEach(function(e){var t=n._typeMap[e];t instanceof u.GraphQLObjectType&&t.getInterfaces().forEach(function(e){var r=n._implementations[e.name];r?r.push(t):n._implementations[e.name]=[t]})}),Object.keys(this._typeMap).forEach(function(e){var t=n._typeMap[e];t instanceof u.GraphQLObjectType&&t.getInterfaces().forEach(function(e){return a(n,t,e)})})}return e.prototype.getQueryType=function(){return this._queryType},e.prototype.getMutationType=function(){return this._mutationType},e.prototype.getSubscriptionType=function(){return this._subscriptionType},e.prototype.getTypeMap=function(){return this._typeMap},e.prototype.getType=function(e){return this.getTypeMap()[e]},e.prototype.getPossibleTypes=function(e){return e instanceof u.GraphQLUnionType?e.getTypes():(e instanceof u.GraphQLInterfaceType||(0,h.default)(0),this._implementations[e.name])},e.prototype.isPossibleType=function(e,t){var n=this._possibleTypeMap;if(n||(this._possibleTypeMap=n=Object.create(null)),!n[e.name]){var r=this.getPossibleTypes(e);Array.isArray(r)||(0,h.default)(0,"Could not find possible implementing types for "+e.name+" in schema. Check that schema.types is defined and is an array of all possible types in the schema."),n[e.name]=r.reduce(function(e,t){return e[t.name]=!0,e},Object.create(null))}return Boolean(n[e.name][t.name])},e.prototype.getDirectives=function(){return this._directives},e.prototype.getDirective=function(e){return(0,f.default)(this.getDirectives(),function(t){return t.name===e})},e}()},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0}),t.specifiedDirectives=t.GraphQLDeprecatedDirective=t.DEFAULT_DEPRECATION_REASON=t.GraphQLSkipDirective=t.GraphQLIncludeDirective=t.GraphQLDirective=t.DirectiveLocation=void 0;var i=n(6),o=n(32),a=n(13),s=function(e){return e&&e.__esModule?e:{default:e}}(a),u=n(111),c=t.DirectiveLocation={QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"},l=t.GraphQLDirective=function e(t){r(this,e),t.name||(0,s.default)(0,"Directive must be named."),(0,u.assertValidName)(t.name),Array.isArray(t.locations)||(0,s.default)(0,"Must provide locations for directive."),this.name=t.name,this.description=t.description,this.locations=t.locations,this.astNode=t.astNode;var n=t.args;n?(Array.isArray(n)&&(0,s.default)(0,"@"+t.name+" args must be an object with argument names as keys."),this.args=Object.keys(n).map(function(e){(0,u.assertValidName)(e);var r=n[e];return(0,i.isInputType)(r.type)||(0,s.default)(0,"@"+t.name+"("+e+":) argument type must be Input Type but got: "+String(r.type)+"."),{name:e,description:void 0===r.description?null:r.description,type:r.type,defaultValue:r.defaultValue,astNode:r.astNode}})):this.args=[]},p=t.GraphQLIncludeDirective=new l({name:"include",description:"Directs the executor to include this field or fragment only when the `if` argument is true.",locations:[c.FIELD,c.FRAGMENT_SPREAD,c.INLINE_FRAGMENT],args:{if:{type:new i.GraphQLNonNull(o.GraphQLBoolean),description:"Included when true."}}}),f=t.GraphQLSkipDirective=new l({name:"skip",description:"Directs the executor to skip this field or fragment when the `if` argument is true.",locations:[c.FIELD,c.FRAGMENT_SPREAD,c.INLINE_FRAGMENT],args:{if:{type:new i.GraphQLNonNull(o.GraphQLBoolean),description:"Skipped when true."}}}),d=t.DEFAULT_DEPRECATION_REASON="No longer supported",h=t.GraphQLDeprecatedDirective=new l({name:"deprecated",description:"Marks an element of a GraphQL schema as no longer supported.",locations:[c.FIELD_DEFINITION,c.ENUM_VALUE],args:{reason:{type:o.GraphQLString,description:"Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).",defaultValue:d}}});t.specifiedDirectives=[p,f,h]},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TypeNameMetaFieldDef=t.TypeMetaFieldDef=t.SchemaMetaFieldDef=t.__TypeKind=t.TypeKind=t.__EnumValue=t.__InputValue=t.__Field=t.__Type=t.__DirectiveLocation=t.__Directive=t.__Schema=void 0;var r=n(58),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=n(112),a=n(19),s=n(6),u=n(32),c=n(27),l=t.__Schema=new s.GraphQLObjectType({name:"__Schema",isIntrospection:!0,description:"A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.",fields:function(){return{types:{description:"A list of all types supported by this server.",type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(d))),resolve:function(e){var t=e.getTypeMap();return Object.keys(t).map(function(e){return t[e]})}},queryType:{description:"The type that query operations will be rooted at.",type:new s.GraphQLNonNull(d),resolve:function(e){return e.getQueryType()}},mutationType:{description:"If this server supports mutation, the type that mutation operations will be rooted at.",type:d,resolve:function(e){return e.getMutationType()}},subscriptionType:{description:"If this server support subscription, the type that subscription operations will be rooted at.",type:d,resolve:function(e){return e.getSubscriptionType()}},directives:{description:"A list of all directives supported by this server.",type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(p))),resolve:function(e){return e.getDirectives()}}}}}),p=t.__Directive=new s.GraphQLObjectType({name:"__Directive",isIntrospection:!0,description:"A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},locations:{type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(f)))},args:{type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(m))),resolve:function(e){return e.args||[]}},onOperation:{deprecationReason:"Use `locations`.",type:new s.GraphQLNonNull(u.GraphQLBoolean),resolve:function(e){return-1!==e.locations.indexOf(c.DirectiveLocation.QUERY)||-1!==e.locations.indexOf(c.DirectiveLocation.MUTATION)||-1!==e.locations.indexOf(c.DirectiveLocation.SUBSCRIPTION)}},onFragment:{deprecationReason:"Use `locations`.",type:new s.GraphQLNonNull(u.GraphQLBoolean),resolve:function(e){return-1!==e.locations.indexOf(c.DirectiveLocation.FRAGMENT_SPREAD)||-1!==e.locations.indexOf(c.DirectiveLocation.INLINE_FRAGMENT)||-1!==e.locations.indexOf(c.DirectiveLocation.FRAGMENT_DEFINITION)}},onField:{deprecationReason:"Use `locations`.",type:new s.GraphQLNonNull(u.GraphQLBoolean),resolve:function(e){return-1!==e.locations.indexOf(c.DirectiveLocation.FIELD)}}}}}),f=t.__DirectiveLocation=new s.GraphQLEnumType({name:"__DirectiveLocation",isIntrospection:!0,description:"A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.",values:{QUERY:{value:c.DirectiveLocation.QUERY,description:"Location adjacent to a query operation."},MUTATION:{value:c.DirectiveLocation.MUTATION,description:"Location adjacent to a mutation operation."},SUBSCRIPTION:{value:c.DirectiveLocation.SUBSCRIPTION,description:"Location adjacent to a subscription operation."},FIELD:{value:c.DirectiveLocation.FIELD,description:"Location adjacent to a field."},FRAGMENT_DEFINITION:{value:c.DirectiveLocation.FRAGMENT_DEFINITION,description:"Location adjacent to a fragment definition."},FRAGMENT_SPREAD:{value:c.DirectiveLocation.FRAGMENT_SPREAD,description:"Location adjacent to a fragment spread."},INLINE_FRAGMENT:{value:c.DirectiveLocation.INLINE_FRAGMENT,description:"Location adjacent to an inline fragment."},SCHEMA:{value:c.DirectiveLocation.SCHEMA,description:"Location adjacent to a schema definition."},SCALAR:{value:c.DirectiveLocation.SCALAR,description:"Location adjacent to a scalar definition."},OBJECT:{value:c.DirectiveLocation.OBJECT,description:"Location adjacent to an object type definition."},FIELD_DEFINITION:{value:c.DirectiveLocation.FIELD_DEFINITION,description:"Location adjacent to a field definition."},ARGUMENT_DEFINITION:{value:c.DirectiveLocation.ARGUMENT_DEFINITION,description:"Location adjacent to an argument definition."},INTERFACE:{value:c.DirectiveLocation.INTERFACE,description:"Location adjacent to an interface definition."},UNION:{value:c.DirectiveLocation.UNION,description:"Location adjacent to a union definition."},ENUM:{value:c.DirectiveLocation.ENUM,description:"Location adjacent to an enum definition."},ENUM_VALUE:{value:c.DirectiveLocation.ENUM_VALUE,description:"Location adjacent to an enum value definition."},INPUT_OBJECT:{value:c.DirectiveLocation.INPUT_OBJECT,description:"Location adjacent to an input object type definition."},INPUT_FIELD_DEFINITION:{value:c.DirectiveLocation.INPUT_FIELD_DEFINITION,description:"Location adjacent to an input object field definition."}}}),d=t.__Type=new s.GraphQLObjectType({name:"__Type",isIntrospection:!0,description:"The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.",fields:function(){return{kind:{type:new s.GraphQLNonNull(v),resolve:function(e){if(e instanceof s.GraphQLScalarType)return y.SCALAR;if(e instanceof s.GraphQLObjectType)return y.OBJECT;if(e instanceof s.GraphQLInterfaceType)return y.INTERFACE;if(e instanceof s.GraphQLUnionType)return y.UNION;if(e instanceof s.GraphQLEnumType)return y.ENUM;if(e instanceof s.GraphQLInputObjectType)return y.INPUT_OBJECT;if(e instanceof s.GraphQLList)return y.LIST;if(e instanceof s.GraphQLNonNull)return y.NON_NULL;throw new Error("Unknown kind of type: "+e)}},name:{type:u.GraphQLString},description:{type:u.GraphQLString},fields:{type:new s.GraphQLList(new s.GraphQLNonNull(h)),args:{includeDeprecated:{type:u.GraphQLBoolean,defaultValue:!1}},resolve:function(e,t){var n=t.includeDeprecated;if(e instanceof s.GraphQLObjectType||e instanceof s.GraphQLInterfaceType){var r=e.getFields(),i=Object.keys(r).map(function(e){return r[e]});return n||(i=i.filter(function(e){return!e.deprecationReason})),i}return null}},interfaces:{type:new s.GraphQLList(new s.GraphQLNonNull(d)),resolve:function(e){if(e instanceof s.GraphQLObjectType)return e.getInterfaces()}},possibleTypes:{type:new s.GraphQLList(new s.GraphQLNonNull(d)),resolve:function(e,t,n,r){var i=r.schema;if((0,s.isAbstractType)(e))return i.getPossibleTypes(e)}},enumValues:{type:new s.GraphQLList(new s.GraphQLNonNull(g)),args:{includeDeprecated:{type:u.GraphQLBoolean,defaultValue:!1}},resolve:function(e,t){var n=t.includeDeprecated;if(e instanceof s.GraphQLEnumType){var r=e.getValues();return n||(r=r.filter(function(e){return!e.deprecationReason})),r}}},inputFields:{type:new s.GraphQLList(new s.GraphQLNonNull(m)),resolve:function(e){if(e instanceof s.GraphQLInputObjectType){var t=e.getFields();return Object.keys(t).map(function(e){return t[e]})}}},ofType:{type:d}}}}),h=t.__Field=new s.GraphQLObjectType({name:"__Field",isIntrospection:!0,description:"Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},args:{type:new s.GraphQLNonNull(new s.GraphQLList(new s.GraphQLNonNull(m))),resolve:function(e){return e.args||[]}},type:{type:new s.GraphQLNonNull(d)},isDeprecated:{type:new s.GraphQLNonNull(u.GraphQLBoolean)},deprecationReason:{type:u.GraphQLString}}}}),m=t.__InputValue=new s.GraphQLObjectType({name:"__InputValue",isIntrospection:!0,description:"Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},type:{type:new s.GraphQLNonNull(d)},defaultValue:{type:u.GraphQLString,description:"A GraphQL-formatted string representing the default value for this input value.",resolve:function(e){return(0,i.default)(e.defaultValue)?null:(0,a.print)((0,o.astFromValue)(e.defaultValue,e.type))}}}}}),g=t.__EnumValue=new s.GraphQLObjectType({name:"__EnumValue",isIntrospection:!0,description:"One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.",fields:function(){return{name:{type:new s.GraphQLNonNull(u.GraphQLString)},description:{type:u.GraphQLString},isDeprecated:{type:new s.GraphQLNonNull(u.GraphQLBoolean)},deprecationReason:{type:u.GraphQLString}}}}),y=t.TypeKind={SCALAR:"SCALAR",OBJECT:"OBJECT",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",INPUT_OBJECT:"INPUT_OBJECT",LIST:"LIST",NON_NULL:"NON_NULL"},v=t.__TypeKind=new s.GraphQLEnumType({name:"__TypeKind",isIntrospection:!0,description:"An enum describing what kind of type a given `__Type` is.",values:{SCALAR:{value:y.SCALAR,description:"Indicates this type is a scalar."},OBJECT:{value:y.OBJECT,description:"Indicates this type is an object. `fields` and `interfaces` are valid fields."},INTERFACE:{value:y.INTERFACE,description:"Indicates this type is an interface. `fields` and `possibleTypes` are valid fields."},UNION:{value:y.UNION,description:"Indicates this type is a union. `possibleTypes` is a valid field."},ENUM:{value:y.ENUM,description:"Indicates this type is an enum. `enumValues` is a valid field."},INPUT_OBJECT:{value:y.INPUT_OBJECT,description:"Indicates this type is an input object. `inputFields` is a valid field."},LIST:{value:y.LIST,description:"Indicates this type is a list. `ofType` is a valid field."},NON_NULL:{value:y.NON_NULL,description:"Indicates this type is a non-null. `ofType` is a valid field."}}});t.SchemaMetaFieldDef={name:"__schema",type:new s.GraphQLNonNull(l),description:"Access the current type schema of this server.",args:[],resolve:function(e,t,n,r){return r.schema}},t.TypeMetaFieldDef={name:"__type",type:d,description:"Request the type information of a single type.",args:[{name:"name",type:new s.GraphQLNonNull(u.GraphQLString)}],resolve:function(e,t,n,r){var i=t.name;return r.schema.getType(i)}},t.TypeNameMetaFieldDef={name:"__typename",type:new s.GraphQLNonNull(u.GraphQLString),description:"The name of the current Object type at runtime.",args:[],resolve:function(e,t,n,r){return r.parentType.name}}},function(e,t,n){"use strict";function r(e,t){var n=void 0;return t.kind===s.LIST_TYPE?(n=c(e,t.type))&&new u.GraphQLList(n):t.kind===s.NON_NULL_TYPE?(n=c(e,t.type))&&new u.GraphQLNonNull(n):(t.kind!==s.NAMED_TYPE&&(0,o.default)(0,"Must be a named type."),e.getType(t.name.value))}Object.defineProperty(t,"__esModule",{value:!0}),t.typeFromAST=void 0;var i=n(13),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=n(10),s=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(a),u=n(6),c=t.typeFromAST=r},function(e,t,n){"use strict";function r(){if("undefined"!==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(r)}catch(e){console.error(e)}}r(),e.exports=n(314)},function(e,t,n){"use strict";function r(e){return null!=e&&"object"==typeof e}t.a=r},function(e,t,n){"use strict";function r(e){if(""===e)throw new TypeError("Int cannot represent non 32-bit signed integer value: (empty string)");var t=Number(e);if(t!==t||t>c||t=l)return t}return null}}),t.GraphQLFloat=new a.GraphQLScalarType({name:"Float",description:"The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](http://en.wikipedia.org/wiki/IEEE_floating_point). ",serialize:i,parseValue:i,parseLiteral:function(e){return e.kind===u.FLOAT||e.kind===u.INT?parseFloat(e.value):null}}),t.GraphQLString=new a.GraphQLScalarType({name:"String",description:"The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.",serialize:o,parseValue:o,parseLiteral:function(e){return e.kind===u.STRING?e.value:null}}),t.GraphQLBoolean=new a.GraphQLScalarType({name:"Boolean",description:"The `Boolean` scalar type represents `true` or `false`.",serialize:Boolean,parseValue:Boolean,parseLiteral:function(e){return e.kind===u.BOOLEAN?e.value:null}}),t.GraphQLID=new a.GraphQLScalarType({name:"ID",description:'The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `"4"`) or integer (such as `4`) input value will be accepted as an ID.',serialize:String,parseValue:String,parseLiteral:function(e){return e.kind===u.STRING||e.kind===u.INT?e.value:null}})},function(e,t,n){"use strict";function r(e){return null==e?void 0===e?u:s:c&&c in Object(e)?Object(o.a)(e):Object(a.a)(e)}var i=n(103),o=n(349),a=n(350),s="[object Null]",u="[object Undefined]",c=i.a?i.a.toStringTag:void 0;t.a=r},function(e,t,n){"use strict";function r(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"*";if(arguments.length&&Object(w.h)(arguments[0],w.q.notUndef,"take(patternOrChannel): patternOrChannel is undefined"),w.q.pattern(e))return G(A,{pattern:e});if(w.q.channel(e))return G(A,{channel:e});throw new Error("take(patternOrChannel): argument "+String(e)+" is not valid channel or a valid pattern")}function i(e,t){return arguments.length>1?(Object(w.h)(e,w.q.notUndef,"put(channel, action): argument channel is undefined"),Object(w.h)(e,w.q.channel,"put(channel, action): argument "+e+" is not a valid channel"),Object(w.h)(t,w.q.notUndef,"put(channel, action): argument action is undefined")):(Object(w.h)(e,w.q.notUndef,"put(action): argument action is undefined"),t=e,e=null),G(_,{channel:e,action:t})}function o(e){return G(T,e)}function a(e){return G(O,e)}function s(e,t,n){Object(w.h)(t,w.q.notUndef,e+": argument fn is undefined");var r=null;if(w.q.array(t)){var i=t;r=i[0],t=i[1]}else if(t.fn){var o=t;r=o.context,t=o.fn}return r&&w.q.string(t)&&w.q.func(r[t])&&(t=r[t]),Object(w.h)(t,w.q.func,e+": argument "+t+" is not a function"),{context:r,fn:t,args:n}}function u(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:[];return G(F,s("apply",{context:e,fn:t},n))}function l(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r1?t-1:0),r=1;r1?t-1:0),r=1;r1)return o(t.map(function(e){return d(e)}));var r=t[0];return Object(w.h)(r,w.q.notUndef,"join(task): argument task is undefined"),Object(w.h)(r,w.q.task,"join(task): argument "+r+" is not a valid Task object "+z),G(L,r)}function h(){for(var e=arguments.length,t=Array(e),n=0;n1)return o(t.map(function(e){return h(e)}));var r=t[0];return 1===t.length&&(Object(w.h)(r,w.q.notUndef,"cancel(task): argument task is undefined"),Object(w.h)(r,w.q.task,"cancel(task): argument "+r+" is not a valid Task object "+z)),G(P,r||w.d)}function m(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r1&&(Object(w.h)(t,w.q.notUndef,"actionChannel(pattern, buffer): argument buffer is undefined"),Object(w.h)(t,w.q.buffer,"actionChannel(pattern, buffer): argument "+t+" is not a valid buffer")),G(j,{pattern:e,buffer:t})}function y(){return G(R,{})}function v(e){return Object(w.h)(e,w.q.channel,"flush(channel): argument "+e+" is not valid channel"),G(B,e)}function b(e){return Object(w.h)(e,w.q.string,"getContext(prop): argument "+e+" is not a string"),G($,e)}function x(e){return Object(w.h)(e,w.q.object,Object(w.k)(null,e)),G(U,e)}function C(e,t){for(var n=arguments.length,r=Array(n>2?n-2:0),i=2;i2?n-2:0),i=2;i3?r-3:0),o=3;o
'+e+""}Object.defineProperty(t,"__esModule",{value:!0});var o=n(592);t.default=r}).call(t,n(11))},function(e,t,n){!function(e){e(n(2))}(function(e){"use strict";function t(e){var t=e.search(o);return-1==t?0:t}function n(e,t,n){return/\bstring\b/.test(e.getTokenTypeAt(a(t.line,0)))&&!/^[\'\"\`]/.test(n)}function r(e,t){var n=e.getMode();return!1!==n.useInnerComments&&n.innerMode?e.getModeAt(t):n}var i={},o=/[^\s\u00a0]/,a=e.Pos;e.commands.toggleComment=function(e){e.toggleComment()},e.defineExtension("toggleComment",function(e){e||(e=i);for(var t=this,n=1/0,r=this.listSelections(),o=null,s=r.length-1;s>=0;s--){var u=r[s].from(),c=r[s].to();u.line>=n||(c.line>=n&&(c=a(n,0)),n=u.line,null==o?t.uncomment(u,c,e)?o="un":(t.lineComment(u,c,e),o="line"):"un"==o?t.uncomment(u,c,e):t.lineComment(u,c,e))}}),e.defineExtension("lineComment",function(e,s,u){u||(u=i);var c=this,l=r(c,e),p=c.getLine(e.line);if(null!=p&&!n(c,e,p)){var f=u.lineComment||l.lineComment;if(!f)return void((u.blockCommentStart||l.blockCommentStart)&&(u.fullLines=!0,c.blockComment(e,s,u)));var d=Math.min(0!=s.ch||s.line==e.line?s.line+1:s.line,c.lastLine()+1),h=null==u.padding?" ":u.padding,m=u.commentBlankLines||e.line==s.line;c.operation(function(){if(u.indent){for(var n=null,r=e.line;rs.length)&&(n=s)}for(var r=e.line;rp||s.operation(function(){if(0!=n.fullLines){var r=o.test(s.getLine(p));s.replaceRange(f+l,a(p)),s.replaceRange(c+f,a(e.line,0));var i=n.blockCommentLead||u.blockCommentLead;if(null!=i)for(var d=e.line+1;d<=p;++d)(d!=p||r)&&s.replaceRange(i+f,a(d,0))}else s.replaceRange(l,t),s.replaceRange(c,e)})}}),e.defineExtension("uncomment",function(e,t,n){n||(n=i);var s,u=this,c=r(u,e),l=Math.min(0!=t.ch||t.line==e.line?t.line:t.line-1,u.lastLine()),p=Math.min(e.line,l),f=n.lineComment||c.lineComment,d=[],h=null==n.padding?" ":n.padding;e:if(f){for(var m=p;m<=l;++m){var g=u.getLine(m),y=g.indexOf(f);if(y>-1&&!/comment/.test(u.getTokenTypeAt(a(m,y+1)))&&(y=-1),-1==y&&o.test(g))break e;if(y>-1&&o.test(g.slice(0,y)))break e;d.push(g)}if(u.operation(function(){for(var e=p;e<=l;++e){var t=d[e-p],n=t.indexOf(f),r=n+f.length;n<0||(t.slice(r,r+h.length)==h&&(r+=h.length),s=!0,u.replaceRange("",a(e,n),a(e,r)))}}),s)return!0}var v=n.blockCommentStart||c.blockCommentStart,b=n.blockCommentEnd||c.blockCommentEnd;if(!v||!b)return!1;var x=n.blockCommentLead||c.blockCommentLead,C=u.getLine(p),E=C.indexOf(v);if(-1==E)return!1;var D=l==p?C:u.getLine(l),w=D.indexOf(b,l==p?E+v.length:0),S=a(p,E+1),k=a(l,w+1);if(-1==w||!/comment/.test(u.getTokenTypeAt(S))||!/comment/.test(u.getTokenTypeAt(k))||u.getRange(S,k,"\n").indexOf(b)>-1)return!1;var A=C.lastIndexOf(v,e.ch),_=-1==A?-1:C.slice(0,e.ch).indexOf(b,A+v.length);if(-1!=A&&-1!=_&&_+b.length!=e.ch)return!1;_=D.indexOf(b,t.ch);var T=D.slice(t.ch).lastIndexOf(v,_-t.ch);return A=-1==_||-1==T?-1:t.ch+T,(-1==_||-1==A||A==t.ch)&&(u.operation(function(){u.replaceRange("",a(l,w-(h&&D.slice(w-h.length,w)==h?h.length:0)),a(l,w+b.length));var e=E+v.length;if(h&&C.slice(e,e+h.length)==h&&(e+=h.length),u.replaceRange("",a(p,E),a(p,e)),x)for(var t=p+1;t<=l;++t){var n=u.getLine(t),r=n.indexOf(x);if(-1!=r&&!o.test(n.slice(0,r))){var i=r+x.length;h&&n.slice(i,i+h.length)==h&&(i+=h.length),u.replaceRange("",a(t,r),a(t,i))}}}),!0)})})},function(e,t,n){!function(e){e(n(2),n(38),n(39))}(function(e){"use strict";function t(e,t){return"string"==typeof e?e=new RegExp(e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&"),t?"gi":"g"):e.global||(e=new RegExp(e.source,e.ignoreCase?"gi":"g")),{token:function(t){e.lastIndex=t.pos;var n=e.exec(t.string);if(n&&n.index==t.pos)return t.pos+=n[0].length||1,"searching";n?t.pos=n.index:t.skipToEnd()}}}function n(){this.posFrom=this.posTo=this.lastQuery=this.query=null,this.overlay=null}function r(e){return e.state.search||(e.state.search=new n)}function i(e){return"string"==typeof e&&e==e.toLowerCase()}function o(e,t,n){return e.getSearchCursor(t,n,{caseFold:i(t),multiline:!0})}function a(e,t,n,r,i){e.openDialog(t,r,{value:n,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){h(e)},onKeyDown:i})}function s(e,t,n,r,i){e.openDialog?e.openDialog(t,i,{value:r,selectValueOnOpen:!0}):i(prompt(n,r))}function u(e,t,n,r){e.openConfirm?e.openConfirm(t,r):confirm(n)&&r[0]()}function c(e){return e.replace(/\\(.)/g,function(e,t){return"n"==t?"\n":"r"==t?"\r":t})}function l(e){var t=e.match(/^\/(.*)\/([a-z]*)$/);if(t)try{e=new RegExp(t[1],-1==t[2].indexOf("i")?"":"i")}catch(e){}else e=c(e);return("string"==typeof e?""==e:e.test(""))&&(e=/x^/),e}function p(e,n,r){n.queryText=r,n.query=l(r),e.removeOverlay(n.overlay,i(n.query)),n.overlay=t(n.query,i(n.query)),e.addOverlay(n.overlay),e.showMatchesOnScrollbar&&(n.annotate&&(n.annotate.clear(),n.annotate=null),n.annotate=e.showMatchesOnScrollbar(n.query,i(n.query)))}function f(t,n,i,o){var u=r(t);if(u.query)return d(t,n);var c=t.getSelection()||u.lastQuery;if(c instanceof RegExp&&"x^"==c.source&&(c=null),i&&t.openDialog){var l=null,f=function(n,r){e.e_stop(r),n&&(n!=u.queryText&&(p(t,u,n),u.posFrom=u.posTo=t.getCursor()),l&&(l.style.opacity=1),d(t,r.shiftKey,function(e,n){var r;n.line<3&&document.querySelector&&(r=t.display.wrapper.querySelector(".CodeMirror-dialog"))&&r.getBoundingClientRect().bottom-4>t.cursorCoords(n,"window").top&&((l=r).style.opacity=.4)}))};a(t,y,c,f,function(n,i){var o=e.keyName(n),a=t.getOption("extraKeys"),s=a&&a[o]||e.keyMap[t.getOption("keyMap")][o];"findNext"==s||"findPrev"==s||"findPersistentNext"==s||"findPersistentPrev"==s?(e.e_stop(n),p(t,r(t),i),t.execCommand(s)):"find"!=s&&"findPersistent"!=s||(e.e_stop(n),f(i,n))}),o&&c&&(p(t,u,c),d(t,n))}else s(t,y,"Search for:",c,function(e){e&&!u.query&&t.operation(function(){p(t,u,e),u.posFrom=u.posTo=t.getCursor(),d(t,n)})})}function d(t,n,i){t.operation(function(){var a=r(t),s=o(t,a.query,n?a.posFrom:a.posTo);(s.find(n)||(s=o(t,a.query,n?e.Pos(t.lastLine()):e.Pos(t.firstLine(),0)),s.find(n)))&&(t.setSelection(s.from(),s.to()),t.scrollIntoView({from:s.from(),to:s.to()},20),a.posFrom=s.from(),a.posTo=s.to(),i&&i(s.from(),s.to()))})}function h(e){e.operation(function(){var t=r(e);t.lastQuery=t.query,t.query&&(t.query=t.queryText=null,e.removeOverlay(t.overlay),t.annotate&&(t.annotate.clear(),t.annotate=null))})}function m(e,t,n){e.operation(function(){for(var r=o(e,t);r.findNext();)if("string"!=typeof t){var i=e.getRange(r.from(),r.to()).match(t);r.replace(n.replace(/\$(\d)/g,function(e,t){return i[t]}))}else r.replace(n)})}function g(e,t){if(!e.getOption("readOnly")){var n=e.getSelection()||r(e).lastQuery,i=''+(t?"Replace all:":"Replace:")+"";s(e,i+v,i,n,function(n){n&&(n=l(n),s(e,b,"Replace with:","",function(r){if(r=c(r),t)m(e,n,r);else{h(e);var i=o(e,n,e.getCursor("from")),a=function(){var t,c=i.from();!(t=i.findNext())&&(i=o(e,n),!(t=i.findNext())||c&&i.from().line==c.line&&i.from().ch==c.ch)||(e.setSelection(i.from(),i.to()),e.scrollIntoView({from:i.from(),to:i.to()}),u(e,x,"Replace?",[function(){s(t)},a,function(){m(e,n,r)}]))},s=function(e){i.replace("string"==typeof n?r:r.replace(/\$(\d)/g,function(t,n){return e[n]})),a()};a()}}))})}}var y='Search: (Use /re/ syntax for regexp search)',v=' (Use /re/ syntax for regexp search)',b='With: ',x='Replace? ';e.commands.find=function(e){h(e),f(e)},e.commands.findPersistent=function(e){h(e),f(e,!1,!0)},e.commands.findPersistentNext=function(e){f(e,!1,!0,!0)},e.commands.findPersistentPrev=function(e){f(e,!0,!0,!0)},e.commands.findNext=f,e.commands.findPrev=function(e){f(e,!0)},e.commands.clearSearch=h,e.commands.replace=g,e.commands.replaceAll=function(e){g(e,!0)}})},function(e,t,n){"use strict";function r(e){return{style:"keyword",match:function(t){return"Name"===t.kind&&t.value===e}}}function i(e){return{style:e,match:function(e){return"Name"===e.kind},update:function(e,t){e.name=t.value}}}Object.defineProperty(t,"__esModule",{value:!0}),t.ParseRules=t.LexRules=t.isIgnored=void 0;var o=n(276);t.isIgnored=function(e){return" "===e||"\t"===e||","===e||"\n"===e||"\r"===e||"\ufeff"===e},t.LexRules={Name:/^[_A-Za-z][_0-9A-Za-z]*/,Punctuation:/^(?:!|\$|\(|\)|\.\.\.|:|=|@|\[|]|\{|\||\})/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^(?:"""(?:\\"""|[^"]|"[^"]|""[^"])*(?:""")?|"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?)/,Comment:/^#.*/},t.ParseRules={Document:[(0,o.list)("Definition")],Definition:function(e){switch(e.value){case"{":return"ShortQuery";case"query":return"Query";case"mutation":return"Mutation";case"subscription":return"Subscription";case"fragment":return"FragmentDefinition";case"schema":return"SchemaDef";case"scalar":return"ScalarDef";case"type":return"ObjectTypeDef";case"interface":return"InterfaceDef";case"union":return"UnionDef";case"enum":return"EnumDef";case"input":return"InputDef";case"extend":return"ExtendDef";case"directive":return"DirectiveDef"}},ShortQuery:["SelectionSet"],Query:[r("query"),(0,o.opt)(i("def")),(0,o.opt)("VariableDefinitions"),(0,o.list)("Directive"),"SelectionSet"],Mutation:[r("mutation"),(0,o.opt)(i("def")),(0,o.opt)("VariableDefinitions"),(0,o.list)("Directive"),"SelectionSet"],Subscription:[r("subscription"),(0,o.opt)(i("def")),(0,o.opt)("VariableDefinitions"),(0,o.list)("Directive"),"SelectionSet"],VariableDefinitions:[(0,o.p)("("),(0,o.list)("VariableDefinition"),(0,o.p)(")")],VariableDefinition:["Variable",(0,o.p)(":"),"Type",(0,o.opt)("DefaultValue")],Variable:[(0,o.p)("$","variable"),i("variable")],DefaultValue:[(0,o.p)("="),"Value"],SelectionSet:[(0,o.p)("{"),(0,o.list)("Selection"),(0,o.p)("}")],Selection:function(e,t){return"..."===e.value?t.match(/[\s\u00a0,]*(on\b|@|{)/,!1)?"InlineFragment":"FragmentSpread":t.match(/[\s\u00a0,]*:/,!1)?"AliasedField":"Field"},AliasedField:[i("property"),(0,o.p)(":"),i("qualifier"),(0,o.opt)("Arguments"),(0,o.list)("Directive"),(0,o.opt)("SelectionSet")],Field:[i("property"),(0,o.opt)("Arguments"),(0,o.list)("Directive"),(0,o.opt)("SelectionSet")],Arguments:[(0,o.p)("("),(0,o.list)("Argument"),(0,o.p)(")")],Argument:[i("attribute"),(0,o.p)(":"),"Value"],FragmentSpread:[(0,o.p)("..."),i("def"),(0,o.list)("Directive")],InlineFragment:[(0,o.p)("..."),(0,o.opt)("TypeCondition"),(0,o.list)("Directive"),"SelectionSet"],FragmentDefinition:[r("fragment"),(0,o.opt)((0,o.butNot)(i("def"),[r("on")])),"TypeCondition",(0,o.list)("Directive"),"SelectionSet"],TypeCondition:[r("on"),"NamedType"],Value:function(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue";case"$":return"Variable"}return null;case"Name":switch(e.value){case"true":case"false":return"BooleanValue"}return"null"===e.value?"NullValue":"EnumValue"}},NumberValue:[(0,o.t)("Number","number")],StringValue:[(0,o.t)("String","string")],BooleanValue:[(0,o.t)("Name","builtin")],NullValue:[(0,o.t)("Name","keyword")],EnumValue:[i("string-2")],ListValue:[(0,o.p)("["),(0,o.list)("Value"),(0,o.p)("]")],ObjectValue:[(0,o.p)("{"),(0,o.list)("ObjectField"),(0,o.p)("}")],ObjectField:[i("attribute"),(0,o.p)(":"),"Value"],Type:function(e){return"["===e.value?"ListType":"NonNullType"},ListType:[(0,o.p)("["),"Type",(0,o.p)("]"),(0,o.opt)((0,o.p)("!"))],NonNullType:["NamedType",(0,o.opt)((0,o.p)("!"))],NamedType:[function(e){return{style:e,match:function(e){return"Name"===e.kind},update:function(e,t){e.prevState&&e.prevState.prevState&&(e.name=t.value,e.prevState.prevState.type=t.value)}}}("atom")],Directive:[(0,o.p)("@","meta"),i("meta"),(0,o.opt)("Arguments")],SchemaDef:[r("schema"),(0,o.list)("Directive"),(0,o.p)("{"),(0,o.list)("OperationTypeDef"),(0,o.p)("}")],OperationTypeDef:[i("keyword"),(0,o.p)(":"),i("atom")],ScalarDef:[r("scalar"),i("atom"),(0,o.list)("Directive")],ObjectTypeDef:[r("type"),i("atom"),(0,o.opt)("Implements"),(0,o.list)("Directive"),(0,o.p)("{"),(0,o.list)("FieldDef"),(0,o.p)("}")],Implements:[r("implements"),(0,o.list)("NamedType")],FieldDef:[i("property"),(0,o.opt)("ArgumentsDef"),(0,o.p)(":"),"Type",(0,o.list)("Directive")],ArgumentsDef:[(0,o.p)("("),(0,o.list)("InputValueDef"),(0,o.p)(")")],InputValueDef:[i("attribute"),(0,o.p)(":"),"Type",(0,o.opt)("DefaultValue"),(0,o.list)("Directive")],InterfaceDef:[r("interface"),i("atom"),(0,o.list)("Directive"),(0,o.p)("{"),(0,o.list)("FieldDef"),(0,o.p)("}")],UnionDef:[r("union"),i("atom"),(0,o.list)("Directive"),(0,o.p)("="),(0,o.list)("UnionMember",(0,o.p)("|"))],UnionMember:["NamedType"],EnumDef:[r("enum"),i("atom"),(0,o.list)("Directive"),(0,o.p)("{"),(0,o.list)("EnumValueDef"),(0,o.p)("}")],EnumValueDef:[i("string-2"),(0,o.list)("Directive")],InputDef:[r("input"),i("atom"),(0,o.list)("Directive"),(0,o.p)("{"),(0,o.list)("InputValueDef"),(0,o.p)("}")],ExtendDef:[r("extend"),"ObjectTypeDef"],DirectiveDef:[r("directive"),(0,o.p)("@","meta"),i("meta"),(0,o.opt)("ArgumentsDef"),r("on"),(0,o.list)("DirectiveLocation",(0,o.p)("|"))],DirectiveLocation:[i("string-2")]}},function(e,t,n){"use strict";function r(e){return{ofRule:e}}function i(e,t){return{ofRule:e,isList:!0,separator:t}}function o(e,t){var n=e.match;return e.match=function(e){var r=!1;return n&&(r=n(e)),r&&t.every(function(t){return t.match&&!t.match(e)})},e}function a(e,t){return{style:t,match:function(t){return t.kind===e}}}function s(e,t){return{style:t||"punctuation",match:function(t){return"Punctuation"===t.kind&&t.value===e}}}Object.defineProperty(t,"__esModule",{value:!0}),t.opt=r,t.list=i,t.butNot=o,t.t=a,t.p=s},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){var n=e.slice(0,t),r=n.split("\n").length-1,i=n.lastIndexOf("\n");return new s(r,t-i-1)}function o(e,t){var n=i(e,t.start),r=i(e,t.end);return new a(n,r)}Object.defineProperty(t,"__esModule",{value:!0}),t.offsetToPosition=i,t.locToRange=o;var a=t.Range=function(){function e(t,n){var i=this;r(this,e),this.containsPosition=function(e){return i.start.line===e.line?i.start.character<=e.character:i.end.line===e.line?i.end.character>=e.character:i.start.line<=e.line&&i.end.line>=e.line},this.start=t,this.end=n}return e.prototype.setStart=function(e,t){this.start=new s(e,t)},e.prototype.setEnd=function(e,t){this.end=new s(e,t)},e}(),s=t.Position=function(){function e(t,n){var i=this;r(this,e),this.lessThanOrEqualTo=function(e){return i.line=0;s--)if(u[s]!==c[s])return!1;for(s=u.length-1;s>=0;s--)if(a=u[s],!d(e[a],t[a],n,r))return!1;return!0}function g(e,t,n){d(e,t,!0)&&p(e,t,n,"notDeepStrictEqual",g)}function y(e,t){if(!e||!t)return!1;if("[object RegExp]"==Object.prototype.toString.call(t))return t.test(e);try{if(e instanceof t)return!0}catch(e){}return!Error.isPrototypeOf(t)&&!0===t.call({},e)}function v(e){var t;try{e()}catch(e){t=e}return t}function b(e,t,n,r){var i;if("function"!==typeof t)throw new TypeError('"block" argument must be a function');"string"===typeof n&&(r=n,n=null),i=v(t),r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),e&&!i&&p(i,n,"Missing expected exception"+r);var o="string"===typeof r,a=!e&&x.isError(i),s=!e&&i&&!n;if((a&&o&&y(i,n)||s)&&p(i,n,"Got unwanted exception"+r),e&&i&&n&&!y(i,n)||!e&&i)throw i}var x=n(253),C=Object.prototype.hasOwnProperty,E=Array.prototype.slice,D=function(){return"foo"===function(){}.name}(),w=e.exports=f,S=/\s*function\s+([^\(\s]*)\s*/;w.AssertionError=function(e){this.name="AssertionError",this.actual=e.actual,this.expected=e.expected,this.operator=e.operator,e.message?(this.message=e.message,this.generatedMessage=!1):(this.message=l(this),this.generatedMessage=!0);var t=e.stackStartFunction||p;if(Error.captureStackTrace)Error.captureStackTrace(this,t);else{var n=new Error;if(n.stack){var r=n.stack,i=s(t),o=r.indexOf("\n"+i);if(o>=0){var a=r.indexOf("\n",o+1);r=r.substring(a+1)}this.stack=r}}},x.inherits(w.AssertionError,Error),w.fail=p,w.ok=f,w.equal=function(e,t,n){e!=t&&p(e,t,n,"==",w.equal)},w.notEqual=function(e,t,n){e==t&&p(e,t,n,"!=",w.notEqual)},w.deepEqual=function(e,t,n){d(e,t,!1)||p(e,t,n,"deepEqual",w.deepEqual)},w.deepStrictEqual=function(e,t,n){d(e,t,!0)||p(e,t,n,"deepStrictEqual",w.deepStrictEqual)},w.notDeepEqual=function(e,t,n){d(e,t,!1)&&p(e,t,n,"notDeepEqual",w.notDeepEqual)},w.notDeepStrictEqual=g,w.strictEqual=function(e,t,n){e!==t&&p(e,t,n,"===",w.strictEqual)},w.notStrictEqual=function(e,t,n){e===t&&p(e,t,n,"!==",w.notStrictEqual)},w.throws=function(e,t,n){b(!0,e,t,n)},w.doesNotThrow=function(e,t,n){b(!1,e,t,n)},w.ifError=function(e){if(e)throw e};var k=Object.keys||function(e){var t=[];for(var n in e)C.call(e,n)&&t.push(n);return t}}).call(t,n(11))},function(e,t,n){function r(e){return n(i(e))}function i(e){var t=o[e];if(!(t+1))throw new Error("Cannot find module '"+e+"'.");return t}var o={".":50,"./":50,"./GraphQLLanguageService":141,"./GraphQLLanguageService.js":141,"./GraphQLLanguageService.js.flow":600,"./autocompleteUtils":92,"./autocompleteUtils.js":92,"./autocompleteUtils.js.flow":601,"./getAutocompleteSuggestions":93,"./getAutocompleteSuggestions.js":93,"./getAutocompleteSuggestions.js.flow":602,"./getDefinition":94,"./getDefinition.js":94,"./getDefinition.js.flow":603,"./getDiagnostics":96,"./getDiagnostics.js":96,"./getDiagnostics.js.flow":604,"./getOutline":140,"./getOutline.js":140,"./getOutline.js.flow":605,"./index":50,"./index.js":50,"./index.js.flow":606};r.keys=function(){return Object.keys(o)},r.resolve=i,e.exports=r,r.id=279},function(e,t,n){"use strict";function r(e,t){var n={schema:e,type:null,parentType:null,inputType:null,directiveDef:null,fieldDef:null,argDef:null,argDefs:null,objectFieldDefs:null};return(0,c.default)(t,function(t){switch(t.kind){case"Query":case"ShortQuery":n.type=e.getQueryType();break;case"Mutation":n.type=e.getMutationType();break;case"Subscription":n.type=e.getSubscriptionType();break;case"InlineFragment":case"FragmentDefinition":t.type&&(n.type=e.getType(t.type));break;case"Field":case"AliasedField":n.fieldDef=n.type&&t.name?i(e,n.parentType,t.name):null,n.type=n.fieldDef&&n.fieldDef.type;break;case"SelectionSet":n.parentType=(0,a.getNamedType)(n.type);break;case"Directive":n.directiveDef=t.name&&e.getDirective(t.name);break;case"Arguments":var r="Field"===t.prevState.kind?n.fieldDef:"Directive"===t.prevState.kind?n.directiveDef:"AliasedField"===t.prevState.kind?t.prevState.name&&i(e,n.parentType,t.prevState.name):null;n.argDefs=r&&r.args;break;case"Argument":if(n.argDef=null,n.argDefs)for(var s=0;s=0;i--)t(n[i])}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";function r(e){return{kind:"Field",schema:e.schema,field:e.fieldDef,type:u(e.fieldDef)?null:e.parentType}}function i(e){return{kind:"Directive",schema:e.schema,directive:e.directiveDef}}function o(e){return e.directiveDef?{kind:"Argument",schema:e.schema,argument:e.argDef,directive:e.directiveDef}:{kind:"Argument",schema:e.schema,argument:e.argDef,field:e.fieldDef,type:u(e.fieldDef)?null:e.parentType}}function a(e){return{kind:"EnumValue",value:e.enumValue,type:(0,c.getNamedType)(e.inputType)}}function s(e,t){return{kind:"Type",schema:e.schema,type:t||e.type}}function u(e){return"__"===e.name.slice(0,2)}Object.defineProperty(t,"__esModule",{value:!0}),t.getFieldReference=r,t.getDirectiveReference=i,t.getArgumentReference=o,t.getEnumValueReference=a,t.getTypeReference=s;var c=n(7)},function(e,t,n){"use strict";function r(e,t){var n=e.levels;return(n&&0!==n.length?n[n.length-1]-(this.electricInput.test(t)?1:0):e.indentLevel)*this.config.indentUnit}var i=n(2),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=n(71);o.default.defineMode("graphql",function(e){var t=(0,a.onlineParser)({eatWhitespace:function(e){return e.eatWhile(a.isIgnored)},lexRules:a.LexRules,parseRules:a.ParseRules,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r,electricInput:/^\s*[})\]]/,fold:"brace",lineComment:"#",closeBrackets:{pairs:'()[]{}""',explode:"()[]{}"}}})},function(e,t,n){"use strict";function r(e){var t=(/mac os x/i.test(navigator.userAgent)?"\u2318":"Ctrl")+"+C";return e.replace(/#{\s*key\s*}/g,t)}function i(e,t){var n,i,s,u,c,l,p=!1;t||(t={}),n=t.debug||!1;try{s=o(),u=document.createRange(),c=document.getSelection(),l=document.createElement("span"),l.textContent=e,l.style.all="unset",l.style.position="fixed",l.style.top=0,l.style.clip="rect(0, 0, 0, 0)",l.style.whiteSpace="pre",l.style.webkitUserSelect="text",l.style.MozUserSelect="text",l.style.msUserSelect="text",l.style.userSelect="text",document.body.appendChild(l),u.selectNode(l),c.addRange(u);if(!document.execCommand("copy"))throw new Error("copy command was unsuccessful");p=!0}catch(o){n&&console.error("unable to copy using execCommand: ",o),n&&console.warn("trying IE specific stuff");try{window.clipboardData.setData("text",e),p=!0}catch(o){n&&console.error("unable to copy using clipboardData: ",o),n&&console.error("falling back to prompt"),i=r("message"in t?t.message:a),window.prompt(i,e)}}finally{c&&("function"==typeof c.removeRange?c.removeRange(u):c.removeAllRanges()),l&&document.body.removeChild(l),s()}return p}var o=n(613),a="Copy to clipboard: #{key}, Enter";e.exports=i},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(1);t.default=i.styled.div(o||(o=r(["\n width: 20px;\n height: 20px;\n"],["\n width: 20px;\n height: 20px;\n"])));var o},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r="Invalid"===t.state.kind?t.state.prevState:t.state,i=r.kind,a=r.step;if("Document"===i&&0===a)return(0,f.default)(e,t,[{text:"{"}]);var s=n.variableToType;if(s){var c=o(s,t.state);if("Document"===i||"Variable"===i&&0===a){var l=Object.keys(s);return(0,f.default)(e,t,l.map(function(e){return{text:'"'+e+'": ',type:s[e]}}))}if(("ObjectValue"===i||"ObjectField"===i&&0===a)&&c.fields){var p=Object.keys(c.fields).map(function(e){return c.fields[e]});return(0,f.default)(e,t,p.map(function(e){return{text:'"'+e.name+'": ',type:e.type,description:e.description}}))}if("StringValue"===i||"NumberValue"===i||"BooleanValue"===i||"NullValue"===i||"ListValue"===i&&1===a||"ObjectField"===i&&2===a||"Variable"===i&&2===a){var d=(0,u.getNamedType)(c.type);if(d instanceof u.GraphQLInputObjectType)return(0,f.default)(e,t,[{text:"{"}]);if(d instanceof u.GraphQLEnumType){var h=d.getValues(),m=Object.keys(h).map(function(e){return h[e]});return(0,f.default)(e,t,m.map(function(e){return{text:'"'+e.name+'"',type:d,description:e.description}}))}if(d===u.GraphQLBoolean)return(0,f.default)(e,t,[{text:"true",type:u.GraphQLBoolean,description:"Not false."},{text:"false",type:u.GraphQLBoolean,description:"Not true."}])}}}function o(e,t){var n={type:null,fields:null};return(0,l.default)(t,function(t){if("Variable"===t.kind)n.type=e[t.name];else if("ListValue"===t.kind){var r=(0,u.getNullableType)(n.type);n.type=r instanceof u.GraphQLList?r.ofType:null}else if("ObjectValue"===t.kind){var i=(0,u.getNamedType)(n.type);n.fields=i instanceof u.GraphQLInputObjectType?i.getFields():null}else if("ObjectField"===t.kind){var o=t.name&&n.fields?n.fields[t.name]:null;n.type=o&&o.type}}),n}var a=n(2),s=r(a),u=n(7),c=n(281),l=r(c),p=n(626),f=r(p);s.default.registerHelper("hint","graphql-variables",function(e,t){var n=e.getCursor(),r=e.getTokenAt(n),o=i(n,r,t);return o&&o.list&&o.list.length>0&&(o.from=s.default.Pos(o.from.line,o.from.column),o.to=s.default.Pos(o.to.line,o.to.column),s.default.signal(e,"hasCompletion",e,o,r)),o})},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=[];return n.members.forEach(function(n){var i=n.key.value,s=t[i];s?o(s,n.value).forEach(function(t){var n=t[0],i=t[1];r.push(a(e,n,i))}):r.push(a(e,n.key,'Variable "$'+i+'" does not appear in any GraphQL query.'))}),r}function o(e,t){if(e instanceof p.GraphQLNonNull)return"Null"===t.kind?[[t,'Type "'+e+'" is non-nullable and cannot be null.']]:o(e.ofType,t);if("Null"===t.kind)return[];if(e instanceof p.GraphQLList){var n=e.ofType;return"Array"===t.kind?u(t.values,function(e){return o(n,e)}):o(n,t)}if(e instanceof p.GraphQLInputObjectType){if("Object"!==t.kind)return[[t,'Type "'+e+'" must be an Object.']];var r=Object.create(null),i=u(t.members,function(t){var n=t.key.value;r[n]=!0;var i=e.getFields()[n];return i?o(i?i.type:void 0,t.value):[[t.key,'Type "'+e+'" does not have a field "'+n+'".']]});return Object.keys(e.getFields()).forEach(function(n){if(!r[n]){e.getFields()[n].type instanceof p.GraphQLNonNull&&i.push([t,'Object of type "'+e+'" is missing required field "'+n+'".'])}}),i}return"Boolean"===e.name&&"Boolean"!==t.kind||"String"===e.name&&"String"!==t.kind||"ID"===e.name&&"Number"!==t.kind&&"String"!==t.kind||"Float"===e.name&&"Number"!==t.kind||"Int"===e.name&&("Number"!==t.kind||(0|t.value)!==t.value)?[[t,'Expected value of type "'+e+'".']]:(e instanceof p.GraphQLEnumType||e instanceof p.GraphQLScalarType)&&("String"!==t.kind&&"Number"!==t.kind&&"Boolean"!==t.kind&&"Null"!==t.kind||s(e.parseValue(t.value)))?[[t,'Expected value of type "'+e+'".']]:[]}function a(e,t,n){return{message:n,severity:"error",type:"validation",from:e.posFromIndex(t.start),to:e.posFromIndex(t.end)}}function s(e){return null===e||void 0===e||e!==e}function u(e,t){return Array.prototype.concat.apply([],e.map(t))}var c=n(2),l=r(c),p=n(7),f=n(627),d=r(f);l.default.registerHelper("lint","graphql-variables",function(e,t,n){if(!e)return[];var r=void 0;try{r=(0,d.default)(e)}catch(e){if(e.stack)throw e;return[a(n,e,e.message)]}var o=t.variableToType;return o?i(n,o,r):[]})},function(e,t,n){"use strict";function r(e,t){var n=e.levels;return(n&&0!==n.length?n[n.length-1]-(this.electricInput.test(t)?1:0):e.indentLevel)*this.config.indentUnit}function i(e){return{style:e,match:function(e){return"String"===e.kind},update:function(e,t){e.name=t.value.slice(1,-1)}}}var o=n(2),a=function(e){return e&&e.__esModule?e:{default:e}}(o),s=n(71);a.default.defineMode("graphql-variables",function(e){var t=(0,s.onlineParser)({eatWhitespace:function(e){return e.eatSpace()},lexRules:u,parseRules:c,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}});var u={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},c={Document:[(0,s.p)("{"),(0,s.list)("Variable",(0,s.opt)((0,s.p)(","))),(0,s.p)("}")],Variable:[i("variable"),(0,s.p)(":"),"Value"],Value:function(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,s.t)("Number","number")],StringValue:[(0,s.t)("String","string")],BooleanValue:[(0,s.t)("Keyword","builtin")],NullValue:[(0,s.t)("Keyword","keyword")],ListValue:[(0,s.p)("["),(0,s.list)("Value",(0,s.opt)((0,s.p)(","))),(0,s.p)("]")],ObjectValue:[(0,s.p)("{"),(0,s.list)("ObjectField",(0,s.opt)((0,s.p)(","))),(0,s.p)("}")],ObjectField:[i("attribute"),(0,s.p)(":"),"Value"]}},function(e,t,n){"use strict";function r(e){for(var t=0,n=e;n.offsetParent;)t+=n.offsetLeft,n=n.offsetParent;return t}function i(e){for(var t=0,n=e;n.offsetParent;)t+=n.offsetTop,n=n.offsetParent;return t}Object.defineProperty(t,"__esModule",{value:!0}),t.getLeft=r,t.getTop=i},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(1),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(){var e=this.props,t=e.label,n=e.activeColor,r=e.active,i=e.onClick,a=e.tabWidth;return o.createElement(c,{onClick:i,activeColor:n,active:r,tabWidth:a},t)},t}(o.PureComponent);t.default=s;var u,c=a.styled("div")(u||(u=i(["\n z-index: ",";\n padding: 8px 8px 8px 8px;\n border-radius: 2px 2px 0px 0px;\n color: ",";\n background: ",";\n box-shadow: -1px 1px 6px 0 rgba(0, 0, 0, 0.3);\n text-transform: uppercase;\n text-align: center;\n font-weight: 600;\n font-size: 12px;\n line-height: 12px;\n letter-spacing: 0.45px;\n cursor: pointer;\n transform: rotate(-90deg);\n transform-origin: bottom left;\n margin-top: 65px;\n width: ",";\n"],["\n z-index: ",";\n padding: 8px 8px 8px 8px;\n border-radius: 2px 2px 0px 0px;\n color: ",";\n background: ",";\n box-shadow: -1px 1px 6px 0 rgba(0, 0, 0, 0.3);\n text-transform: uppercase;\n text-align: center;\n font-weight: 600;\n font-size: 12px;\n line-height: 12px;\n letter-spacing: 0.45px;\n cursor: pointer;\n transform: rotate(-90deg);\n transform-origin: bottom left;\n margin-top: 65px;\n width: ",";\n"])),function(e){return e.active?10:2},function(e){return"dark"===e.theme.mode?e.theme.colours.white:e.theme.colours[e.active?"white":"darkBlue"]},function(e){return e.active&&e.activeColor?e.theme.colours[e.activeColor]:"dark"===e.theme.mode?"#3D5866":"#DBDEE0"},function(e){return e.tabWidth||"100%"})},function(e,t){function n(e){if(e&&"object"===typeof e){var t=e.which||e.keyCode||e.charCode;t&&(e=t)}if("number"===typeof e)return a[e];var n=String(e),o=r[n.toLowerCase()];if(o)return o;var o=i[n.toLowerCase()];return o||(1===n.length?n.charCodeAt(0):void 0)}n.isEventKey=function(e,t){if(e&&"object"===typeof e){var n=e.which||e.keyCode||e.charCode;if(null===n||void 0===n)return!1;if("string"===typeof t){var o=r[t.toLowerCase()];if(o)return o===n;var o=i[t.toLowerCase()];if(o)return o===n}else if("number"===typeof t)return t===n;return!1}},t=e.exports=n;var r=t.code=t.codes={backspace:8,tab:9,enter:13,shift:16,ctrl:17,alt:18,"pause/break":19,"caps lock":20,esc:27,space:32,"page up":33,"page down":34,end:35,home:36,left:37,up:38,right:39,down:40,insert:45,delete:46,command:91,"left command":91,"right command":93,"numpad *":106,"numpad +":107,"numpad -":109,"numpad .":110,"numpad /":111,"num lock":144,"scroll lock":145,"my computer":182,"my calculator":183,";":186,"=":187,",":188,"-":189,".":190,"/":191,"`":192,"[":219,"\\":220,"]":221,"'":222},i=t.aliases={windows:91,"\u21e7":16,"\u2325":18,"\u2303":17,"\u2318":91,ctl:17,control:17,option:18,pause:19,break:19,caps:20,return:13,escape:27,spc:32,spacebar:32,pgup:33,pgdn:34,ins:45,del:46,cmd:91};for(o=97;o<123;o++)r[String.fromCharCode(o)]=o-32;for(var o=48;o<58;o++)r[o-48]=o;for(o=1;o<13;o++)r["f"+o]=o+111;for(o=0;o<10;o++)r["numpad "+o]=o+96;var a=t.names=t.title={};for(o in r)a[r[o]]=o;for(var s in i)r[s]=i[s]},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(1);t.ErrorContainer=i.styled.div(o||(o=r(["\n font-weight: bold;\n left: 0;\n letter-spacing: 1px;\n opacity: 0.5;\n position: absolute;\n right: 0;\n text-align: center;\n text-transform: uppercase;\n top: 50%;\n transform: translate(0, -50%);\n"],["\n font-weight: bold;\n left: 0;\n letter-spacing: 1px;\n opacity: 0.5;\n position: absolute;\n right: 0;\n text-align: center;\n text-transform: uppercase;\n top: 50%;\n transform: translate(0, -50%);\n"])));var o},function(e,t,n){"use strict";function r(e,t){return(Object.values||function(e){return Object.keys(e).map(function(t){return e[t]})})(e.getTypeMap()).sort(function(e,t){return e.name.localeCompare(t.name)}).filter(function(e){return!d.includes(e.name)}).map(function(t){return c({},t,p.serialize(e,t),{instanceOf:i(t)})})}function i(e){return e instanceof l.GraphQLInterfaceType?"interface":e instanceof l.GraphQLUnionType?"union":e instanceof l.GraphQLEnumType?"enum":e instanceof l.GraphQLInputObjectType?"input":"type"}function o(e,t){void 0===t&&(t=!0);var n=e.replace(/^\s*$(?:\r\n?|\n)/gm,""),r=n.replace(/[}]/gm,"$&\r\n"),i=r.replace(/(?:scalar )\w+/g,"$&\r\n");return t?i:i.replace(/(?:\#[\w\'\s\r\n\*](.*)$)/gm,"$&\r")}function a(e,t){if(void 0===t&&(t=!0),e instanceof l.GraphQLSchema){var n=l.printSchema(e,{commentDescriptions:!0});if(t){var r=n.replace(/(\#[\w\'\s\r\n\*](.*)$)/gm,"");return o(f.prettify(r,{printWidth:80,tabWidth:2,useTabs:!1}),t)}return o(f.prettify(n,{printWidth:80,tabWidth:2,useTabs:!1}))}return""}function s(e,t){if("sdl"===t){var n=a(e,!1),r="schema.graphql";return u(n,r)}var n=JSON.stringify(e),r="instrospectionSchema.json";return u(n,r)}function u(e,t,n){var r=new Blob([e],{type:n||"application/octet-stream"});if("undefined"!==typeof window.navigator.msSaveBlob)window.navigator.msSaveBlob(r,t);else{var i=window.URL.createObjectURL(r),o=document.createElement("a");o.style.display="none",o.href=i,o.setAttribute("download",t),"undefined"===typeof o.download&&o.setAttribute("target","_blank"),document.body.appendChild(o),o.click(),document.body.removeChild(o),window.URL.revokeObjectURL(i)}}var c=function(){return c=Object.assign||function(e){for(var t,n=1,r=arguments.length;n`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",i="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",o=new RegExp("^(?:"+r+"|"+i+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?].*?[?]>|]*>|)"),a=new RegExp("^(?:"+r+"|"+i+")");e.exports.HTML_TAG_RE=o,e.exports.HTML_OPEN_CLOSE_TAG_RE=a},function(e,t,n){"use strict";e.exports.tokenize=function(e,t){var n,r,i,o,a,s=e.pos,u=e.src.charCodeAt(s);if(t)return!1;if(126!==u)return!1;if(r=e.scanDelims(e.pos,!0),o=r.length,a=String.fromCharCode(u),o<2)return!1;for(o%2&&(i=e.push("text","",0),i.content=a,o--),n=0;n=0;t--)n=s[t],95!==n.marker&&42!==n.marker||-1!==n.end&&(r=s[n.end],a=t>0&&s[t-1].end===n.end+1&&s[t-1].token===n.token-1&&s[n.end+1].token===r.token+1&&s[t-1].marker===n.marker,o=String.fromCharCode(n.marker),i=e.tokens[n.token],i.type=a?"strong_open":"em_open",i.tag=a?"strong":"em",i.nesting=1,i.markup=a?o+o:o,i.content="",i=e.tokens[r.token],i.type=a?"strong_close":"em_close",i.tag=a?"strong":"em",i.nesting=-1,i.markup=a?o+o:o,i.content="",a&&(e.tokens[s[t-1].token].content="",e.tokens[s[n.end+1].token].content="",t--))}},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(1),a=o.styled.div(s||(s=r(["\n color: rgba(0, 0, 0, 0.3);\n cursor: default;\n font-size: 14px;\n font-weight: 600;\n text-transform: uppercase !important;\n letter-spacing: 1px;\n padding: 16px;\n user-select: none;\n"],["\n color: rgba(0, 0, 0, 0.3);\n cursor: default;\n font-size: 14px;\n font-weight: 600;\n text-transform: uppercase !important;\n letter-spacing: 1px;\n padding: 16px;\n user-select: none;\n"])));t.CategoryTitle=function(e){var t=e.children;return i.createElement(a,null,t)};var s},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(36),a=n(1),s=function(e){var t=e.children,n=e.overflow,r=void 0===n||n,a=e.width,s=void 0===a?o.columnWidth:a;return i.createElement(c,{style:{width:s},verticalScroll:r},t)};t.default=s;var u,c=a.styled("div")(u||(u=r(["\n display: flex;\n flex: 0 0 auto;\n flex-flow: column;\n padding-bottom: 20px;\n border-right: 1px solid ",";\n overflow-x: ","\n overflow-y: ","\n"],["\n display: flex;\n flex: 0 0 auto;\n flex-flow: column;\n padding-bottom: 20px;\n border-right: 1px solid ",";\n overflow-x: ","\n overflow-y: ","\n"])),function(e){return e.theme.colours.black10},function(e){return e.verticalScroll?"hidden":"auto"},function(e){return e.verticalScroll?"scroll":"auto"})},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(699),s=n(24),u=n(1),c=function(e){function t(t){var n=e.call(this,t)||this;return n.handleChange=function(e){n.setState({value:e.target.value}),n.debouncedOnSearch()},n.state={value:""},n.debouncedOnSearch=a.default(200,function(){n.props.onSearch(n.state.value)}),n}return r(t,e),t.prototype.shouldComponentUpdate=function(e,t){return t.value!==this.state.value},t.prototype.render=function(){var e=o.createElement(h,null,o.createElement(s.Search,{height:16,width:16,strokeWidth:3,color:"rgba(0, 0, 0, 0.3)"}),o.createElement(m,{onChange:this.handleChange,type:"text",value:this.state.value,placeholder:this.props.placeholder||"Search the docs ..."}));return this.props.clean?e:o.createElement(d,null,e)},t}(o.Component);t.default=c;var l,p,f,d=u.styled.div(l||(l=i(["\n position: relative;\n flex: 0 0 auto;\n z-index: 1;\n display: flex;\n margin-left: 6px;\n padding: 25px;\n background: ",";\n border-bottom: 1px solid ",";\n div {\n width: 100%;\n }\n"],["\n position: relative;\n flex: 0 0 auto;\n z-index: 1;\n display: flex;\n margin-left: 6px;\n padding: 25px;\n background: ",";\n border-bottom: 1px solid ",";\n div {\n width: 100%;\n }\n"])),function(e){return e.theme.colours.black02},function(e){return e.theme.colours.black10}),h=u.styled.div(p||(p=i(["\n box-sizing: border-box;\n display: flex;\n align-items: center;\n padding: 12px 14px 13px 15px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n background: ",";\n"],["\n box-sizing: border-box;\n display: flex;\n align-items: center;\n padding: 12px 14px 13px 15px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n background: ",";\n"])),function(e){return e.theme.colours.white}),m=u.styled.input(f||(f=i(["\n font-size: 16px;\n margin-left: 10px;\n &::placeholder {\n color: ",";\n }\n"],["\n font-size: 16px;\n margin-left: 10px;\n &::placeholder {\n color: ",";\n }\n"])),function(e){return e.theme.colours.black30})},function(e,t,n){"use strict";function r(e){return(e.configPath?e.configPath+"~":"")+(e.workspaceName?e.workspaceName+"~":"")+e.endpoint}Object.defineProperty(t,"__esModule",{value:!0}),t.getWorkspaceId=r},function(e,t){t.__esModule=!0;var n=(t.ATTRIBUTE_NAMES={BODY:"bodyAttributes",HTML:"htmlAttributes",TITLE:"titleAttributes"},t.TAG_NAMES={BASE:"base",BODY:"body",HEAD:"head",HTML:"html",LINK:"link",META:"meta",NOSCRIPT:"noscript",SCRIPT:"script",STYLE:"style",TITLE:"title"}),r=(t.VALID_TAG_NAMES=Object.keys(n).map(function(e){return n[e]}),t.TAG_PROPERTIES={CHARSET:"charset",CSS_TEXT:"cssText",HREF:"href",HTTPEQUIV:"http-equiv",INNER_HTML:"innerHTML",ITEM_PROP:"itemprop",NAME:"name",PROPERTY:"property",REL:"rel",SRC:"src"},t.REACT_TAG_MAP={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"});t.HELMET_PROPS={DEFAULT_TITLE:"defaultTitle",DEFER:"defer",ENCODE_SPECIAL_CHARACTERS:"encodeSpecialCharacters",ON_CHANGE_CLIENT_STATE:"onChangeClientState",TITLE_TEMPLATE:"titleTemplate"},t.HTML_TAG_MAP=Object.keys(r).reduce(function(e,t){return e[r[t]]=t,e},{}),t.SELF_CLOSING_TAGS=[n.NOSCRIPT,n.SCRIPT,n.STYLE],t.HELMET_ATTRIBUTE="data-react-helmet"},function(e,t,n){"use strict";var r=n(53);e.exports=new r({include:[n(304)]})},function(e,t,n){"use strict";var r=n(53);e.exports=new r({include:[n(148)],implicit:[n(729),n(730),n(731),n(732)]})},function(e,t){!function(e){"use strict";function t(e){if("string"!==typeof e&&(e=String(e)),/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(e))throw new TypeError("Invalid character in header field name");return e.toLowerCase()}function n(e){return"string"!==typeof e&&(e=String(e)),e}function r(e){var t={next:function(){var t=e.shift();return{done:void 0===t,value:t}}};return y.iterable&&(t[Symbol.iterator]=function(){return t}),t}function i(e){this.map={},e instanceof i?e.forEach(function(e,t){this.append(t,e)},this):Array.isArray(e)?e.forEach(function(e){this.append(e[0],e[1])},this):e&&Object.getOwnPropertyNames(e).forEach(function(t){this.append(t,e[t])},this)}function o(e){if(e.bodyUsed)return Promise.reject(new TypeError("Already read"));e.bodyUsed=!0}function a(e){return new Promise(function(t,n){e.onload=function(){t(e.result)},e.onerror=function(){n(e.error)}})}function s(e){var t=new FileReader,n=a(t);return t.readAsArrayBuffer(e),n}function u(e){var t=new FileReader,n=a(t);return t.readAsText(e),n}function c(e){for(var t=new Uint8Array(e),n=new Array(t.length),r=0;r-1?t:e}function d(e,t){t=t||{};var n=t.body;if(e instanceof d){if(e.bodyUsed)throw new TypeError("Already read");this.url=e.url,this.credentials=e.credentials,t.headers||(this.headers=new i(e.headers)),this.method=e.method,this.mode=e.mode,n||null==e._bodyInit||(n=e._bodyInit,e.bodyUsed=!0)}else this.url=String(e);if(this.credentials=t.credentials||this.credentials||"omit",!t.headers&&this.headers||(this.headers=new i(t.headers)),this.method=f(t.method||this.method||"GET"),this.mode=t.mode||this.mode||null,this.referrer=null,("GET"===this.method||"HEAD"===this.method)&&n)throw new TypeError("Body not allowed for GET or HEAD requests");this._initBody(n)}function h(e){var t=new FormData;return e.trim().split("&").forEach(function(e){if(e){var n=e.split("="),r=n.shift().replace(/\+/g," "),i=n.join("=").replace(/\+/g," ");t.append(decodeURIComponent(r),decodeURIComponent(i))}}),t}function m(e){var t=new i;return e.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(e){var n=e.split(":"),r=n.shift().trim();if(r){var i=n.join(":").trim();t.append(r,i)}}),t}function g(e,t){t||(t={}),this.type="default",this.status=void 0===t.status?200:t.status,this.ok=this.status>=200&&this.status<300,this.statusText="statusText"in t?t.statusText:"OK",this.headers=new i(t.headers),this.url=t.url||"",this._initBody(e)}if(!e.fetch){var y={searchParams:"URLSearchParams"in e,iterable:"Symbol"in e&&"iterator"in Symbol,blob:"FileReader"in e&&"Blob"in e&&function(){try{return new Blob,!0}catch(e){return!1}}(),formData:"FormData"in e,arrayBuffer:"ArrayBuffer"in e};if(y.arrayBuffer)var v=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],b=function(e){return e&&DataView.prototype.isPrototypeOf(e)},x=ArrayBuffer.isView||function(e){return e&&v.indexOf(Object.prototype.toString.call(e))>-1};i.prototype.append=function(e,r){e=t(e),r=n(r);var i=this.map[e];this.map[e]=i?i+","+r:r},i.prototype.delete=function(e){delete this.map[t(e)]},i.prototype.get=function(e){return e=t(e),this.has(e)?this.map[e]:null},i.prototype.has=function(e){return this.map.hasOwnProperty(t(e))},i.prototype.set=function(e,r){this.map[t(e)]=n(r)},i.prototype.forEach=function(e,t){for(var n in this.map)this.map.hasOwnProperty(n)&&e.call(t,this.map[n],n,this)},i.prototype.keys=function(){var e=[];return this.forEach(function(t,n){e.push(n)}),r(e)},i.prototype.values=function(){var e=[];return this.forEach(function(t){e.push(t)}),r(e)},i.prototype.entries=function(){var e=[];return this.forEach(function(t,n){e.push([n,t])}),r(e)},y.iterable&&(i.prototype[Symbol.iterator]=i.prototype.entries);var C=["DELETE","GET","HEAD","OPTIONS","POST","PUT"];d.prototype.clone=function(){return new d(this,{body:this._bodyInit})},p.call(d.prototype),p.call(g.prototype),g.prototype.clone=function(){return new g(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new i(this.headers),url:this.url})},g.error=function(){var e=new g(null,{status:0,statusText:""});return e.type="error",e};var E=[301,302,303,307,308];g.redirect=function(e,t){if(-1===E.indexOf(t))throw new RangeError("Invalid status code");return new g(null,{status:t,headers:{location:e}})},e.Headers=i,e.Request=d,e.Response=g,e.fetch=function(e,t){return new Promise(function(n,r){var i=new d(e,t),o=new XMLHttpRequest;o.onload=function(){var e={status:o.status,statusText:o.statusText,headers:m(o.getAllResponseHeaders()||"")};e.url="responseURL"in o?o.responseURL:e.headers.get("X-Request-URL");var t="response"in o?o.response:o.responseText;n(new g(t,e))},o.onerror=function(){r(new TypeError("Network request failed"))},o.ontimeout=function(){r(new TypeError("Network request failed"))},o.open(i.method,i.url,!0),"include"===i.credentials?o.withCredentials=!0:"omit"===i.credentials&&(o.withCredentials=!1),"responseType"in o&&y.blob&&(o.responseType="blob"),i.headers.forEach(function(e,t){o.setRequestHeader(t,e)}),o.send("undefined"===typeof i._bodyInit?null:i._bodyInit)})},e.fetch.polyfill=!0}}("undefined"!==typeof self?self:this)},,function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(518),i=function(e){return e&&e.__esModule?e:{default:e}}(r);t.default=i.default,e.exports=t.default},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(1),a=n(24);t.Button=function(e){var n=e.purple,r=e.hideArrow,o=e.children,s=e.onClick;return i.createElement(t.ButtonBox,{purple:n,onClick:s},o||"Learn more",!r&&i.createElement(a.FullArrowRightIcon,{color:"red",width:14,height:11}))},t.ButtonBox=o.styled("div")(s||(s=r(["\n display: flex;\n align-items: center;\n\n padding: 6px 16px;\n border-radius: 2px;\n background: ",";\n color: ",";\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2);\n text-transform: uppercase;\n font-weight: 600;\n font-size: 14px;\n letter-spacing: 1px;\n white-space: nowrap;\n\n transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;\n cursor: pointer;\n &:hover {\n background: ",";\n transform: ",";\n svg {\n animation: move 1s ease infinite;\n }\n }\n\n svg {\n margin-left: 10px;\n fill: ",";\n }\n\n @keyframes move {\n 0% {\n transform: translate3D(0, 0, 0);\n }\n\n 50% {\n transform: translate3D(3px, 0, 0);\n }\n\n 100% {\n transform: translate3D(0, 0, 0);\n }\n }\n"],["\n display: flex;\n align-items: center;\n\n padding: 6px 16px;\n border-radius: 2px;\n background: ",";\n color: ",";\n box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2);\n text-transform: uppercase;\n font-weight: 600;\n font-size: 14px;\n letter-spacing: 1px;\n white-space: nowrap;\n\n transition: background 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;\n cursor: pointer;\n &:hover {\n background: ",";\n transform: ",";\n svg {\n animation: move 1s ease infinite;\n }\n }\n\n svg {\n margin-left: 10px;\n fill: ",";\n }\n\n @keyframes move {\n 0% {\n transform: translate3D(0, 0, 0);\n }\n\n 50% {\n transform: translate3D(3px, 0, 0);\n }\n\n 100% {\n transform: translate3D(0, 0, 0);\n }\n }\n"])),function(e){return e.purple?"rgb(218, 27, 127)":"#2a7ed2"},function(e){return e.theme.colours.white},function(e){return e.purple?"rgb(164, 3, 111)":"#3f8ad7"},function(e){return e.purple?"translate3D(0, 0, 0)":"translate3D(0, -1px, 0)"},function(e){return e.theme.colours.white});var s},function(e,t,n){"undefined"===typeof Promise&&(n(310).enable(),window.Promise=n(312)),n(305),Object.assign=n(54)},function(e,t,n){"use strict";function r(){c=!1,s._47=null,s._71=null}function i(e){function t(t){(e.allRejections||a(p[t].error,e.whitelist||u))&&(p[t].displayId=l++,e.onUnhandled?(p[t].logged=!0,e.onUnhandled(p[t].displayId,p[t].error)):(p[t].logged=!0,o(p[t].displayId,p[t].error)))}function n(t){p[t].logged&&(e.onHandled?e.onHandled(p[t].displayId,p[t].error):p[t].onUnhandled||(console.warn("Promise Rejection Handled (id: "+p[t].displayId+"):"),console.warn(' This means you can ignore any previous messages of the form "Possible Unhandled Promise Rejection" with id '+p[t].displayId+".")))}e=e||{},c&&r(),c=!0;var i=0,l=0,p={};s._47=function(e){2===e._83&&p[e._56]&&(p[e._56].logged?n(e._56):clearTimeout(p[e._56].timeout),delete p[e._56])},s._71=function(e,n){0===e._75&&(e._56=i++,p[e._56]={displayId:null,error:n,timeout:setTimeout(t.bind(null,e._56),a(n,u)?100:2e3),logged:!1})}}function o(e,t){console.warn("Possible Unhandled Promise Rejection (id: "+e+"):"),((t&&(t.stack||t))+"").split("\n").forEach(function(e){console.warn(" "+e)})}function a(e,t){return t.some(function(t){return e instanceof t})}var s=n(151),u=[ReferenceError,TypeError,RangeError],c=!1;t.disable=r,t.enable=i},function(e,t,n){"use strict";(function(t){function n(e){a.length||(o(),s=!0),a[a.length]=e}function r(){for(;uc){for(var t=0,n=a.length-u;tR.length&&R.push(e)}function f(e,t,n,i){var o=typeof e;"undefined"!==o&&"boolean"!==o||(e=null);var a=!1;if(null===e)a=!0;else switch(o){case"string":case"number":a=!0;break;case"object":switch(e.$$typeof){case E:case D:a=!0}}if(a)return n(i,e,""===t?"."+d(e,0):t),1;if(a=0,t=""===t?".":t+":",Array.isArray(e))for(var s=0;sthis.eventPool.length&&this.eventPool.push(e)}function B(e){e.eventPool=[],e.getPooled=j,e.release=R}function $(e,t){switch(e){case"keyup":return-1!==Ci.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function U(e){return e=e.detail,"object"===typeof e&&"data"in e?e.data:null}function z(e,t){switch(e){case"compositionend":return U(t);case"keypress":return 32!==t.which?null:(_i=!0,ki);case"textInput":return e=t.data,e===ki&&_i?null:e;default:return null}}function G(e,t){if(Ti)return"compositionend"===e||!Ei&&$(e,t)?(e=L(),gi._root=null,gi._startText=null,gi._fallbackText=null,Ti=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1t}return!1}function pe(e,t,n,r,i){this.acceptsBooleans=2===t||3===t||4===t,this.attributeName=r,this.attributeNamespace=i,this.mustUseProperty=n,this.propertyName=e,this.type=t}function fe(e){return e[1].toUpperCase()}function de(e,t,n,r){var i=eo.hasOwnProperty(t)?eo[t]:null;(null!==i?0===i.type:!r&&(2To.length&&To.push(e)}}}function He(e){return Object.prototype.hasOwnProperty.call(e,Lo)||(e[Lo]=Io++,No[e[Lo]]={}),No[e[Lo]]}function We(e){for(;e&&e.firstChild;)e=e.firstChild;return e}function Qe(e,t){var n=We(e);e=0;for(var r;n;){if(3===n.nodeType){if(r=e+n.textContent.length,e<=t&&r>=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=We(n)}}function Ke(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&("input"===t&&"text"===e.type||"textarea"===t||"true"===e.contentEditable)}function Je(e,t){if($o||null==jo||jo!==Rr())return null;var n=jo;return"selectionStart"in n&&Ke(n)?n={start:n.selectionStart,end:n.selectionEnd}:window.getSelection?(n=window.getSelection(),n={anchorNode:n.anchorNode,anchorOffset:n.anchorOffset,focusNode:n.focusNode,focusOffset:n.focusOffset}):n=void 0,Bo&&Br(Bo,n)?null:(Bo=n,e=M.getPooled(Mo.select,Ro,e,t),e.type="select",e.target=jo,T(e),e)}function Ye(e){var t="";return Lr.Children.forEach(e,function(e){null==e||"string"!==typeof e&&"number"!==typeof e||(t+=e)}),t}function Xe(e,t){return e=Mr({children:void 0},t),(t=Ye(t.children))&&(e.children=t),e}function Ze(e,t,n,r){if(e=e.options,t){t={};for(var i=0;i=t.length||r("93"),t=t[0]),n=""+t),null==n&&(n="")),e._wrapperState={initialValue:""+n}}function rt(e,t){var n=t.value;null!=n&&(n=""+n,n!==e.value&&(e.value=n),null==t.defaultValue&&(e.defaultValue=n)),null!=t.defaultValue&&(e.defaultValue=t.defaultValue)}function it(e){var t=e.textContent;t===e._wrapperState.initialValue&&(e.value=t)}function ot(e){switch(e){case"svg":return"http://www.w3.org/2000/svg";case"math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function at(e,t){return null==e||"http://www.w3.org/1999/xhtml"===e?ot(t):"http://www.w3.org/2000/svg"===e&&"foreignObject"===t?"http://www.w3.org/1999/xhtml":e}function st(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&3===n.nodeType)return void(n.nodeValue=t)}e.textContent=t}function ut(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=0===n.indexOf("--"),i=n,o=t[n];i=null==o||"boolean"===typeof o||""===o?"":r||"number"!==typeof o||0===o||ca.hasOwnProperty(i)&&ca[i]?(""+o).trim():o+"px","float"===n&&(n="cssFloat"),r?e.setProperty(n,i):e[n]=i}}function ct(e,t,n){t&&(pa[e]&&(null!=t.children||null!=t.dangerouslySetInnerHTML)&&r("137",e,n()),null!=t.dangerouslySetInnerHTML&&(null!=t.children&&r("60"),"object"===typeof t.dangerouslySetInnerHTML&&"__html"in t.dangerouslySetInnerHTML||r("61")),null!=t.style&&"object"!==typeof t.style&&r("62",n()))}function lt(e,t){if(-1===e.indexOf("-"))return"string"===typeof t.is;switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}function pt(e,t){e=9===e.nodeType||11===e.nodeType?e:e.ownerDocument;var n=He(e);t=Qr[t];for(var r=0;r<\/script>",e=e.removeChild(e.firstChild)):e="string"===typeof t.is?n.createElement(e,{is:t.is}):n.createElement(e):e=n.createElementNS(r,e),e}function dt(e,t){return(9===t.nodeType?t:t.ownerDocument).createTextNode(e)}function ht(e,t,n,r){var i=lt(t,n);switch(t){case"iframe":case"object":ze("load",e);var o=n;break;case"video":case"audio":for(o=0;oxa||(e.current=ba[xa],ba[xa]=null,xa--)}function St(e,t){xa++,ba[xa]=e.current,e.current=t}function kt(e){return _t(e)?Da:Ca.current}function At(e,t){var n=e.type.contextTypes;if(!n)return Ur;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var i,o={};for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function _t(e){return 2===e.tag&&null!=e.type.childContextTypes}function Tt(e){_t(e)&&(wt(Ea,e),wt(Ca,e))}function Ot(e){wt(Ea,e),wt(Ca,e)}function Ft(e,t,n){Ca.current!==Ur&&r("168"),St(Ca,t,e),St(Ea,n,e)}function Nt(e,t){var n=e.stateNode,i=e.type.childContextTypes;if("function"!==typeof n.getChildContext)return t;n=n.getChildContext();for(var o in n)o in i||r("108",ae(e)||"Unknown",o);return Mr({},t,n)}function It(e){if(!_t(e))return!1;var t=e.stateNode;return t=t&&t.__reactInternalMemoizedMergedChildContext||Ur,Da=Ca.current,St(Ca,t,e),St(Ea,Ea.current,e),!0}function Lt(e,t){var n=e.stateNode;if(n||r("169"),t){var i=Nt(e,Da);n.__reactInternalMemoizedMergedChildContext=i,wt(Ea,e),wt(Ca,e),St(Ca,i,e)}else wt(Ea,e);St(Ea,t,e)}function Pt(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=null,this.index=0,this.ref=null,this.pendingProps=t,this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.effectTag=0,this.lastEffect=this.firstEffect=this.nextEffect=null,this.expirationTime=0,this.alternate=null}function Mt(e,t,n){var r=e.alternate;return null===r?(r=new Pt(e.tag,t,e.key,e.mode),r.type=e.type,r.stateNode=e.stateNode,r.alternate=e,e.alternate=r):(r.pendingProps=t,r.effectTag=0,r.nextEffect=null,r.firstEffect=null,r.lastEffect=null),r.expirationTime=n,r.child=e.child,r.memoizedProps=e.memoizedProps,r.memoizedState=e.memoizedState,r.updateQueue=e.updateQueue,r.sibling=e.sibling,r.index=e.index,r.ref=e.ref,r}function jt(e,t,n){var i=e.type,o=e.key;if(e=e.props,"function"===typeof i)var a=i.prototype&&i.prototype.isReactComponent?2:0;else if("string"===typeof i)a=5;else switch(i){case zi:return Rt(e.children,t,n,o);case Wi:a=11,t|=3;break;case Gi:a=11,t|=2;break;case Vi:return i=new Pt(15,e,o,4|t),i.type=Vi,i.expirationTime=n,i;case Ki:a=16,t|=2;break;default:e:{switch("object"===typeof i&&null!==i?i.$$typeof:null){case qi:a=13;break e;case Hi:a=12;break e;case Qi:a=14;break e;default:r("130",null==i?i:typeof i,"")}a=void 0}}return t=new Pt(a,e,o,t),t.type=i,t.expirationTime=n,t}function Rt(e,t,n,r){return e=new Pt(10,e,r,t),e.expirationTime=n,e}function Bt(e,t,n){return e=new Pt(6,e,null,t),e.expirationTime=n,e}function $t(e,t,n){return t=new Pt(4,null!==e.children?e.children:[],e.key,t),t.expirationTime=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Ut(e,t,n){return t=new Pt(3,null,null,t?3:0),e={current:t,containerInfo:e,pendingChildren:null,earliestPendingTime:0,latestPendingTime:0,earliestSuspendedTime:0,latestSuspendedTime:0,latestPingedTime:0,pendingCommitExpirationTime:0,finishedWork:null,context:null,pendingContext:null,hydrate:n,remainingExpirationTime:0,firstBatch:null,nextScheduledRoot:null},t.stateNode=e}function zt(e){return function(t){try{return e(t)}catch(e){}}}function Gt(e){if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1;var t=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(t.isDisabled||!t.supportsFiber)return!0;try{var n=t.inject(e);wa=zt(function(e){return t.onCommitFiberRoot(n,e)}),Sa=zt(function(e){return t.onCommitFiberUnmount(n,e)})}catch(e){}return!0}function Vt(e){"function"===typeof wa&&wa(e)}function qt(e){"function"===typeof Sa&&Sa(e)}function Ht(e){return{expirationTime:0,baseState:e,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Wt(e){return{expirationTime:e.expirationTime,baseState:e.baseState,firstUpdate:e.firstUpdate,lastUpdate:e.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Qt(e){return{expirationTime:e,tag:0,payload:null,callback:null,next:null,nextEffect:null}}function Kt(e,t,n){null===e.lastUpdate?e.firstUpdate=e.lastUpdate=t:(e.lastUpdate.next=t,e.lastUpdate=t),(0===e.expirationTime||e.expirationTime>n)&&(e.expirationTime=n)}function Jt(e,t,n){var r=e.alternate;if(null===r){var i=e.updateQueue,o=null;null===i&&(i=e.updateQueue=Ht(e.memoizedState))}else i=e.updateQueue,o=r.updateQueue,null===i?null===o?(i=e.updateQueue=Ht(e.memoizedState),o=r.updateQueue=Ht(r.memoizedState)):i=e.updateQueue=Wt(o):null===o&&(o=r.updateQueue=Wt(i));null===o||i===o?Kt(i,t,n):null===i.lastUpdate||null===o.lastUpdate?(Kt(i,t,n),Kt(o,t,n)):(Kt(i,t,n),o.lastUpdate=t)}function Yt(e,t,n){var r=e.updateQueue;r=null===r?e.updateQueue=Ht(e.memoizedState):Xt(e,r),null===r.lastCapturedUpdate?r.firstCapturedUpdate=r.lastCapturedUpdate=t:(r.lastCapturedUpdate.next=t,r.lastCapturedUpdate=t),(0===r.expirationTime||r.expirationTime>n)&&(r.expirationTime=n)}function Xt(e,t){var n=e.alternate;return null!==n&&t===n.updateQueue&&(t=e.updateQueue=Wt(t)),t}function Zt(e,t,n,r,i,o){switch(n.tag){case 1:return e=n.payload,"function"===typeof e?e.call(o,r,i):e;case 3:e.effectTag=-1025&e.effectTag|64;case 0:if(e=n.payload,null===(i="function"===typeof e?e.call(o,r,i):e)||void 0===i)break;return Mr({},r,i);case 2:ka=!0}return r}function en(e,t,n,r,i){if(ka=!1,!(0===t.expirationTime||t.expirationTime>i)){t=Xt(e,t);for(var o=t.baseState,a=null,s=0,u=t.firstUpdate,c=o;null!==u;){var l=u.expirationTime;l>i?(null===a&&(a=u,o=c),(0===s||s>l)&&(s=l)):(c=Zt(e,t,u,c,n,r),null!==u.callback&&(e.effectTag|=32,u.nextEffect=null,null===t.lastEffect?t.firstEffect=t.lastEffect=u:(t.lastEffect.nextEffect=u,t.lastEffect=u))),u=u.next}for(l=null,u=t.firstCapturedUpdate;null!==u;){var p=u.expirationTime;p>i?(null===l&&(l=u,null===a&&(o=c)),(0===s||s>p)&&(s=p)):(c=Zt(e,t,u,c,n,r),null!==u.callback&&(e.effectTag|=32,u.nextEffect=null,null===t.lastCapturedEffect?t.firstCapturedEffect=t.lastCapturedEffect=u:(t.lastCapturedEffect.nextEffect=u,t.lastCapturedEffect=u))),u=u.next}null===a&&(t.lastUpdate=null),null===l?t.lastCapturedUpdate=null:e.effectTag|=32,null===a&&null===l&&(o=c),t.baseState=o,t.firstUpdate=a,t.firstCapturedUpdate=l,t.expirationTime=s,e.memoizedState=c}}function tn(e,t){"function"!==typeof e&&r("191",e),e.call(t)}function nn(e,t,n){for(null!==t.firstCapturedUpdate&&(null!==t.lastUpdate&&(t.lastUpdate.next=t.firstCapturedUpdate,t.lastUpdate=t.lastCapturedUpdate),t.firstCapturedUpdate=t.lastCapturedUpdate=null),e=t.firstEffect,t.firstEffect=t.lastEffect=null;null!==e;){var r=e.callback;null!==r&&(e.callback=null,tn(r,n)),e=e.nextEffect}for(e=t.firstCapturedEffect,t.firstCapturedEffect=t.lastCapturedEffect=null;null!==e;)t=e.callback,null!==t&&(e.callback=null,tn(t,n)),e=e.nextEffect}function rn(e,t){return{value:e,source:t,stack:se(t)}}function on(e){var t=e.type._context;St(Ta,t._changedBits,e),St(_a,t._currentValue,e),St(Aa,e,e),t._currentValue=e.pendingProps.value,t._changedBits=e.stateNode}function an(e){var t=Ta.current,n=_a.current;wt(Aa,e),wt(_a,e),wt(Ta,e),e=e.type._context,e._currentValue=n,e._changedBits=t}function sn(e){return e===Oa&&r("174"),e}function un(e,t){St(Ia,t,e),St(Na,e,e),St(Fa,Oa,e);var n=t.nodeType;switch(n){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:at(null,"");break;default:n=8===n?t.parentNode:t,t=n.namespaceURI||null,n=n.tagName,t=at(t,n)}wt(Fa,e),St(Fa,t,e)}function cn(e){wt(Fa,e),wt(Na,e),wt(Ia,e)}function ln(e){Na.current===e&&(wt(Fa,e),wt(Na,e))}function pn(e,t,n){var r=e.memoizedState;t=t(n,r),r=null===t||void 0===t?r:Mr({},r,t),e.memoizedState=r,null!==(e=e.updateQueue)&&0===e.expirationTime&&(e.baseState=r)}function fn(e,t,n,r,i,o){var a=e.stateNode;return e=e.type,"function"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(n,i,o):!e.prototype||!e.prototype.isPureReactComponent||(!Br(t,n)||!Br(r,i))}function dn(e,t,n,r){e=t.state,"function"===typeof t.componentWillReceiveProps&&t.componentWillReceiveProps(n,r),"function"===typeof t.UNSAFE_componentWillReceiveProps&&t.UNSAFE_componentWillReceiveProps(n,r),t.state!==e&&La.enqueueReplaceState(t,t.state,null)}function hn(e,t){var n=e.type,r=e.stateNode,i=e.pendingProps,o=kt(e);r.props=i,r.state=e.memoizedState,r.refs=Ur,r.context=At(e,o),o=e.updateQueue,null!==o&&(en(e,o,i,r,t),r.state=e.memoizedState),o=e.type.getDerivedStateFromProps,"function"===typeof o&&(pn(e,o,i),r.state=e.memoizedState),"function"===typeof n.getDerivedStateFromProps||"function"===typeof r.getSnapshotBeforeUpdate||"function"!==typeof r.UNSAFE_componentWillMount&&"function"!==typeof r.componentWillMount||(n=r.state,"function"===typeof r.componentWillMount&&r.componentWillMount(),"function"===typeof r.UNSAFE_componentWillMount&&r.UNSAFE_componentWillMount(),n!==r.state&&La.enqueueReplaceState(r,r.state,null),null!==(o=e.updateQueue)&&(en(e,o,i,r,t),r.state=e.memoizedState)),"function"===typeof r.componentDidMount&&(e.effectTag|=4)}function mn(e,t,n){if(null!==(e=n.ref)&&"function"!==typeof e&&"object"!==typeof e){if(n._owner){n=n._owner;var i=void 0;n&&(2!==n.tag&&r("110"),i=n.stateNode),i||r("147",e);var o=""+e;return null!==t&&null!==t.ref&&"function"===typeof t.ref&&t.ref._stringRef===o?t.ref:(t=function(e){var t=i.refs===Ur?i.refs={}:i.refs;null===e?delete t[o]:t[o]=e},t._stringRef=o,t)}"string"!==typeof e&&r("148"),n._owner||r("254",e)}return e}function gn(e,t){"textarea"!==e.type&&r("31","[object Object]"===Object.prototype.toString.call(t)?"object with keys {"+Object.keys(t).join(", ")+"}":t,"")}function yn(e){function t(t,n){if(e){var r=t.lastEffect;null!==r?(r.nextEffect=n,t.lastEffect=n):t.firstEffect=t.lastEffect=n,n.nextEffect=null,n.effectTag=8}}function n(n,r){if(!e)return null;for(;null!==r;)t(n,r),r=r.sibling;return null}function i(e,t){for(e=new Map;null!==t;)null!==t.key?e.set(t.key,t):e.set(t.index,t),t=t.sibling;return e}function o(e,t,n){return e=Mt(e,t,n),e.index=0,e.sibling=null,e}function a(t,n,r){return t.index=r,e?null!==(r=t.alternate)?(r=r.index,rm?(g=p,p=null):g=p.sibling;var y=d(r,p,s[m],u);if(null===y){null===p&&(p=g);break}e&&p&&null===y.alternate&&t(r,p),o=a(y,o,m),null===l?c=y:l.sibling=y,l=y,p=g}if(m===s.length)return n(r,p),c;if(null===p){for(;mg?(y=m,m=null):y=m.sibling;var b=d(o,m,v.value,c);if(null===b){m||(m=y);break}e&&m&&null===b.alternate&&t(o,m),s=a(b,s,g),null===p?l=b:p.sibling=b,p=b,m=y}if(v.done)return n(o,m),l;if(null===m){for(;!v.done;g++,v=u.next())null!==(v=f(o,v.value,c))&&(s=a(v,s,g),null===p?l=v:p.sibling=v,p=v);return l}for(m=i(o,m);!v.done;g++,v=u.next())null!==(v=h(m,o,g,v.value,c))&&(e&&null!==v.alternate&&m.delete(null===v.key?g:v.key),s=a(v,s,g),null===p?l=v:p.sibling=v,p=v);return e&&m.forEach(function(e){return t(o,e)}),l}return function(e,i,a,u){"object"===typeof a&&null!==a&&a.type===zi&&null===a.key&&(a=a.props.children);var c="object"===typeof a&&null!==a;if(c)switch(a.$$typeof){case $i:e:{var l=a.key;for(c=i;null!==c;){if(c.key===l){if(10===c.tag?a.type===zi:c.type===a.type){n(e,c.sibling),i=o(c,a.type===zi?a.props.children:a.props,u),i.ref=mn(e,c,a),i.return=e,e=i;break e}n(e,c);break}t(e,c),c=c.sibling}a.type===zi?(i=Rt(a.props.children,e.mode,u,a.key),i.return=e,e=i):(u=jt(a,e.mode,u),u.ref=mn(e,i,a),u.return=e,e=u)}return s(e);case Ui:e:{for(c=a.key;null!==i;){if(i.key===c){if(4===i.tag&&i.stateNode.containerInfo===a.containerInfo&&i.stateNode.implementation===a.implementation){n(e,i.sibling),i=o(i,a.children||[],u),i.return=e,e=i;break e}n(e,i);break}t(e,i),i=i.sibling}i=$t(a,e.mode,u),i.return=e,e=i}return s(e)}if("string"===typeof a||"number"===typeof a)return a=""+a,null!==i&&6===i.tag?(n(e,i.sibling),i=o(i,a,u),i.return=e,e=i):(n(e,i),i=Bt(a,e.mode,u),i.return=e,e=i),s(e);if(Pa(a))return m(e,i,a,u);if(oe(a))return g(e,i,a,u);if(c&&gn(e,a),"undefined"===typeof a)switch(e.tag){case 2:case 1:u=e.type,r("152",u.displayName||u.name||"Component")}return n(e,i)}}function vn(e,t){var n=new Pt(5,null,null,0);n.type="DELETED",n.stateNode=t,n.return=e,n.effectTag=8,null!==e.lastEffect?(e.lastEffect.nextEffect=n,e.lastEffect=n):e.firstEffect=e.lastEffect=n}function bn(e,t){switch(e.tag){case 5:var n=e.type;return null!==(t=1!==t.nodeType||n.toLowerCase()!==t.nodeName.toLowerCase()?null:t)&&(e.stateNode=t,!0);case 6:return null!==(t=""===e.pendingProps||3!==t.nodeType?null:t)&&(e.stateNode=t,!0);default:return!1}}function xn(e){if($a){var t=Ba;if(t){var n=t;if(!bn(e,t)){if(!(t=Ct(n))||!bn(e,t))return e.effectTag|=2,$a=!1,void(Ra=e);vn(Ra,n)}Ra=e,Ba=Et(t)}else e.effectTag|=2,$a=!1,Ra=e}}function Cn(e){for(e=e.return;null!==e&&5!==e.tag&&3!==e.tag;)e=e.return;Ra=e}function En(e){if(e!==Ra)return!1;if(!$a)return Cn(e),$a=!0,!1;var t=e.type;if(5!==e.tag||"head"!==t&&"body"!==t&&!xt(t,e.memoizedProps))for(t=Ba;t;)vn(e,t),t=Ct(t);return Cn(e),Ba=Ra?Ct(e.stateNode):null,!0}function Dn(){Ba=Ra=null,$a=!1}function wn(e,t,n){Sn(e,t,n,t.expirationTime)}function Sn(e,t,n,r){t.child=null===e?ja(t,null,n,r):Ma(t,e.child,n,r)}function kn(e,t){var n=t.ref;(null===e&&null!==n||null!==e&&e.ref!==n)&&(t.effectTag|=128)}function An(e,t,n,r,i){kn(e,t);var o=0!==(64&t.effectTag);if(!n&&!o)return r&&Lt(t,!1),Fn(e,t);n=t.stateNode,Ri.current=t;var a=o?null:n.render();return t.effectTag|=1,o&&(Sn(e,t,null,i),t.child=null),Sn(e,t,a,i),t.memoizedState=n.state,t.memoizedProps=n.props,r&&Lt(t,!0),t.child}function _n(e){var t=e.stateNode;t.pendingContext?Ft(e,t.pendingContext,t.pendingContext!==t.context):t.context&&Ft(e,t.context,!1),un(e,t.containerInfo)}function Tn(e,t,n,r){var i=e.child;for(null!==i&&(i.return=e);null!==i;){switch(i.tag){case 12:var o=0|i.stateNode;if(i.type===t&&0!==(o&n)){for(o=i;null!==o;){var a=o.alternate;if(0===o.expirationTime||o.expirationTime>r)o.expirationTime=r,null!==a&&(0===a.expirationTime||a.expirationTime>r)&&(a.expirationTime=r);else{if(null===a||!(0===a.expirationTime||a.expirationTime>r))break;a.expirationTime=r}o=o.return}o=null}else o=i.child;break;case 13:o=i.type===e.type?null:i.child;break;default:o=i.child}if(null!==o)o.return=i;else for(o=i;null!==o;){if(o===e){o=null;break}if(null!==(i=o.sibling)){i.return=o.return,o=i;break}o=o.return}i=o}}function On(e,t,n){var r=t.type._context,i=t.pendingProps,o=t.memoizedProps,a=!0;if(Ea.current)a=!1;else if(o===i)return t.stateNode=0,on(t),Fn(e,t);var s=i.value;if(t.memoizedProps=i,null===o)s=1073741823;else if(o.value===i.value){if(o.children===i.children&&a)return t.stateNode=0,on(t),Fn(e,t);s=0}else{var u=o.value;if(u===s&&(0!==u||1/u===1/s)||u!==u&&s!==s){if(o.children===i.children&&a)return t.stateNode=0,on(t),Fn(e,t);s=0}else if(s="function"===typeof r._calculateChangedBits?r._calculateChangedBits(u,s):1073741823,0===(s|=0)){if(o.children===i.children&&a)return t.stateNode=0,on(t),Fn(e,t)}else Tn(t,r,s,n)}return t.stateNode=s,on(t),wn(e,t,i.children),t.child}function Fn(e,t){if(null!==e&&t.child!==e.child&&r("153"),null!==t.child){e=t.child;var n=Mt(e,e.pendingProps,e.expirationTime);for(t.child=n,n.return=t;null!==e.sibling;)e=e.sibling,n=n.sibling=Mt(e,e.pendingProps,e.expirationTime),n.return=t;n.sibling=null}return t.child}function Nn(e,t,n){if(0===t.expirationTime||t.expirationTime>n){switch(t.tag){case 3:_n(t);break;case 2:It(t);break;case 4:un(t,t.stateNode.containerInfo);break;case 13:on(t)}return null}switch(t.tag){case 0:null!==e&&r("155");var i=t.type,o=t.pendingProps,a=kt(t);return a=At(t,a),i=i(o,a),t.effectTag|=1,"object"===typeof i&&null!==i&&"function"===typeof i.render&&void 0===i.$$typeof?(a=t.type,t.tag=2,t.memoizedState=null!==i.state&&void 0!==i.state?i.state:null,a=a.getDerivedStateFromProps,"function"===typeof a&&pn(t,a,o),o=It(t),i.updater=La,t.stateNode=i,i._reactInternalFiber=t,hn(t,n),e=An(e,t,!0,o,n)):(t.tag=1,wn(e,t,i),t.memoizedProps=o,e=t.child),e;case 1:return o=t.type,n=t.pendingProps,Ea.current||t.memoizedProps!==n?(i=kt(t),i=At(t,i),o=o(n,i),t.effectTag|=1,wn(e,t,o),t.memoizedProps=n,e=t.child):e=Fn(e,t),e;case 2:if(o=It(t),null===e)if(null===t.stateNode){var s=t.pendingProps,u=t.type;i=kt(t);var c=2===t.tag&&null!=t.type.contextTypes;a=c?At(t,i):Ur,s=new u(s,a),t.memoizedState=null!==s.state&&void 0!==s.state?s.state:null,s.updater=La,t.stateNode=s,s._reactInternalFiber=t,c&&(c=t.stateNode,c.__reactInternalMemoizedUnmaskedChildContext=i,c.__reactInternalMemoizedMaskedChildContext=a),hn(t,n),i=!0}else{u=t.type,i=t.stateNode,c=t.memoizedProps,a=t.pendingProps,i.props=c;var l=i.context;s=kt(t),s=At(t,s);var p=u.getDerivedStateFromProps;(u="function"===typeof p||"function"===typeof i.getSnapshotBeforeUpdate)||"function"!==typeof i.UNSAFE_componentWillReceiveProps&&"function"!==typeof i.componentWillReceiveProps||(c!==a||l!==s)&&dn(t,i,a,s),ka=!1;var f=t.memoizedState;l=i.state=f;var d=t.updateQueue;null!==d&&(en(t,d,a,i,n),l=t.memoizedState),c!==a||f!==l||Ea.current||ka?("function"===typeof p&&(pn(t,p,a),l=t.memoizedState),(c=ka||fn(t,c,a,f,l,s))?(u||"function"!==typeof i.UNSAFE_componentWillMount&&"function"!==typeof i.componentWillMount||("function"===typeof i.componentWillMount&&i.componentWillMount(),"function"===typeof i.UNSAFE_componentWillMount&&i.UNSAFE_componentWillMount()),"function"===typeof i.componentDidMount&&(t.effectTag|=4)):("function"===typeof i.componentDidMount&&(t.effectTag|=4),t.memoizedProps=a,t.memoizedState=l),i.props=a,i.state=l,i.context=s,i=c):("function"===typeof i.componentDidMount&&(t.effectTag|=4),i=!1)}else u=t.type,i=t.stateNode,a=t.memoizedProps,c=t.pendingProps,i.props=a,l=i.context,s=kt(t),s=At(t,s),p=u.getDerivedStateFromProps,(u="function"===typeof p||"function"===typeof i.getSnapshotBeforeUpdate)||"function"!==typeof i.UNSAFE_componentWillReceiveProps&&"function"!==typeof i.componentWillReceiveProps||(a!==c||l!==s)&&dn(t,i,c,s),ka=!1,l=t.memoizedState,f=i.state=l,d=t.updateQueue,null!==d&&(en(t,d,c,i,n),f=t.memoizedState),a!==c||l!==f||Ea.current||ka?("function"===typeof p&&(pn(t,p,c),f=t.memoizedState),(p=ka||fn(t,a,c,l,f,s))?(u||"function"!==typeof i.UNSAFE_componentWillUpdate&&"function"!==typeof i.componentWillUpdate||("function"===typeof i.componentWillUpdate&&i.componentWillUpdate(c,f,s),"function"===typeof i.UNSAFE_componentWillUpdate&&i.UNSAFE_componentWillUpdate(c,f,s)),"function"===typeof i.componentDidUpdate&&(t.effectTag|=4),"function"===typeof i.getSnapshotBeforeUpdate&&(t.effectTag|=256)):("function"!==typeof i.componentDidUpdate||a===e.memoizedProps&&l===e.memoizedState||(t.effectTag|=4),"function"!==typeof i.getSnapshotBeforeUpdate||a===e.memoizedProps&&l===e.memoizedState||(t.effectTag|=256),t.memoizedProps=c,t.memoizedState=f),i.props=c,i.state=f,i.context=s,i=p):("function"!==typeof i.componentDidUpdate||a===e.memoizedProps&&l===e.memoizedState||(t.effectTag|=4),"function"!==typeof i.getSnapshotBeforeUpdate||a===e.memoizedProps&&l===e.memoizedState||(t.effectTag|=256),i=!1);return An(e,t,i,o,n);case 3:return _n(t),o=t.updateQueue,null!==o?(i=t.memoizedState,i=null!==i?i.element:null,en(t,o,t.pendingProps,null,n),(o=t.memoizedState.element)===i?(Dn(),e=Fn(e,t)):(i=t.stateNode,(i=(null===e||null===e.child)&&i.hydrate)&&(Ba=Et(t.stateNode.containerInfo),Ra=t,i=$a=!0),i?(t.effectTag|=2,t.child=ja(t,null,o,n)):(Dn(),wn(e,t,o)),e=t.child)):(Dn(),e=Fn(e,t)),e;case 5:return sn(Ia.current),o=sn(Fa.current),i=at(o,t.type),o!==i&&(St(Na,t,t),St(Fa,i,t)),null===e&&xn(t),o=t.type,c=t.memoizedProps,i=t.pendingProps,a=null!==e?e.memoizedProps:null,Ea.current||c!==i||((c=1&t.mode&&!!i.hidden)&&(t.expirationTime=1073741823),c&&1073741823===n)?(c=i.children,xt(o,i)?c=null:a&&xt(o,a)&&(t.effectTag|=16),kn(e,t),1073741823!==n&&1&t.mode&&i.hidden?(t.expirationTime=1073741823,t.memoizedProps=i,e=null):(wn(e,t,c),t.memoizedProps=i,e=t.child)):e=Fn(e,t),e;case 6:return null===e&&xn(t),t.memoizedProps=t.pendingProps,null;case 16:return null;case 4:return un(t,t.stateNode.containerInfo),o=t.pendingProps,Ea.current||t.memoizedProps!==o?(null===e?t.child=Ma(t,null,o,n):wn(e,t,o),t.memoizedProps=o,e=t.child):e=Fn(e,t),e;case 14:return o=t.type.render,n=t.pendingProps,i=t.ref,Ea.current||t.memoizedProps!==n||i!==(null!==e?e.ref:null)?(o=o(n,i),wn(e,t,o),t.memoizedProps=n,e=t.child):e=Fn(e,t),e;case 10:return n=t.pendingProps,Ea.current||t.memoizedProps!==n?(wn(e,t,n),t.memoizedProps=n,e=t.child):e=Fn(e,t),e;case 11:return n=t.pendingProps.children,Ea.current||null!==n&&t.memoizedProps!==n?(wn(e,t,n),t.memoizedProps=n,e=t.child):e=Fn(e,t),e;case 15:return n=t.pendingProps,t.memoizedProps===n?e=Fn(e,t):(wn(e,t,n.children),t.memoizedProps=n,e=t.child),e;case 13:return On(e,t,n);case 12:e:if(i=t.type,a=t.pendingProps,c=t.memoizedProps,o=i._currentValue,s=i._changedBits,Ea.current||0!==s||c!==a){if(t.memoizedProps=a,u=a.unstable_observedBits,void 0!==u&&null!==u||(u=1073741823),t.stateNode=u,0!==(s&u))Tn(t,i,s,n);else if(c===a){e=Fn(e,t);break e}n=a.children,n=n(o),t.effectTag|=1,wn(e,t,n),e=t.child}else e=Fn(e,t);return e;default:r("156")}}function In(e){e.effectTag|=4}function Ln(e,t){var n=t.pendingProps;switch(t.tag){case 1:return null;case 2:return Tt(t),null;case 3:cn(t),Ot(t);var i=t.stateNode;return i.pendingContext&&(i.context=i.pendingContext,i.pendingContext=null),null!==e&&null!==e.child||(En(t),t.effectTag&=-3),Ua(t),null;case 5:ln(t),i=sn(Ia.current);var o=t.type;if(null!==e&&null!=t.stateNode){var a=e.memoizedProps,s=t.stateNode,u=sn(Fa.current);s=mt(s,o,a,n,i),za(e,t,s,o,a,n,i,u),e.ref!==t.ref&&(t.effectTag|=128)}else{if(!n)return null===t.stateNode&&r("166"),null;if(e=sn(Fa.current),En(t))n=t.stateNode,o=t.type,a=t.memoizedProps,n[ri]=t,n[ii]=a,i=yt(n,o,a,e,i),t.updateQueue=i,null!==i&&In(t);else{e=ft(o,n,i,e),e[ri]=t,e[ii]=n;e:for(a=t.child;null!==a;){if(5===a.tag||6===a.tag)e.appendChild(a.stateNode);else if(4!==a.tag&&null!==a.child){a.child.return=a,a=a.child;continue}if(a===t)break;for(;null===a.sibling;){if(null===a.return||a.return===t)break e;a=a.return}a.sibling.return=a.return,a=a.sibling}ht(e,o,n,i),bt(o,n)&&In(t),t.stateNode=e}null!==t.ref&&(t.effectTag|=128)}return null;case 6:if(e&&null!=t.stateNode)Ga(e,t,e.memoizedProps,n);else{if("string"!==typeof n)return null===t.stateNode&&r("166"),null;i=sn(Ia.current),sn(Fa.current),En(t)?(i=t.stateNode,n=t.memoizedProps,i[ri]=t,vt(i,n)&&In(t)):(i=dt(n,i),i[ri]=t,t.stateNode=i)}return null;case 14:case 16:case 10:case 11:case 15:return null;case 4:return cn(t),Ua(t),null;case 13:return an(t),null;case 12:return null;case 0:r("167");default:r("156")}}function Pn(e,t){var n=t.source;null===t.stack&&null!==n&&se(n),null!==n&&ae(n),t=t.value,null!==e&&2===e.tag&&ae(e);try{t&&t.suppressReactErrorLogging||console.error(t)}catch(e){e&&e.suppressReactErrorLogging||console.error(e)}}function Mn(e){var t=e.ref;if(null!==t)if("function"===typeof t)try{t(null)}catch(t){Jn(e,t)}else t.current=null}function jn(e){switch("function"===typeof qt&&qt(e),e.tag){case 2:Mn(e);var t=e.stateNode;if("function"===typeof t.componentWillUnmount)try{t.props=e.memoizedProps,t.state=e.memoizedState,t.componentWillUnmount()}catch(t){Jn(e,t)}break;case 5:Mn(e);break;case 4:$n(e)}}function Rn(e){return 5===e.tag||3===e.tag||4===e.tag}function Bn(e){e:{for(var t=e.return;null!==t;){if(Rn(t)){var n=t;break e}t=t.return}r("160"),n=void 0}var i=t=void 0;switch(n.tag){case 5:t=n.stateNode,i=!1;break;case 3:case 4:t=n.stateNode.containerInfo,i=!0;break;default:r("161")}16&n.effectTag&&(st(t,""),n.effectTag&=-17);e:t:for(n=e;;){for(;null===n.sibling;){if(null===n.return||Rn(n.return)){n=null;break e}n=n.return}for(n.sibling.return=n.return,n=n.sibling;5!==n.tag&&6!==n.tag;){if(2&n.effectTag)continue t;if(null===n.child||4===n.tag)continue t;n.child.return=n,n=n.child}if(!(2&n.effectTag)){n=n.stateNode;break e}}for(var o=e;;){if(5===o.tag||6===o.tag)if(n)if(i){var a=t,s=o.stateNode,u=n;8===a.nodeType?a.parentNode.insertBefore(s,u):a.insertBefore(s,u)}else t.insertBefore(o.stateNode,n);else i?(a=t,s=o.stateNode,8===a.nodeType?a.parentNode.insertBefore(s,a):a.appendChild(s)):t.appendChild(o.stateNode);else if(4!==o.tag&&null!==o.child){o.child.return=o,o=o.child;continue}if(o===e)break;for(;null===o.sibling;){if(null===o.return||o.return===e)return;o=o.return}o.sibling.return=o.return,o=o.sibling}}function $n(e){for(var t=e,n=!1,i=void 0,o=void 0;;){if(!n){n=t.return;e:for(;;){switch(null===n&&r("160"),n.tag){case 5:i=n.stateNode,o=!1;break e;case 3:case 4:i=n.stateNode.containerInfo,o=!0;break e}n=n.return}n=!0}if(5===t.tag||6===t.tag){e:for(var a=t,s=a;;)if(jn(s),null!==s.child&&4!==s.tag)s.child.return=s,s=s.child;else{if(s===a)break;for(;null===s.sibling;){if(null===s.return||s.return===a)break e;s=s.return}s.sibling.return=s.return,s=s.sibling}o?(a=i,s=t.stateNode,8===a.nodeType?a.parentNode.removeChild(s):a.removeChild(s)):i.removeChild(t.stateNode)}else if(4===t.tag?i=t.stateNode.containerInfo:jn(t),null!==t.child){t.child.return=t,t=t.child;continue}if(t===e)break;for(;null===t.sibling;){if(null===t.return||t.return===e)return;t=t.return,4===t.tag&&(n=!1)}t.sibling.return=t.return,t=t.sibling}}function Un(e,t){switch(t.tag){case 2:break;case 5:var n=t.stateNode;if(null!=n){var i=t.memoizedProps;e=null!==e?e.memoizedProps:i;var o=t.type,a=t.updateQueue;t.updateQueue=null,null!==a&&(n[ii]=i,gt(n,a,o,e,i))}break;case 6:null===t.stateNode&&r("162"),t.stateNode.nodeValue=t.memoizedProps;break;case 3:case 15:case 16:break;default:r("163")}}function zn(e,t,n){n=Qt(n),n.tag=3,n.payload={element:null};var r=t.value;return n.callback=function(){hr(r),Pn(e,t)},n}function Gn(e,t,n){n=Qt(n),n.tag=3;var r=e.stateNode;return null!==r&&"function"===typeof r.componentDidCatch&&(n.callback=function(){null===is?is=new Set([this]):is.add(this);var n=t.value,r=t.stack;Pn(e,t),this.componentDidCatch(n,{componentStack:null!==r?r:""})}),n}function Vn(e,t,n,r,i,o){n.effectTag|=512,n.firstEffect=n.lastEffect=null,r=rn(r,n),e=t;do{switch(e.tag){case 3:return e.effectTag|=1024,r=zn(e,r,o),void Yt(e,r,o);case 2:if(t=r,n=e.stateNode,0===(64&e.effectTag)&&null!==n&&"function"===typeof n.componentDidCatch&&(null===is||!is.has(n)))return e.effectTag|=1024,r=Gn(e,t,o),void Yt(e,r,o)}e=e.return}while(null!==e)}function qn(e){switch(e.tag){case 2:Tt(e);var t=e.effectTag;return 1024&t?(e.effectTag=-1025&t|64,e):null;case 3:return cn(e),Ot(e),t=e.effectTag,1024&t?(e.effectTag=-1025&t|64,e):null;case 5:return ln(e),null;case 16:return t=e.effectTag,1024&t?(e.effectTag=-1025&t|64,e):null;case 4:return cn(e),null;case 13:return an(e),null;default:return null}}function Hn(){if(null!==Ja)for(var e=Ja.return;null!==e;){var t=e;switch(t.tag){case 2:Tt(t);break;case 3:cn(t),Ot(t);break;case 5:ln(t);break;case 4:cn(t);break;case 13:an(t)}e=e.return}Ya=null,Xa=0,Za=-1,es=!1,Ja=null,rs=!1}function Wn(e){for(;;){var t=e.alternate,n=e.return,r=e.sibling;if(0===(512&e.effectTag)){t=Ln(t,e,Xa);var i=e;if(1073741823===Xa||1073741823!==i.expirationTime){var o=0;switch(i.tag){case 3:case 2:var a=i.updateQueue;null!==a&&(o=a.expirationTime)}for(a=i.child;null!==a;)0!==a.expirationTime&&(0===o||o>a.expirationTime)&&(o=a.expirationTime),a=a.sibling;i.expirationTime=o}if(null!==t)return t;if(null!==n&&0===(512&n.effectTag)&&(null===n.firstEffect&&(n.firstEffect=e.firstEffect),null!==e.lastEffect&&(null!==n.lastEffect&&(n.lastEffect.nextEffect=e.firstEffect),n.lastEffect=e.lastEffect),1fs)&&(fs=e),e}function Zn(e,t){for(;null!==e;){if((0===e.expirationTime||e.expirationTime>t)&&(e.expirationTime=t),null!==e.alternate&&(0===e.alternate.expirationTime||e.alternate.expirationTime>t)&&(e.alternate.expirationTime=t),null===e.return){if(3!==e.tag)break;var n=e.stateNode;!Ka&&0!==Xa&&tCs&&r("185")}e=e.return}}function er(){return Ha=ga()-Va,qa=2+(Ha/10|0)}function tr(e){var t=Qa;Qa=2+25*(1+((er()-2+500)/25|0));try{return e()}finally{Qa=t}}function nr(e,t,n,r,i){var o=Qa;Qa=1;try{return e(t,n,r,i)}finally{Qa=o}}function rr(e){if(0!==ss){if(e>ss)return;va(us)}var t=ga()-Va;ss=e,us=ya(ar,{timeout:10*(e-2)-t})}function ir(e,t){if(null===e.nextScheduledRoot)e.remainingExpirationTime=t,null===as?(os=as=e,e.nextScheduledRoot=e):(as=as.nextScheduledRoot=e,as.nextScheduledRoot=os);else{var n=e.remainingExpirationTime;(0===n||t=ps)&&(!ds||er()>=ps);)er(),pr(ls,ps,!ds),or();else for(;null!==ls&&0!==ps&&(0===e||e>=ps);)pr(ls,ps,!1),or();null!==gs&&(ss=0,us=-1),0!==ps&&rr(ps),gs=null,ds=!1,lr()}function cr(e,t){cs&&r("253"),ls=e,ps=t,pr(e,t,!1),sr(),lr()}function lr(){if(Es=0,null!==xs){var e=xs;xs=null;for(var t=0;tb&&(x=b,b=k,k=x),x=Qe(w,k),C=Qe(w,b),x&&C&&(1!==S.rangeCount||S.anchorNode!==x.node||S.anchorOffset!==x.offset||S.focusNode!==C.node||S.focusOffset!==C.offset)&&(E=document.createRange(),E.setStart(x.node,x.offset),S.removeAllRanges(),k>b?(S.addRange(E),S.extend(C.node,C.offset)):(E.setEnd(C.node,C.offset),S.addRange(E))))),S=[];for(k=w;k=k.parentNode;)1===k.nodeType&&S.push({element:k,left:k.scrollLeft,top:k.scrollTop});for(w.focus(),w=0;wDs)&&(ds=!0)}function hr(e){null===ls&&r("246"),ls.remainingExpirationTime=0,hs||(hs=!0,ms=e)}function mr(e){null===ls&&r("246"),ls.remainingExpirationTime=e}function gr(e,t){var n=ys;ys=!0;try{return e(t)}finally{(ys=n)||cs||sr()}}function yr(e,t){if(ys&&!vs){vs=!0;try{return e(t)}finally{vs=!1}}return e(t)}function vr(e,t){cs&&r("187");var n=ys;ys=!0;try{return nr(e,t)}finally{ys=n,sr()}}function br(e){var t=ys;ys=!0;try{nr(e)}finally{(ys=t)||cs||ur(1,!1,null)}}function xr(e,t,n,i,o){var a=t.current;if(n){n=n._reactInternalFiber;var s;e:{for(2===Ie(n)&&2===n.tag||r("170"),s=n;3!==s.tag;){if(_t(s)){s=s.stateNode.__reactInternalMemoizedMergedChildContext;break e}(s=s.return)||r("171")}s=s.stateNode.context}n=_t(n)?Nt(n,s):s}else n=Ur;return null===t.context?t.context=n:t.pendingContext=n,t=o,o=Qt(i),o.payload={element:e},t=void 0===t?null:t,null!==t&&(o.callback=t),Jt(a,o,i),Zn(a,i),i}function Cr(e){var t=e._reactInternalFiber;return void 0===t&&("function"===typeof e.render?r("188"):r("268",Object.keys(e))),e=Me(t),null===e?null:e.stateNode}function Er(e,t,n,r){var i=t.current;return i=Xn(er(),i),xr(e,t,n,i,r)}function Dr(e){if(e=e.current,!e.child)return null;switch(e.child.tag){case 5:default:return e.child.stateNode}}function wr(e){var t=e.findFiberByHostInstance;return Gt(Mr({},e,{findHostInstanceByFiber:function(e){return e=Me(e),null===e?null:e.stateNode},findFiberByHostInstance:function(e){return t?t(e):null}}))}function Sr(e,t,n){var r=3=Di),ki=String.fromCharCode(32),Ai={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},_i=!1,Ti=!1,Oi={eventTypes:Ai,extractEvents:function(e,t,n,r){var i=void 0,o=void 0;if(Ei)e:{switch(e){case"compositionstart":i=Ai.compositionStart;break e;case"compositionend":i=Ai.compositionEnd;break e;case"compositionupdate":i=Ai.compositionUpdate;break e}i=void 0}else Ti?$(e,n)&&(i=Ai.compositionEnd):"keydown"===e&&229===n.keyCode&&(i=Ai.compositionStart);return i?(Si&&(Ti||i!==Ai.compositionStart?i===Ai.compositionEnd&&Ti&&(o=L()):(gi._root=r,gi._startText=P(),Ti=!0)),i=bi.getPooled(i,t,n,r),o?i.data=o:null!==(o=U(n))&&(i.data=o),T(i),o=i):o=null,(e=wi?z(e,n):G(e,n))?(t=xi.getPooled(Ai.beforeInput,t,n,r),t.data=e,T(t)):t=null,null===o?t:null===t?o:[o,t]}},Fi=null,Ni={injectFiberControlledHostComponent:function(e){Fi=e}},Ii=null,Li=null,Pi={injection:Ni,enqueueStateRestore:q,needsStateRestore:H,restoreStateIfNeeded:W},Mi=!1,ji={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0},Ri=Lr.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,Bi="function"===typeof Symbol&&Symbol.for,$i=Bi?Symbol.for("react.element"):60103,Ui=Bi?Symbol.for("react.portal"):60106,zi=Bi?Symbol.for("react.fragment"):60107,Gi=Bi?Symbol.for("react.strict_mode"):60108,Vi=Bi?Symbol.for("react.profiler"):60114,qi=Bi?Symbol.for("react.provider"):60109,Hi=Bi?Symbol.for("react.context"):60110,Wi=Bi?Symbol.for("react.async_mode"):60111,Qi=Bi?Symbol.for("react.forward_ref"):60112,Ki=Bi?Symbol.for("react.timeout"):60113,Ji="function"===typeof Symbol&&Symbol.iterator,Yi=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Xi={},Zi={},eo={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){eo[e]=new pe(e,0,!1,e,null)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];eo[t]=new pe(t,1,!1,e[1],null)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){eo[e]=new pe(e,2,!1,e.toLowerCase(),null)}),["autoReverse","externalResourcesRequired","preserveAlpha"].forEach(function(e){eo[e]=new pe(e,2,!1,e,null)}),"allowFullScreen async autoFocus autoPlay controls default defer disabled formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){eo[e]=new pe(e,3,!1,e.toLowerCase(),null)}),["checked","multiple","muted","selected"].forEach(function(e){eo[e]=new pe(e,3,!0,e.toLowerCase(),null)}),["capture","download"].forEach(function(e){eo[e]=new pe(e,4,!1,e.toLowerCase(),null)}),["cols","rows","size","span"].forEach(function(e){eo[e]=new pe(e,6,!1,e.toLowerCase(),null)}),["rowSpan","start"].forEach(function(e){eo[e]=new pe(e,5,!1,e.toLowerCase(),null)});var to=/[\-:]([a-z])/g;"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(to,fe);eo[t]=new pe(t,1,!1,e,null)}),"xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(to,fe);eo[t]=new pe(t,1,!1,e,"http://www.w3.org/1999/xlink")}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(to,fe);eo[t]=new pe(t,1,!1,e,"http://www.w3.org/XML/1998/namespace")}),eo.tabIndex=new pe("tabIndex",1,!1,"tabindex",null);var no={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"},dependencies:"blur change click focus input keydown keyup selectionchange".split(" ")}},ro=null,io=null,oo=!1;Pr.canUseDOM&&(oo=ee("input")&&(!document.documentMode||9=document.documentMode,Mo={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"blur contextmenu focus keydown keyup mousedown mouseup selectionchange".split(" ")}},jo=null,Ro=null,Bo=null,$o=!1,Uo={eventTypes:Mo,extractEvents:function(e,t,n,r){var i,o=r.window===r?r.document:9===r.nodeType?r:r.ownerDocument;if(!(i=!o)){e:{o=He(o),i=Qr.onSelect;for(var a=0;ae))){Qo=-1,ea.didTimeout=!0;for(var t=0,n=qo.length;tt&&(t=8),Zo=t"+t+"",t=sa.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}}),ca={animationIterationCount:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},la=["Webkit","ms","Moz","O"];Object.keys(ca).forEach(function(e){la.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),ca[t]=ca[e]})});var pa=Mr({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),fa=jr.thatReturns(""),da={createElement:ft,createTextNode:dt,setInitialProperties:ht,diffProperties:mt,updateProperties:gt,diffHydratedProperties:yt,diffHydratedText:vt,warnForUnmatchedText:function(){},warnForDeletedHydratableElement:function(){},warnForDeletedHydratableText:function(){},warnForInsertedHydratedElement:function(){},warnForInsertedHydratedText:function(){},restoreControlledState:function(e,t,n){switch(t){case"input":if(ye(e,n),t=n.name,"radio"===n.type&&null!=t){for(n=e;n.parentNode;)n=n.parentNode;for(n=n.querySelectorAll("input[name="+JSON.stringify(""+t)+'][type="radio"]'),t=0;t0&&void 0!==arguments[0]?arguments[0]:"store",n=arguments[1],a=n||t+"Subscription",u=function(e){function n(o,a){r(this,n);var s=i(this,e.call(this,o,a));return s[t]=o.store,s}return o(n,e),n.prototype.getChildContext=function(){var e;return e={},e[t]=this[t],e[a]=null,e},n.prototype.render=function(){return s.Children.only(this.props.children)},n}(s.Component);return u.propTypes={store:l.a.isRequired,children:c.a.element.isRequired},u.childContextTypes=(e={},e[t]=l.a.isRequired,e[a]=l.b,e),u}t.a=a;var s=n(0),u=(n.n(s),n(18)),c=n.n(u),l=n(155);n(101);t.b=a()},function(e,t,n){!function(t,n){e.exports=n()}(0,function(){"use strict";var e={childContextTypes:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},t={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},n=Object.defineProperty,r=Object.getOwnPropertyNames,i=Object.getOwnPropertySymbols,o=Object.getOwnPropertyDescriptor,a=Object.getPrototypeOf,s=a&&a(Object);return function u(c,l,p){if("string"!==typeof l){if(s){var f=a(l);f&&f!==s&&u(c,f,p)}var d=r(l);i&&(d=d.concat(i(l)));for(var h=0;h=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function i(e,t,n){for(var r=t.length-1;r>=0;r--){var i=t[r](e);if(i)return i}return function(t,r){throw new Error("Invalid value of type "+typeof e+" for "+n+" argument when connecting component "+r.wrappedComponentName+".")}}function o(e,t){return e===t}var a=n(156),s=n(333),u=n(334),c=n(352),l=n(353),p=n(354),f=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:{},t=e.connectHOC,n=void 0===t?a.a:t,d=e.mapStateToPropsFactories,h=void 0===d?c.a:d,m=e.mapDispatchToPropsFactories,g=void 0===m?u.a:m,y=e.mergePropsFactories,v=void 0===y?l.a:y,b=e.selectorFactory,x=void 0===b?p.a:b;return function(e,t,a){var u=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},c=u.pure,l=void 0===c||c,p=u.areStatesEqual,d=void 0===p?o:p,m=u.areOwnPropsEqual,y=void 0===m?s.a:m,b=u.areStatePropsEqual,C=void 0===b?s.a:b,E=u.areMergedPropsEqual,D=void 0===E?s.a:E,w=r(u,["pure","areStatesEqual","areOwnPropsEqual","areStatePropsEqual","areMergedPropsEqual"]),S=i(e,h,"mapStateToProps"),k=i(t,g,"mapDispatchToProps"),A=i(a,v,"mergeProps");return n(x,f({methodName:"connect",getDisplayName:function(e){return"Connect("+e+")"},shouldHandleStateChanges:Boolean(e),initMapStateToProps:S,initMapDispatchToProps:k,initMergeProps:A,pure:l,areStatesEqual:d,areOwnPropsEqual:y,areStatePropsEqual:C,areMergedPropsEqual:D},w))}}()},function(e,t,n){"use strict";function r(e,t){return e===t?0!==e||0!==t||1/e===1/t:e!==e&&t!==t}function i(e,t){if(r(e,t))return!0;if("object"!==typeof e||null===e||"object"!==typeof t||null===t)return!1;var n=Object.keys(e),i=Object.keys(t);if(n.length!==i.length)return!1;for(var a=0;a0&&void 0!==arguments[0]?arguments[0]:{},t=arguments[1];if(u)throw u;for(var i=!1,o={},a=0;a=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function i(e,t,n,r){return function(i,o){return n(e(i,o),t(r,o),o)}}function o(e,t,n,r,i){function o(i,o){return h=i,m=o,g=e(h,m),y=t(r,m),v=n(g,y,m),d=!0,v}function a(){return g=e(h,m),t.dependsOnOwnProps&&(y=t(r,m)),v=n(g,y,m)}function s(){return e.dependsOnOwnProps&&(g=e(h,m)),t.dependsOnOwnProps&&(y=t(r,m)),v=n(g,y,m)}function u(){var t=e(h,m),r=!f(t,g);return g=t,r&&(v=n(g,y,m)),v}function c(e,t){var n=!p(t,m),r=!l(e,h);return h=e,m=t,n&&r?a():n?s():r?u():v}var l=i.areStatesEqual,p=i.areOwnPropsEqual,f=i.areStatePropsEqual,d=!1,h=void 0,m=void 0,g=void 0,y=void 0,v=void 0;return function(e,t){return d?c(e,t):o(e,t)}}function a(e,t){var n=t.initMapStateToProps,a=t.initMapDispatchToProps,s=t.initMergeProps,u=r(t,["initMapStateToProps","initMapDispatchToProps","initMergeProps"]),c=n(e,u),l=a(e,u),p=s(e,u);return(u.pure?o:i)(c,l,p,e,u)}t.a=a;n(355)},function(e,t,n){"use strict";n(101)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(40),i=n(104),o=n(362),a=n(17),s=n(12),u=n(517),c=i.default(),l=[r.applyMiddleware(c)],p=window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__||r.compose,f=u.deserializeState();t.default=function(){var e=r.createStore(a.default,f,p.apply(null,l));return e.subscribe(u.serializeState(e)),window.s=e,window.session=function(){return s.getSelectedSession(e.getState())},c.run(o.default),e}},function(e,t,n){"use strict";function r(e,t){var n={};for(var r in e)t.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function i(){function e(t){var n=t.getState,r=t.dispatch,f=Object(a.c)();return f.emit=(u.emitter||o.o)(f.emit),e.run=s.a.bind(null,{context:i,subscribe:f.subscribe,dispatch:r,getState:n,sagaMonitor:c,logger:l,onError:p}),function(e){return function(t){c&&c.actionDispatched&&c.actionDispatched(t);var n=e(t);return f.emit(t),n}}}var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.context,i=void 0===n?{}:n,u=r(t,["context"]),c=u.sagaMonitor,l=u.logger,p=u.onError;if(o.q.func(u))throw new Error("Saga middleware no longer accept Generator functions. Use sagaMiddleware.run instead");if(l&&!o.q.func(l))throw new Error("`options.logger` passed to the Saga middleware is not a function!");if(p&&!o.q.func(p))throw new Error("`options.onError` passed to the Saga middleware is not a function!");if(u.emitter&&!o.q.func(u.emitter))throw new Error("`options.emitter` passed to the Saga middleware is not a function!");return e.run=function(){throw new Error("Before running a Saga, you must mount the Saga middleware on the Store using applyMiddleware")},e.setContext=function(e){Object(o.h)(e,o.q.object,Object(o.k)("sagaMiddleware",e)),o.v.assign(i,e)},e}t.a=i;var o=n(22),a=n(42),s=n(167)},function(e,t,n){"use strict";function r(e,t){for(var n=arguments.length,r=Array(n>2?n-2:0),s=2;s2?n-2:0),s=2;s3?r-3:0),l=3;l0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]1,i=!1,a=arguments[1],s=a;return new n(function(n){return t.subscribe({next:function(t){var o=!i;if(i=!0,!o||r)try{s=e(s,t)}catch(e){return n.error(e)}else s=t},error:function(e){n.error(e)},complete:function(){if(!i&&!r)return n.error(new TypeError("Cannot reduce an empty sequence"));n.next(s),n.complete()}})})}},{key:"concat",value:function(){for(var e=this,t=arguments.length,n=Array(t),r=0;r=0&&o.splice(e,1),i()}});o.push(a)},error:function(e){r.error(e)},complete:function(){i()}});return function(){o.forEach(function(e){return e.unsubscribe()}),a.unsubscribe()}})}},{key:y("observable"),value:function(){return this}}],[{key:"from",value:function(t){var n="function"===typeof this?this:e;if(null==t)throw new TypeError(t+" is not an object");var r=i(t,y("observable"));if(r){var o=r.call(t);if(Object(o)!==o)throw new TypeError(o+" is not an object");return a(o)&&o.constructor===n?o:new n(function(e){return o.subscribe(e)})}if(g("iterator")&&(r=i(t,y("iterator"))))return new n(function(e){u(function(){if(!e.closed){var n=!0,i=!1,o=void 0;try{for(var a,s=r.call(t)[Symbol.iterator]();!(n=(a=s.next()).done);n=!0){var u=a.value;if(e.next(u),e.closed)return}}catch(e){i=!0,o=e}finally{try{!n&&s.return&&s.return()}finally{if(i)throw o}}e.complete()}})});if(Array.isArray(t))return new n(function(e){u(function(){if(!e.closed){for(var n=0;n0&&e.jitter<=1?e.jitter:0,this.attempts=0}e.exports=n,n.prototype.duration=function(){var e=this.ms*Math.pow(this.factor,this.attempts++);if(this.jitter){var t=Math.random(),n=Math.floor(t*this.jitter*e);e=0==(1&Math.floor(10*t))?e-n:e+n}return 0|Math.min(e,this.max)},n.prototype.reset=function(){this.attempts=0},n.prototype.setMin=function(e){this.ms=e},n.prototype.setMax=function(e){this.max=e},n.prototype.setJitter=function(e){this.jitter=e}},function(e,t,n){"use strict";function r(){}function i(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function o(){this._events=new r,this._eventsCount=0}var a=Object.prototype.hasOwnProperty,s="~";Object.create&&(r.prototype=Object.create(null),(new r).__proto__||(s=!1)),o.prototype.eventNames=function(){var e,t,n=[];if(0===this._eventsCount)return n;for(t in e=this._events)a.call(e,t)&&n.push(s?t.slice(1):t);return Object.getOwnPropertySymbols?n.concat(Object.getOwnPropertySymbols(e)):n},o.prototype.listeners=function(e,t){var n=s?s+e:e,r=this._events[n];if(t)return!!r;if(!r)return[];if(r.fn)return[r.fn];for(var i=0,o=r.length,a=new Array(o);i=300&&c(t,n,"Response not successful: Received status code "+t.status),Array.isArray(n)||n.hasOwnProperty("data")||n.hasOwnProperty("errors")||c(t,n,"Server response was missing for query '"+(Array.isArray(e)?e.map(function(e){return e.operationName}):e.operationName)+"'."),n})}},p=function(e){if(!e&&"undefined"===typeof fetch){var t="unfetch";throw"undefined"===typeof window&&(t="node-fetch"),new Error("\nfetch is not found globally and no fetcher passed, to fix pass a fetch for\nyour environment like https://www.npmjs.com/package/"+t+".\n\nFor example:\nimport fetch from '"+t+"';\nimport { createHttpLink } from 'apollo-link-http';\n\nconst link = createHttpLink({ uri: '/graphql', fetch: fetch });")}},f=function(){if("undefined"===typeof AbortController)return{controller:!1,signal:!1};var e=new AbortController;return{controller:e,signal:e.signal}},d=function(e,t){for(var n=[],o=2;o0)return l({errors:f});l((0,s.execute)(e,p,n,r,i,u,c))})}Object.defineProperty(t,"__esModule",{value:!0}),t.graphql=r;var o=n(80),a=n(181),s=n(118)},function(e,t,n){"use strict";function r(e,t,n){var r=(0,u.getLocation)(e,t),a=r.line+e.locationOffset.line-1,s=o(e,r),l=r.column+s;return new c.GraphQLError("Syntax Error "+e.name+" ("+a+":"+l+") "+n+"\n\n"+i(e,r),void 0,e,[t])}function i(e,t){var n=t.line,r=e.locationOffset.line-1,i=o(e,t),u=n+r,c=(u-1).toString(),l=u.toString(),p=(u+1).toString(),f=p.length,d=e.body.split(/\r\n|[\n\r]/g);return d[0]=a(e.locationOffset.column-1)+d[0],(n>=2?s(f,c)+": "+d[n-2]+"\n":"")+s(f,l)+": "+d[n-1]+"\n"+a(2+f+t.column-1+i)+"^\n"+(n1&&void 0!==arguments[1]?arguments[1]:"";return 0===e.length?"":e.every(function(e){return!e.description})?"("+e.map(D).join(", ")+")":"(\n"+e.map(function(e,n){return k(e," "+t,!n)+" "+t+D(e)}).join("\n")+"\n"+t+")"}function D(e){var t=e.name+": "+String(e.type);return(0,I.default)(e.defaultValue)||(t+=" = "+(0,P.print)((0,L.astFromValue)(e.defaultValue,e.type))),t}function w(e){return k(e)+"directive @"+e.name+E(e.args)+" on "+e.locations.join(" | ")}function S(e){var t=e.deprecationReason;return(0,F.default)(t)?"":""===t||t===R.DEFAULT_DEPRECATION_REASON?" @deprecated":" @deprecated(reason: "+(0,P.print)((0,L.astFromValue)(t,j.GraphQLString))+")"}function k(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];if(!e.description)return"";for(var r=e.description.split("\n"),i=t&&!n?"\n":"",o=0;o1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:{},o=n.prefix,a=n.namespace,s=void 0===a?D.b:a;return Object(b.a)(Object.keys(e),function(n,a){var u=e[a];y()(t(u),"Expected function, undefined, null, or array with payload and meta functions for "+a);var c=o?""+o+s+a:a,l=Object(p.a)(u)?E.a.apply(void 0,[c].concat(i(u))):Object(E.a)(c,u);return S({},n,r({},a,l))})}function u(e,t){var n=Object(b.a)(e,function(e,t){return S({},e,r({},t,c.a))}),i=s(n,t);return Object(b.a)(Object.keys(i),function(e,t){return S({},e,r({},Object(v.a)(t),i[t]))})}t.a=o;var c=n(63),l=n(41),p=n(47),f=n(425),d=n(121),h=n(48),m=n(222),g=n(20),y=n.n(g),v=n(223),b=n(444),x=n(445),C=n(447),E=n(124),D=n(62),w=function(){function e(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var a,s=e[Symbol.iterator]();!(r=(a=s.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{!r&&s.return&&s.return()}finally{if(i)throw o}}return n}return function(t,n){if(Array.isArray(t))return t;if(Symbol.iterator in Object(t))return e(t,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),S=Object.assign||function(e){for(var t=1;t=r?e:Object(i.a)(e,t,n)}var i=n(431);t.a=r},function(e,t,n){"use strict";function r(e,t,n){var r=-1,i=e.length;t<0&&(t=-t>i?0:i+t),n=n>i?i:n,n<0&&(n+=i),i=t>n?0:n-t>>>0,t>>>=0;for(var o=Array(i);++r1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],s=Object(a.a)(o.shift());Object(i.a)(o)?r[s]=e[n]:(r[s]||(r[s]={}),t(n,r[s],o))}var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=n.namespace,s=void 0===r?o.b:r,u=n.prefix,c={};return Object.getOwnPropertyNames(e).forEach(function(e){var n=u?e.replace(""+u+s,""):e;return t(e,c,n.split(s))}),c}t.a=r;var i=n(209),o=n(62),a=n(223)},function(e,t,n){"use strict";var r=n(449),i=n(124);t.a=function(e,t){return Object(r.a)(Object(i.a)(e,t),t.length)}},function(e,t,n){"use strict";function r(e,t,n){t=n?void 0:t;var a=Object(i.a)(e,o,void 0,void 0,void 0,void 0,void 0,t);return a.placeholder=r.placeholder,a}var i=n(450),o=8;r.placeholder={},t.a=r},function(e,t,n){"use strict";function r(e,t,n,r,E,D,w,S){var k=t&g;if(!k&&"function"!=typeof e)throw new TypeError(h);var A=r?r.length:0;if(A||(t&=~(b|x),r=E=void 0),w=void 0===w?w:C(Object(d.a)(w),0),S=void 0===S?S:Object(d.a)(S),A-=E?E.length:0,t&x){var _=r,T=E;r=E=void 0}var O=k?void 0:Object(c.a)(e),F=[e,t,n,r,E,_,T,D,w,S];if(O&&Object(l.a)(F,O),e=F[0],t=F[1],n=F[2],r=F[3],E=F[4],S=F[9]=void 0===F[9]?k?0:e.length:C(F[9]-A,0),!S&&t&(y|v)&&(t&=~(y|v)),t&&t!=m)N=t==y||t==v?Object(a.a)(e,t,S):t!=b&&t!=(m|b)||E.length?s.a.apply(void 0,F):Object(u.a)(e,t,n,r);else var N=Object(o.a)(e,t,n);var I=O?i.a:p.a;return Object(f.a)(I(N,F),e,t)}var i=n(226),o=n(451),a=n(452),s=n(229),u=n(473),c=n(233),l=n(474),p=n(236),f=n(238),d=n(242),h="Expected a function",m=1,g=2,y=8,v=16,b=32,x=64,C=Math.max;t.a=r},function(e,t,n){"use strict";function r(e,t,n){function r(){return(this&&this!==o.a&&this instanceof r?u:e).apply(s?n:this,arguments)}var s=t&a,u=Object(i.a)(e);return r}var i=n(84),o=n(21),a=1;t.a=r},function(e,t,n){"use strict";function r(e,t,n){function r(){for(var o=arguments.length,f=Array(o),d=o,h=Object(u.a)(r);d--;)f[d]=arguments[d];var m=o<3&&f[0]!==h&&f[o-1]!==h?[]:Object(c.a)(f,h);if((o-=m.length)1?"& ":"")+t[r],t=t.join(n>2?", ":" "),e.replace(i,"{\n/* [wrapped with "+t+"] */\n")}var i=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/;t.a=r},function(e,t,n){"use strict";var r=n(463),i=n(237),o=Object(i.a)(r.a);t.a=o},function(e,t,n){"use strict";var r=n(464),i=n(465),o=n(63),a=i.a?function(e,t){return Object(i.a)(e,"toString",{configurable:!0,enumerable:!1,value:Object(r.a)(t),writable:!0})}:o.a;t.a=a},function(e,t,n){"use strict";function r(e){return function(){return e}}t.a=r},function(e,t,n){"use strict";var r=n(49),i=function(){try{var e=Object(r.a)(Object,"defineProperty");return e({},"",{}),e}catch(e){}}();t.a=i},function(e,t,n){"use strict";function r(e,t){return Object(i.a)(a,function(n){var r="_."+n[0];t&n[1]&&!Object(o.a)(e,r)&&e.push(r)}),e.sort()}var i=n(467),o=n(468),a=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]];t.a=r},function(e,t,n){"use strict";function r(e,t){for(var n=-1,r=null==e?0:e.length;++n-1}var i=n(239);t.a=r},function(e,t,n){"use strict";function r(e,t,n,r){for(var i=e.length,o=n+(r?1:-1);r?o--:++o-1:!!l&&Object(i.a)(e,t,n)>-1}var i=n(239),o=n(122),a=n(121),s=n(242),u=n(479),c=Math.max;t.a=r},function(e,t,n){"use strict";function r(e){return null==e?[]:Object(i.a)(e,Object(o.a)(e))}var i=n(480),o=n(481);t.a=r},function(e,t,n){"use strict";function r(e,t){return Object(i.a)(t,function(t){return e[t]})}var i=n(221);t.a=r},function(e,t,n){"use strict";function r(e){return Object(a.a)(e)?Object(i.a)(e):Object(o.a)(e)}var i=n(482),o=n(210),a=n(122);t.a=r},function(e,t,n){"use strict";function r(e,t){var n=Object(a.a)(e),r=!n&&Object(o.a)(e),l=!n&&!r&&Object(s.a)(e),f=!n&&!r&&!l&&Object(c.a)(e),d=n||r||l||f,h=d?Object(i.a)(e.length,String):[],m=h.length;for(var g in e)!t&&!p.call(e,g)||d&&("length"==g||l&&("offset"==g||"parent"==g)||f&&("buffer"==g||"byteLength"==g||"byteOffset"==g)||Object(u.a)(g,m))||h.push(g);return h}var i=n(483),o=n(215),a=n(47),s=n(217),u=n(241),c=n(218),l=Object.prototype,p=l.hasOwnProperty;t.a=r},function(e,t,n){"use strict";function r(e,t){for(var n=-1,r=Array(e);++n2&&void 0!==arguments[2]?arguments[2]:{};p()(Object(a.a)(e)||Object(s.a)(e),"Expected handlers to be a plain object.");var o=Object(h.a)(e,n),u=Object(d.a)(o).map(function(e){return Object(f.a)(e,i(e,o),t)}),l=c.a.apply(void 0,r(u));return function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:t,n=arguments[1];return l(e,n)}}t.a=o;var a=n(41),s=n(83),u=n(485),c=n.n(u),l=n(20),p=n.n(l),f=n(243),d=n(125),h=n(486)},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){for(var e=arguments.length,t=Array(e),n=0;n1&&void 0!==arguments[1]?arguments[1]:i.default.Map,n=Object.keys(e);return function(){var r=arguments.length>0&&void 0!==arguments[0]?arguments[0]:t(),i=arguments[1];return r.withMutations(function(t){n.forEach(function(n){var r=e[n],a=t.get(n),s=r(a,i);(0,o.validateNextState)(s,n,i),t.set(n,s)})})}},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.validateNextState=t.getUnexpectedInvocationParameterMessage=t.getStateName=void 0;var i=n(244),o=r(i),a=n(491),s=r(a),u=n(492),c=r(u);t.getStateName=o.default,t.getUnexpectedInvocationParameterMessage=s.default,t.validateNextState=c.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(14),o=r(i),a=n(244),s=r(a);t.default=function(e,t,n){var r=Object.keys(t);if(!r.length)return"Store does not have a valid reducer. Make sure the argument passed to combineReducers is an object whose values are reducers.";var i=(0,s.default)(n);if(o.default.isImmutable?!o.default.isImmutable(e):!o.default.Iterable.isIterable(e))return"The "+i+' is of unexpected type. Expected argument to be an instance of Immutable.Collection or Immutable.Record with the following properties: "'+r.join('", "')+'".';var a=e.toSeq().keySeq().toArray().filter(function(e){return!t.hasOwnProperty(e)});return a.length>0?"Unexpected "+(1===a.length?"property":"properties")+' "'+a.join('", "')+'" found in '+i+'. Expected to find one of the known reducer property names instead: "'+r.join('", "')+'". Unexpected properties will be ignored.':null},e.exports=t.default},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t,n){if(void 0===e)throw new Error('Reducer "'+t+'" returned undefined when handling "'+n.type+'" action. To ignore an action, you must explicitly return the previous state.')},e.exports=t.default},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t1&&void 0!==arguments[1]?arguments[1]:{withRef:!1};return n=t=function(t){function n(e){o(this,n);var t=a(this,(n.__proto__||Object.getPrototypeOf(n)).call(this,e));return t.handleStart=function(e){var n=t.props,r=n.distance,i=n.shouldCancelStart;if(2===e.button||i(e))return!1;t._touched=!0,t._pos=(0,C.getPosition)(e);var o=(0,C.closest)(e.target,function(e){return null!=e.sortableInfo});if(o&&o.sortableInfo&&t.nodeIsChild(o)&&!t.state.sorting){var a=t.props.useDragHandle,s=o.sortableInfo,u=s.index,c=s.collection;if(a&&!(0,C.closest)(e.target,function(e){return null!=e.sortableHandle}))return;t.manager.active={index:u,collection:c},(0,C.isTouchEvent)(e)||"a"!==e.target.tagName.toLowerCase()||e.preventDefault(),r||(0===t.props.pressDelay?t.handlePress(e):t.pressTimer=setTimeout(function(){return t.handlePress(e)},t.props.pressDelay))}},t.nodeIsChild=function(e){return e.sortableInfo.manager===t.manager},t.handleMove=function(e){var n=t.props,r=n.distance,i=n.pressThreshold;if(!t.state.sorting&&t._touched){var o=(0,C.getPosition)(e),a=t._delta={x:t._pos.x-o.x,y:t._pos.y-o.y},s=Math.abs(a.x)+Math.abs(a.y);r||i&&!(i&&s>=i)?r&&s>=r&&t.manager.isActive()&&t.handlePress(e):(clearTimeout(t.cancelTimer),t.cancelTimer=setTimeout(t.cancel,0))}},t.handleEnd=function(){var e=t.props.distance;t._touched=!1,e||t.cancel()},t.cancel=function(){t.state.sorting||(clearTimeout(t.pressTimer),t.manager.active=null)},t.handlePress=function(e){var n=t.manager.getActive();if(n){var r=t.props,o=r.axis,a=r.getHelperDimensions,s=r.helperClass,u=r.hideSortableGhost,c=r.onSortStart,l=r.useWindowAsScrollContainer,p=n.node,f=n.collection,d=p.sortableInfo.index,h=(0,C.getElementMargin)(p),m=t.container.getBoundingClientRect(),g=a({index:d,node:p,collection:f});t.node=p,t.margin=h,t.width=g.width,t.height=g.height,t.marginOffset={x:t.margin.left+t.margin.right,y:Math.max(t.margin.top,t.margin.bottom)},t.boundingClientRect=p.getBoundingClientRect(),t.containerBoundingRect=m,t.index=d,t.newIndex=d,t.axis={x:o.indexOf("x")>=0,y:o.indexOf("y")>=0},t.offsetEdge=(0,C.getEdgeOffset)(p,t.container),t.initialOffset=(0,C.getPosition)(e),t.initialScroll={top:t.container.scrollTop,left:t.container.scrollLeft},t.initialWindowScroll={top:window.pageYOffset,left:window.pageXOffset};var y=p.querySelectorAll("input, textarea, select"),v=p.cloneNode(!0);if([].concat(i(v.querySelectorAll("input, textarea, select"))).forEach(function(e,t){"file"!==e.type&&y[t]&&(e.value=y[t].value)}),t.helper=t.document.body.appendChild(v),t.helper.style.position="fixed",t.helper.style.top=t.boundingClientRect.top-h.top+"px",t.helper.style.left=t.boundingClientRect.left-h.left+"px",t.helper.style.width=t.width+"px",t.helper.style.height=t.height+"px",t.helper.style.boxSizing="border-box",t.helper.style.pointerEvents="none",u&&(t.sortableGhost=p,p.style.visibility="hidden",p.style.opacity=0),t.minTranslate={},t.maxTranslate={},t.axis.x&&(t.minTranslate.x=(l?0:m.left)-t.boundingClientRect.left-t.width/2,t.maxTranslate.x=(l?t.contentWindow.innerWidth:m.left+m.width)-t.boundingClientRect.left-t.width/2),t.axis.y&&(t.minTranslate.y=(l?0:m.top)-t.boundingClientRect.top-t.height/2,t.maxTranslate.y=(l?t.contentWindow.innerHeight:m.top+m.height)-t.boundingClientRect.top-t.height/2),s){var b;(b=t.helper.classList).add.apply(b,i(s.split(" ")))}t.listenerNode=e.touches?p:t.contentWindow,C.events.move.forEach(function(e){return t.listenerNode.addEventListener(e,t.handleSortMove,!1)}),C.events.end.forEach(function(e){return t.listenerNode.addEventListener(e,t.handleSortEnd,!1)}),t.setState({sorting:!0,sortingIndex:d}),c&&c({node:p,index:d,collection:f},e)}},t.handleSortMove=function(e){var n=t.props.onSortMove;e.preventDefault(),t.updatePosition(e),t.animateNodes(),t.autoscroll(),n&&n(e)},t.handleSortEnd=function(e){var n=t.props,r=n.hideSortableGhost,i=n.onSortEnd,o=t.manager.active.collection;t.listenerNode&&(C.events.move.forEach(function(e){return t.listenerNode.removeEventListener(e,t.handleSortMove)}),C.events.end.forEach(function(e){return t.listenerNode.removeEventListener(e,t.handleSortEnd)})),t.helper.parentNode.removeChild(t.helper),r&&t.sortableGhost&&(t.sortableGhost.style.visibility="",t.sortableGhost.style.opacity="");for(var a=t.manager.refs[o],s=0,u=a.length;s=t.maxTranslate.y-t.height/2?(n.y=1,r.y=i.y*Math.abs((t.maxTranslate.y-t.height/2-e.y)/t.height)):e.x>=t.maxTranslate.x-t.width/2?(n.x=1,r.x=i.x*Math.abs((t.maxTranslate.x-t.width/2-e.x)/t.width)):e.y<=t.minTranslate.y+t.height/2?(n.y=-1,r.y=i.y*Math.abs((e.y-t.height/2-t.minTranslate.y)/t.height)):e.x<=t.minTranslate.x+t.width/2&&(n.x=-1,r.x=i.x*Math.abs((e.x-t.width/2-t.minTranslate.x)/t.width)),t.autoscrollInterval&&(clearInterval(t.autoscrollInterval),t.autoscrollInterval=null,t.isAutoScrolling=!1),0===n.x&&0===n.y||(t.autoscrollInterval=setInterval(function(){t.isAutoScrolling=!0;var e={left:1*r.x*n.x,top:1*r.y*n.y};t.scrollContainer.scrollTop+=e.top,t.scrollContainer.scrollLeft+=e.left,t.translate.x+=e.left,t.translate.y+=e.top,t.animateNodes()},5))},t.manager=new x.default,t.events={start:t.handleStart,move:t.handleMove,end:t.handleEnd},(0,v.default)(!(e.distance&&e.pressDelay),"Attempted to set both `pressDelay` and `distance` on SortableContainer, you may only use one or the other, not both at the same time."),t.state={},t}return s(n,t),p(n,[{key:"getChildContext",value:function(){return{manager:this.manager}}},{key:"componentDidMount",value:function(){var e=this,t=this.props.useWindowAsScrollContainer,n=this.getContainer();Promise.resolve(n).then(function(n){e.container=n,e.document=e.container.ownerDocument||document;var r=e.props.contentWindow||e.document.defaultView||window;e.contentWindow="function"===typeof r?r():r,e.scrollContainer=t?e.document.scrollingElement||e.document.documentElement:e.container;for(var i in e.events)!function(t){e.events.hasOwnProperty(t)&&C.events[t].forEach(function(n){return e.container.addEventListener(n,e.events[t],!1)})}(i)})}},{key:"componentWillUnmount",value:function(){var e=this;if(this.container){for(var t in this.events)!function(t){e.events.hasOwnProperty(t)&&C.events[t].forEach(function(n){return e.container.removeEventListener(n,e.events[t])})}(t)}}},{key:"getLockPixelOffsets",value:function(){var e=this.width,t=this.height,n=this.props.lockOffset,r=Array.isArray(n)?n:[n,n];(0,v.default)(2===r.length,"lockOffset prop of SortableContainer should be a single value or an array of exactly two values. Given %s",n);var i=l(r,2),o=i[0],a=i[1];return[(0,C.getLockPixelOffset)({lockOffset:o,width:e,height:t}),(0,C.getLockPixelOffset)({lockOffset:a,width:e,height:t})]}},{key:"updatePosition",value:function(e){var t=this.props,n=t.lockAxis,r=t.lockToContainerEdges,i=(0,C.getPosition)(e),o={x:i.x-this.initialOffset.x,y:i.y-this.initialOffset.y};if(o.y-=window.pageYOffset-this.initialWindowScroll.top,o.x-=window.pageXOffset-this.initialWindowScroll.left,this.translate=o,r){var a=this.getLockPixelOffsets(),s=l(a,2),u=s[0],c=s[1],p={x:this.width/2-u.x,y:this.height/2-u.y},f={x:this.width/2-c.x,y:this.height/2-c.y};o.x=(0,C.limit)(this.minTranslate.x+p.x,this.maxTranslate.x-f.x,o.x),o.y=(0,C.limit)(this.minTranslate.y+p.y,this.maxTranslate.y-f.y,o.y)}"x"===n?o.y=0:"y"===n&&(o.x=0),this.helper.style[C.vendorPrefix+"Transform"]="translate3d("+o.x+"px,"+o.y+"px, 0)"}},{key:"animateNodes",value:function(){var e=this.props,t=e.transitionDuration,n=e.hideSortableGhost,r=e.onSortOver,i=this.manager.getOrderedRefs(),o={left:this.container.scrollLeft-this.initialScroll.left,top:this.container.scrollTop-this.initialScroll.top},a={left:this.offsetEdge.left+this.translate.x+o.left,top:this.offsetEdge.top+this.translate.y+o.top},s={top:window.pageYOffset-this.initialWindowScroll.top,left:window.pageXOffset-this.initialWindowScroll.left},u=this.newIndex;this.newIndex=null;for(var c=0,l=i.length;cd?d/2:this.width/2,height:this.height>h?h/2:this.height/2},g={x:0,y:0},y=i[c].edgeOffset;y||(i[c].edgeOffset=y=(0,C.getEdgeOffset)(p,this.container));var v=c0&&i[c-1];v&&!v.edgeOffset&&(v.edgeOffset=(0,C.getEdgeOffset)(v.node,this.container)),f!==this.index?(t&&(p.style[C.vendorPrefix+"TransitionDuration"]=t+"ms"),this.axis.x?this.axis.y?fthis.containerBoundingRect.width-m.width&&(g.x=v.edgeOffset.left-y.left,g.y=v.edgeOffset.top-y.top),null===this.newIndex&&(this.newIndex=f)):f>this.index&&(a.left+s.left+m.width>=y.left&&a.top+s.top+m.height>=y.top||a.top+s.top+m.height>=y.top+h)&&(g.x=-(this.width+this.marginOffset.x),y.left+g.xthis.index&&a.left+s.left+m.width>=y.left?(g.x=-(this.width+this.marginOffset.x),this.newIndex=f):fthis.index&&a.top+s.top+m.height>=y.top?(g.y=-(this.height+this.marginOffset.y),this.newIndex=f):f0&&void 0!==arguments[0]?arguments[0]:this.active.collection;return this.refs[e].sort(i)}}]),e}();t.default=a},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t}function a(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(e){var t,n,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{withRef:!1};return n=t=function(t){function n(){return i(this,n),o(this,(n.__proto__||Object.getPrototypeOf(n)).apply(this,arguments))}return a(n,t),c(n,[{key:"componentDidMount",value:function(){var e=this.props,t=e.collection,n=e.disabled,r=e.index;n||this.setDraggable(t,r)}},{key:"componentWillReceiveProps",value:function(e){if(this.props.index!==e.index&&this.node&&(this.node.sortableInfo.index=e.index),this.props.disabled!==e.disabled){var t=e.collection,n=e.disabled,r=e.index;n?this.removeDraggable(t):this.setDraggable(t,r)}else this.props.collection!==e.collection&&(this.removeDraggable(this.props.collection),this.setDraggable(e.collection,e.index))}},{key:"componentWillUnmount",value:function(){var e=this.props,t=e.collection;e.disabled||this.removeDraggable(t)}},{key:"setDraggable",value:function(e,t){var n=this.node=(0,h.findDOMNode)(this);n.sortableInfo={index:t,collection:e,manager:this.context.manager},this.ref={node:n},this.context.manager.add(e,this.ref)}},{key:"removeDraggable",value:function(e){this.context.manager.remove(e,this.ref)}},{key:"getWrappedInstance",value:function(){return(0,g.default)(r.withRef,"To access the wrapped instance, you need to pass in {withRef: true} as the second argument of the SortableElement() call"),this.refs.wrappedInstance}},{key:"render",value:function(){var t=r.withRef?"wrappedInstance":null;return p.default.createElement(e,u({ref:t},(0,y.omit)(this.props,"collection","disabled","index")))}}]),n}(l.Component),t.displayName=(0,y.provideDisplayName)("sortableElement",e),t.contextTypes={manager:d.default.object.isRequired},t.propTypes={index:d.default.number.isRequired,collection:d.default.oneOfType([d.default.number,d.default.string]),disabled:d.default.bool},t.defaultProps={collection:0},n}Object.defineProperty(t,"__esModule",{value:!0});var u=Object.assign||function(e){for(var t=1;t1&&void 0!==arguments[1]?arguments[1]:{withRef:!1};return n=t=function(t){function n(){return i(this,n),o(this,(n.__proto__||Object.getPrototypeOf(n)).apply(this,arguments))}return a(n,t),c(n,[{key:"componentDidMount",value:function(){(0,f.findDOMNode)(this).sortableHandle=!0}},{key:"getWrappedInstance",value:function(){return(0,h.default)(r.withRef,"To access the wrapped instance, you need to pass in {withRef: true} as the second argument of the SortableHandle() call"),this.refs.wrappedInstance}},{key:"render",value:function(){var t=r.withRef?"wrappedInstance":null;return p.default.createElement(e,u({ref:t},this.props))}}]),n}(l.Component),t.displayName=(0,m.provideDisplayName)("sortableHandle",e),n}Object.defineProperty(t,"__esModule",{value:!0});var u=Object.assign||function(e){for(var t=1;t0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]0||!o.data))throw new Error(JSON.stringify(o,null,2));if(!o)throw new s.NoSchemaError(i);var a=t.getSchema(o.data),u=o.extensions&&Boolean(o.extensions.tracing)||!1,c={schema:a,tracingSupported:u};t.sessionCache.set(t.hash(e),c),r(c),t.fetching=t.fetching.remove(n);var l=t.subscriptions.get(n);l&&l(c.schema)},error:function(n){o(n),t.fetching=t.fetching.remove(t.hash(e))}})})},e}();t.SchemaFetcher=d},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(t,"__esModule",{value:!0});var i=function(e){function t(t){return e.call(this,"Schema could not be fetched.\nPlease check if the endpoint '"+t+"' is a valid GraphQL Endpoint.")||this}return r(t,e),t}(Error);t.NoSchemaError=i},function(e,t,n){"pseudomap"===Object({NODE_ENV:"production",PUBLIC_URL:""}).npm_package_name&&"test"===Object({NODE_ENV:"production",PUBLIC_URL:""}).npm_lifecycle_script&&(Object({NODE_ENV:"production",PUBLIC_URL:""}).TEST_PSEUDOMAP="true"),"function"!==typeof Map||Object({NODE_ENV:"production",PUBLIC_URL:""}).TEST_PSEUDOMAP?e.exports=n(504):e.exports=Map},function(e,t){function n(e){if(!(this instanceof n))throw new TypeError("Constructor PseudoMap requires 'new'");if(this.clear(),e)if(e instanceof n||"function"===typeof Map&&e instanceof Map)e.forEach(function(e,t){this.set(t,e)},this);else{if(!Array.isArray(e))throw new TypeError("invalid argument");e.forEach(function(e){this.set(e[0],e[1])},this)}}function r(e,t){return e===t||e!==e&&t!==t}function i(e,t,n){this.key=e,this.value=t,this._index=n}function o(e,t){for(var n=0,i="_"+t,o=i;s.call(e,o);o=i+n++)if(r(e[o].key,t))return e[o]}function a(e,t,n){for(var o=0,a="_"+t,u=a;s.call(e,u);u=a+o++)if(r(e[u].key,t))return void(e[u].value=n);e.size++,e[u]=new i(t,n,u)}var s=Object.prototype.hasOwnProperty;e.exports=n,n.prototype.forEach=function(e,t){t=t||this,Object.keys(this._data).forEach(function(n){"size"!==n&&e.call(t,this._data[n].value,this._data[n].key)},this)},n.prototype.has=function(e){return!!o(this._data,e)},n.prototype.get=function(e){var t=o(this._data,e);return t&&t.value},n.prototype.set=function(e,t){a(this._data,e,t)},n.prototype.delete=function(e){var t=o(this._data,e);t&&(delete this._data[t._index],this._data.size--)},n.prototype.clear=function(){var e=Object.create(null);e.size=0,Object.defineProperty(this,"_data",{value:e,enumerable:!1,configurable:!0,writable:!1})},Object.defineProperty(n.prototype,"size",{get:function(){return this._data.size},set:function(e){},enumerable:!0,configurable:!0}),n.prototype.values=n.prototype.keys=n.prototype.entries=function(){throw new Error("iterators are not implemented in this version")}},function(e,t){e.exports=function(e){return e&&"object"===typeof e&&"function"===typeof e.copy&&"function"===typeof e.fill&&"function"===typeof e.readUInt8}},function(e,t){"function"===typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t){function n(e){var t=this;if(t instanceof n||(t=new n),t.tail=null,t.head=null,t.length=0,e&&"function"===typeof e.forEach)e.forEach(function(e){t.push(e)});else if(arguments.length>0)for(var r=0,i=arguments.length;r1)n=t;else{if(!this.head)throw new TypeError("Reduce of empty list with no initial value");r=this.head.next,n=this.head.value}for(var i=0;null!==r;i++)n=e(n,r.value,i),r=r.next;return n},n.prototype.reduceReverse=function(e,t){var n,r=this.tail;if(arguments.length>1)n=t;else{if(!this.tail)throw new TypeError("Reduce of empty list with no initial value");r=this.tail.prev,n=this.tail.value}for(var i=this.length-1;null!==r;i--)n=e(n,r.value,i),r=r.prev;return n},n.prototype.toArray=function(){for(var e=new Array(this.length),t=0,n=this.head;null!==n;t++)e[t]=n.value,n=n.next;return e},n.prototype.toArrayReverse=function(){for(var e=new Array(this.length),t=0,n=this.tail;null!==n;t++)e[t]=n.value,n=n.prev;return e},n.prototype.slice=function(e,t){t=t||this.length,t<0&&(t+=this.length),(e=e||0)<0&&(e+=this.length);var r=new n;if(tthis.length&&(t=this.length);for(var i=0,o=this.head;null!==o&&ithis.length&&(t=this.length);for(var i=this.length,o=this.tail;null!==o&&i>t;i--)o=o.prev;for(;null!==o&&i>e;i--,o=o.prev)r.push(o.value);return r},n.prototype.reverse=function(){for(var e=this.head,t=this.tail,n=e;null!==n;n=n.prev){var r=n.prev;n.prev=n.next,n.next=r}return this.head=t,this.tail=e,this}},function(module,exports,__webpack_require__){(function(global){!function(e,t){module.exports=t()}(0,function(){"use strict";function unwrapExports(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function createCommonjsModule(e,t){return t={exports:{}},e(t,t.exports),t.exports}function _typeof(e){return(_typeof="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _inherits(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&_setPrototypeOf(e,t)}function _getPrototypeOf(e){return(_getPrototypeOf=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function _setPrototypeOf(e,t){return(_setPrototypeOf=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function isNativeReflectConstruct(){if("undefined"===typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"===typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(e){return!1}}function _construct(e,t,n){return _construct=isNativeReflectConstruct()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var i=Function.bind.apply(e,r),o=new i;return n&&_setPrototypeOf(o,n.prototype),o},_construct.apply(null,arguments)}function _wrapNativeSuper(e){var t="function"===typeof Map?new Map:void 0;return(_wrapNativeSuper=function(e){function n(){return _construct(e,arguments,_getPrototypeOf(this).constructor)}if(null===e)return null;if("function"!==typeof e)throw new TypeError("Super expression must either be null or a function");if("undefined"!==typeof t){if(t.has(e))return t.get(e);t.set(e,n)}return n.prototype=Object.create(e.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),_setPrototypeOf(n,e)})(e)}function _assertThisInitialized(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function _possibleConstructorReturn(e,t){return!t||"object"!==typeof t&&"function"!==typeof t?_assertThisInitialized(e):t}function _taggedTemplateLiteral(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_nonIterableRest()}function _arrayWithHoles(e){if(Array.isArray(e))return e}function _iterableToArrayLimit(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var a,s=e[Symbol.iterator]();!(r=(a=s.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{r||null==s.return||s.return()}finally{if(i)throw o}}return n}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function defaultSetTimout(){throw new Error("setTimeout has not been defined")}function defaultClearTimeout(){throw new Error("clearTimeout has not been defined")}function runTimeout(e){if(cachedSetTimeout===setTimeout)return setTimeout(e,0);if((cachedSetTimeout===defaultSetTimout||!cachedSetTimeout)&&setTimeout)return cachedSetTimeout=setTimeout,setTimeout(e,0);try{return cachedSetTimeout(e,0)}catch(t){try{return cachedSetTimeout.call(null,e,0)}catch(t){return cachedSetTimeout.call(this,e,0)}}}function runClearTimeout(e){if(cachedClearTimeout===clearTimeout)return clearTimeout(e);if((cachedClearTimeout===defaultClearTimeout||!cachedClearTimeout)&&clearTimeout)return cachedClearTimeout=clearTimeout,clearTimeout(e);try{return cachedClearTimeout(e)}catch(t){try{return cachedClearTimeout.call(null,e)}catch(t){return cachedClearTimeout.call(this,e)}}}function cleanUpNextTick(){draining&¤tQueue&&(draining=!1,currentQueue.length?queue=currentQueue.concat(queue):queueIndex=-1,queue.length&&drainQueue())}function drainQueue(){if(!draining){var e=runTimeout(cleanUpNextTick);draining=!0;for(var t=queue.length;t;){for(currentQueue=queue,queue=[];++queueIndex1)for(var n=1;n=0&&e!==1/0))throw new Error("Expected an integer")}function validateChoiceOption(e,t){if(!t.some(function(t){return t.value===e})){var n=t.filter(function(e){return!e.deprecated}).map(function(e){return JSON.stringify(e.value)}).sort(),r=n.slice(0,-2),i=n.slice(-2);throw new Error("Expected ".concat(r.concat(i.join(" or ")).join(", ")))}}function normalizeOptions$1(e,t,n){n=n||{};var r=!1===n.logger?{warn:function(){}}:void 0!==n.logger?n.logger:console,i=n.descriptor||optionsDescriptor.apiDescriptor,o=n.passThrough||[],a=t.reduce(function(e,t){return Object.assign(e,_defineProperty({},t.name,t))},{});return Object.keys(e).reduce(function(n,s){var u=a[s],c=s,l=e[s];if(!u)return!0===o||-1!==o.indexOf(c)?n[c]=l:r.warn(createUnknownOptionMessage(c,l,t,i)),n;if(u.deprecated?"string"===typeof u.redirect?(r.warn(createRedirectOptionMessage(u,i)),c=u.redirect):l&&(r.warn(createRedirectOptionMessage(u,i)),l=u.redirect.value,c=u.redirect.option):l=normalizeOption(l,u),u.choices){var p=u.choices.find(function(e){return e.value===l});p&&p.deprecated&&(r.warn(createRedirectChoiceMessage(u,p,i)),l=p.redirect)}return u.array&&!Array.isArray(l)&&(l=[l]),l!==u.default&&optionsValidator.validateOption(l,a[c],{descriptor:i}),n[c]=l,n},{})}function normalizeOption(e,t){return"int"===t.type?Number(e):e}function createUnknownOptionMessage(e,t,n,r){var i=["Ignored unknown option ".concat(r(e,t),".")],o=n.find(function(t){return leven(t.name,e)<3});return o&&i.push("Did you mean ".concat(JSON.stringify(o.name),"?")),i.join(" ")}function createRedirectOptionMessage(e,t){return"".concat(t(e.name)," is deprecated. Prettier now treats it as ").concat("string"===typeof e.redirect?t(e.redirect):t(e.redirect.option,e.redirect.value),".")}function createRedirectChoiceMessage(e,t,n){return"".concat(n(e.name,t.value)," is deprecated. Prettier now treats it as ").concat(n(e.name,t.redirect),".")}function normalizeApiOptions(e,t,n){return normalizeOptions$1(e,t,Object.assign({descriptor:optionsDescriptor.apiDescriptor},n))}function normalizeCliOptions(e,t,n){var r=e._||[],i=normalizeOptions$1(Object.keys(e).reduce(function(t,n){return Object.assign(t,1===n.length?null:_defineProperty({},n,e[n]))},{}),t,Object.assign({descriptor:optionsDescriptor.cliDescriptor},n));return i._=r,i}function locStart$1(e){return e.declaration&&e.declaration.decorators&&e.declaration.decorators.length>0?locStart$1(e.declaration.decorators[0]):e.decorators&&e.decorators.length>0?locStart$1(e.decorators[0]):e.__location?e.__location.startOffset:e.range?e.range[0]:"number"===typeof e.start?e.start:e.loc?e.loc.start:null}function locEnd$1(e){var t=e.nodes&&getLast(e.nodes);if(t&&e.source&&!e.source.end&&(e=t),e.__location)return e.__location.endOffset;var n=e.range?e.range[1]:"number"===typeof e.end?e.end:null;return e.typeAnnotation?Math.max(n,locEnd$1(e.typeAnnotation)):e.loc&&!n?e.loc.end:n}function buildGraph(){for(var e={},t=models$1.length,n=0;n1&&(t=Array.prototype.slice.call(arguments)),e(t))};return"conversion"in e&&(t.conversion=e.conversion),t}function wrapRounded(e){var t=function(t){if(void 0===t||null===t)return t;arguments.length>1&&(t=Array.prototype.slice.call(arguments));var n=e(t);if("object"===_typeof(n))for(var r=n.length,i=0;i-1||e.filenames&&e.filenames.find(function(e){return e.toLowerCase()===r}))});return i&&i.parsers[0]}function massageAST(e,t,n){if(Array.isArray(e))return e.map(function(e){return massageAST(e,t,n)}).filter(function(e){return e});if(!e||"object"!==_typeof(e))return e;for(var r={},i=Object.keys(e),o=0;o0){for(var i=0;i1?e[e.length-2]:null}function getLast$3(e){return e.length>0?e[e.length-1]:null}function skip(e){return function(t,n,r){var i=r&&r.backwards;if(!1===n)return!1;for(var o=t.length,a=n;a>=0&&a(r.match(s.regex)||[]).length}else c=!0;var l="json"===t.parser?i.quote:u?s.quote:a.quote;return n?c?l+r+l:e:makeString(r,l,!("css"===t.parser||"less"===t.parser||"scss"===t.parser))}function makeString(e,t,n){var r='"'===t?"'":'"',i=/\\([\s\S])|(['"])/g,o=e.replace(i,function(e,i,o){return i===r?i:o===t?"\\"+o:o||(n&&/^[^\\nrvtbfux\r\n\u2028\u2029"'0-7]$/.test(i)?i:"\\"+i)});return t+o+t}function printNumber(e){return e.toLowerCase().replace(/^([+-]?[\d.]+e)(?:\+|(-))?0*(\d)/,"$1$2$3").replace(/^([+-]?[\d.]+)e[+-]?0+$/,"$1").replace(/^([+-])?\./,"$10.").replace(/(\.\d+?)0+(?=e|$)/,"$1").replace(/\.(?=e|$)/,"")}function getMaxContinuousCount(e,t){var n=e.match(new RegExp("(".concat(escapeStringRegexp(t),")+"),"g"));return null===n?0:n.reduce(function(e,n){return Math.max(e,n.length/t.length)},0)}function splitText(e,t){function n(e){var t=getLast$3(a);t&&"word"===t.type&&(t.kind===r&&e.kind===i&&!t.hasTrailingPunctuation||t.kind===i&&e.kind===r&&!e.hasLeadingPunctuation?a.push({type:"whitespace",value:" "}):function(n,r){return t.kind===n&&e.kind===r||t.kind===r&&e.kind===n}(r,o)||[t.value,e.value].some(function(e){return/\u3000/.test(e)})||a.push({type:"whitespace",value:""})),a.push(e)}var r="non-cjk",i="cjk-character",o="cjk-punctuation",a=[];return("preserve"===t.proseWrap?e:e.replace(new RegExp("(".concat(cjkPattern,")\n(").concat(cjkPattern,")"),"g"),"$1$2")).split(/([ \t\n]+)/).forEach(function(e,t,s){if(t%2===1)return void a.push({type:"whitespace",value:/\n/.test(e)?"\n":" "});(0!==t&&t!==s.length-1||""!==e)&&e.split(new RegExp("(".concat(cjkPattern,")"))).forEach(function(e,t,a){if(0!==t&&t!==a.length-1||""!==e)return t%2===0?void(""!==e&&n({type:"word",value:e,kind:r,hasLeadingPunctuation:punctuationRegex.test(e[0]),hasTrailingPunctuation:punctuationRegex.test(getLast$3(e))})):void n(punctuationRegex.test(e)?{type:"word",value:e,kind:o,hasLeadingPunctuation:!0,hasTrailingPunctuation:!0}:{type:"word",value:e,kind:i,hasLeadingPunctuation:!1,hasTrailingPunctuation:!1})})}),a}function getStringWidth(e){return e?stringWidth(e.replace(emojiRegex," ")):0}function hasIgnoreComment(e){return hasNodeIgnoreComment(e.getValue())}function hasNodeIgnoreComment(e){return e&&e.comments&&e.comments.length>0&&e.comments.some(function(e){return"prettier-ignore"===e.value.trim()})}function addCommentHelper(e,t){(e.comments||(e.comments=[])).push(t),t.printed=!1,"JSXText"===e.type&&(t.printed=!0)}function addLeadingComment$1(e,t){t.leading=!0,t.trailing=!1,addCommentHelper(e,t)}function addDanglingComment$1(e,t){t.leading=!1,t.trailing=!1,addCommentHelper(e,t)}function addTrailingComment$1(e,t){t.leading=!1,t.trailing=!0,addCommentHelper(e,t)}function rootIndent(){return{value:"",length:0,queue:[]}}function makeIndent(e,t){return generateInd(e,{type:"indent"},t)}function makeAlign(e,t,n){return t===-1/0?e.root||rootIndent():t<0?generateInd(e,{type:"dedent"},n):t?"root"===t.type?Object.assign({},e,{root:e}):"string"===typeof t?generateInd(e,{type:"stringAlign",n:t},n):generateInd(e,{type:"numberAlign",n:t},n):e}function generateInd(e,t,n){function r(e){l+="\t".repeat(e),p+=n.tabWidth*e}function i(e){l+=" ".repeat(e),p+=e}function o(){n.useTabs?a():s()}function a(){f>0&&r(f),u()}function s(){d>0&&i(d),u()}function u(){f=0,d=0}var c="dedent"===t.type?e.queue.slice(0,-1):e.queue.concat(t),l="",p=0,f=0,d=0,h=!0,m=!1,g=void 0;try{for(var y,v=c[Symbol.iterator]();!(h=(y=v.next()).done);h=!0){var b=y.value;switch(b.type){case"indent":o(),n.useTabs?r(1):i(n.tabWidth);break;case"stringAlign":o(),l+=b.n,p+=b.n.length;break;case"numberAlign":f+=1,d+=b.n;break;default:throw new Error("Unexpected type '".concat(b.type,"'"))}}}catch(e){m=!0,g=e}finally{try{h||null==v.return||v.return()}finally{if(m)throw g}}return s(),Object.assign({},e,{value:l,length:p,queue:c})}function fits(e,t,n,r,i){for(var o=t.length,a=[e];n>=0;)if(0!==a.length){var s=a.pop(),u=s[0],c=s[1],l=s[2];if("string"===typeof l)n-=util.getStringWidth(l);else switch(l.type){case"concat":for(var p=l.parts.length-1;p>=0;p--)a.push([u,c,l.parts[p]]);break;case"indent":a.push([makeIndent(u,r),c,l.contents]);break;case"align":a.push([makeAlign(u,l.n,r),c,l.contents]);break;case"group":if(i&&l.break)return!1;a.push([u,l.break?MODE_BREAK:c,l.contents]);break;case"fill":for(var f=l.parts.length-1;f>=0;f--)a.push([u,c,l.parts[f]]);break;case"if-break":c===MODE_BREAK&&l.breakContents&&a.push([u,c,l.breakContents]),c===MODE_FLAT&&l.flatContents&&a.push([u,c,l.flatContents]);break;case"line":switch(c){case MODE_FLAT:if(!l.hard){l.soft||(n-=1);break}return!0;case MODE_BREAK:return!0}}}else{if(0===o)return!0;a.push(t[o-1]),o--}return!1}function printDocToString(e,t){for(var n=t.printWidth,r=t.newLine||"\n",i=0,o=[[rootIndent(),MODE_BREAK,e]],a=[],s=!1,u=[];0!==o.length;){var c=o.pop(),l=c[0],p=c[1],f=c[2];if("string"===typeof f)a.push(f),i+=util.getStringWidth(f);else switch(f.type){case"cursor":a.push(cursor$2.placeholder);break;case"concat":for(var d=f.parts.length-1;d>=0;d--)o.push([l,p,f.parts[d]]);break;case"indent":o.push([makeIndent(l,t),p,f.contents]);break;case"align":o.push([makeAlign(l,f.n,t),p,f.contents]);break;case"group":switch(p){case MODE_FLAT:if(!s){o.push([l,f.break?MODE_BREAK:MODE_FLAT,f.contents]);break}case MODE_BREAK:s=!1;var h=[l,MODE_FLAT,f.contents],m=n-i;if(!f.break&&fits(h,o,m,t))o.push(h);else if(f.expandedStates){var g=f.expandedStates[f.expandedStates.length-1];if(f.break){o.push([l,MODE_BREAK,g]);break}for(var y=1;y=f.expandedStates.length){o.push([l,MODE_BREAK,g]);break}var v=f.expandedStates[y],b=[l,MODE_FLAT,v];if(fits(b,o,m,t)){o.push(b);break}}}else o.push([l,MODE_BREAK,f.contents])}break;case"fill":var x=n-i,C=f.parts;if(0===C.length)break;var E=C[0],D=[l,MODE_FLAT,E],w=[l,MODE_BREAK,E],S=fits(D,[],x,t,!0);if(1===C.length){S?o.push(D):o.push(w);break}var k=C[1],A=[l,MODE_FLAT,k],_=[l,MODE_BREAK,k];if(2===C.length){S?(o.push(A),o.push(D)):(o.push(_),o.push(w));break}C.splice(0,2);var T=[l,p,fill$1(C)],O=C[0];fits([l,MODE_FLAT,concat$2([E,k,O])],[],x,t,!0)?(o.push(T),o.push(A),o.push(D)):S?(o.push(T),o.push(_),o.push(D)):(o.push(T),o.push(_),o.push(w));break;case"if-break":p===MODE_BREAK&&f.breakContents&&o.push([l,p,f.breakContents]),p===MODE_FLAT&&f.flatContents&&o.push([l,p,f.flatContents]);break;case"line-suffix":u.push([l,p,f.contents]);break;case"line-suffix-boundary":u.length>0&&o.push([l,p,{type:"line",hard:!0}]);break;case"line":switch(p){case MODE_FLAT:if(!f.hard){f.soft||(a.push(" "),i+=1);break}s=!0;case MODE_BREAK:if(u.length){o.push([l,p,f]),[].push.apply(o,u.reverse()),u=[];break}if(f.literal)l.root?(a.push(r,l.root.value),i=l.root.length):(a.push(r),i=0);else{if(a.length>0){for(;a.length>0&&"string"===typeof a[a.length-1]&&a[a.length-1].match(/^[^\S\n]*$/);)a.pop();!a.length||"string"!==typeof a[a.length-1]||"markdown"===t.parser&&/\S {2}$/.test(a[a.length-1])||(a[a.length-1]=a[a.length-1].replace(/[^\S\n]*$/,""))}a.push(r+l.value),i=l.length}}}}var F=a.indexOf(cursor$2.placeholder);if(-1!==F){var N=a.indexOf(cursor$2.placeholder,F+1),I=a.slice(0,F).join(""),L=a.slice(F+1,N).join("");return{formatted:I+L+a.slice(N+1).join(""),cursorNodeStart:I.length,cursorNodeText:L}}return{formatted:a.join("")}}function traverseDoc(e,t,n,r){function i(e){var o=!0;if(t&&!1===t(e)&&(o=!1),o)if("concat"===e.type||"fill"===e.type)for(var a=0;a0){var t=e[e.length-1];t.expandedStates||(t.break=!0)}return null}function propagateBreaks(e){var t=new Map,n=[];traverseDoc(e,function(e){if("break-parent"===e.type&&breakParentGroup(n),"group"===e.type){if(n.push(e),t.has(e))return!1;t.set(e,!0)}},function(e){if("group"===e.type){n.pop().break&&breakParentGroup(n)}},!0)}function removeLines(e){return mapDoc(e,function(e){return"line"!==e.type||e.hard?"if-break"===e.type?e.flatContents||"":e:e.soft?"":" "})}function stripTrailingHardline(e){return"concat"===e.type&&2===e.parts.length&&"concat"===e.parts[1].type&&2===e.parts[1].parts.length&&e.parts[1].parts[0].hard&&"break-parent"===e.parts[1].parts[1].type?e.parts[0]:e}function flattenDoc(e){if("concat"===e.type){for(var t=[],n=0;n=0&&!(i(n[a])<=i(e)&&o(n[a])<=o(e));--a);return void n.splice(a+1,0,e)}}else if(e[childNodesCacheKey])return e[childNodesCacheKey];var s;if(r.getCommentChildNodes?s=r.getCommentChildNodes(e):e&&"object"===_typeof(e)&&(s=Object.keys(e).filter(function(e){return"enclosingNode"!==e&&"precedingNode"!==e&&"followingNode"!==e}).map(function(t){return e[t]})),s)return n||Object.defineProperty(e,childNodesCacheKey,{value:n=[],enumerable:!1}),s.forEach(function(e){getSortedChildNodes(e,t,n)}),n}}function decorateComment(e,t,n){for(var r,i,o=n.locStart,a=n.locEnd,s=getSortedChildNodes(e,n),u=0,c=s.length;u>1,p=s[l];if(o(p)-o(t)<=0&&a(t)-a(p)<=0)return t.enclosingNode=p,void decorateComment(p,t,n);if(a(p)-o(t)<=0)r=p,u=l+1;else{if(!(a(t)-o(p)<=0))throw new Error("Comment location overlaps with node location");i=p,c=l}}if(t.enclosingNode&&"TemplateLiteral"===t.enclosingNode.type){var f=t.enclosingNode.quasis,d=findExpressionIndexForComment(f,t,n);r&&findExpressionIndexForComment(f,r,n)!==d&&(r=null),i&&findExpressionIndexForComment(f,i,n)!==d&&(i=null)}r&&(t.precedingNode=r),i&&(t.followingNode=i)}function attach(e,t,n,r){if(Array.isArray(e)){var i=[],o=r.locStart,a=r.locEnd;e.forEach(function(s,u){if(("json"===r.parser||"json5"===r.parser)&&o(s)-o(t)<=0)return void addLeadingComment(t,s);decorateComment(t,s,r);var c=s.precedingNode,l=s.enclosingNode,p=s.followingNode,f=r.printer.handleComments&&r.printer.handleComments.ownLine?r.printer.handleComments.ownLine:function(){return!1},d=r.printer.handleComments&&r.printer.handleComments.endOfLine?r.printer.handleComments.endOfLine:function(){return!1},h=r.printer.handleComments&&r.printer.handleComments.remaining?r.printer.handleComments.remaining:function(){return!1},m=e.length-1===u;if(hasNewline(n,o(s),{backwards:!0}))f(s,n,r,t,m)||(p?addLeadingComment(p,s):c?addTrailingComment(c,s):l?addDanglingComment(l,s):addDanglingComment(t,s));else if(hasNewline(n,a(s)))d(s,n,r,t,m)||(c?addTrailingComment(c,s):p?addLeadingComment(p,s):l?addDanglingComment(l,s):addDanglingComment(t,s));else if(h(s,n,r,t,m));else if(c&&p){var g=i.length;if(g>0){var y=i[g-1];y.followingNode!==s.followingNode&&breakTies(i,n,r)}i.push(s)}else c?addTrailingComment(c,s):p?addLeadingComment(p,s):l?addDanglingComment(l,s):addDanglingComment(t,s)}),breakTies(i,n,r),e.forEach(function(e){delete e.precedingNode,delete e.enclosingNode,delete e.followingNode})}}function breakTies(e,t,n){var r=e.length;if(0!==r){var i,o=e[0].precedingNode,a=e[0].followingNode,s=n.locStart(a);for(i=r;i>0;--i){var u=e[i-1];assert.strictEqual(u.precedingNode,o),assert.strictEqual(u.followingNode,a);var c=t.slice(n.locEnd(u),s).trim();if(""!==c&&!/^\(+$/.test(c))break;s=n.locStart(u)}e.forEach(function(e,t){t=0;r-=2){var i=n[r];if(i&&!Array.isArray(i)&&--t<0)return i}return null}function printSubtree(e,t,n,r){if(n.printer.embed)return n.printer.embed(e,t,function(e,t){return textToDoc(e,t,n,r)},n)}function textToDoc(e,t,n,r){var i=normalize$1(Object.assign({},n,t,{parentParser:n.parser,originalText:e}),{passThrough:!0}),o=parser.parse(e,i),a=o.ast;e=o.text;var s=a.comments;return delete a.comments,comments.attach(s,a,e,i),r(a,i)}function printAstToDoc(e,t,n){function r(e,n){var a=e.getValue(),s=a&&"object"===_typeof(a)&&void 0===n;if(s&&o.has(a))return o.get(a);var u;return u=i.willPrintOwnComments&&i.willPrintOwnComments(e)?genericPrint(e,t,r,n):comments.printComments(e,function(e){return genericPrint(e,t,r,n)},t,n&&n.needsSemi),s&&o.set(a,u),u}n=n||0;var i=t.printer,o=new Map,a=r(new fastPath(e));return n>0&&(a=addAlignmentToDoc$1(docUtils$2.removeLines(concat$3([hardline$2,a])),n,t.tabWidth)),docUtils$2.propagateBreaks(a),"json"!==t.parser&&"json5"!==t.parser&&"json-stringify"!==t.parser||(a=concat$3([a,hardline$2])),a}function genericPrint(e,t,n,r){assert.ok(e instanceof fastPath);var i=e.getValue(),o=t.printer;if(o.hasPrettierIgnore&&o.hasPrettierIgnore(e))return t.originalText.slice(t.locStart(i),t.locEnd(i));if(i)try{var a=multiparser.printSubtree(e,n,t,printAstToDoc);if(a)return a}catch(e){if(commonjsGlobal.PRETTIER_DEBUG)throw e}return o.print(e,t,n,r)}function findSiblingAncestors(e,t,n){var r=e.node,i=t.node;if(r===i)return{startNode:r,endNode:i};var o=!0,a=!1,s=void 0;try{for(var u,c=t.parentNodes[Symbol.iterator]();!(o=(u=c.next()).done);o=!0){var l=u.value;if(!("Program"!==l.type&&"File"!==l.type&&n.locStart(l)>=n.locStart(e.node)))break;i=l}}catch(e){a=!0,s=e}finally{try{o||null==c.return||c.return()}finally{if(a)throw s}}var p=!0,f=!1,d=void 0;try{for(var h,m=e.parentNodes[Symbol.iterator]();!(p=(h=m.next()).done);p=!0){var g=h.value;if(!("Program"!==g.type&&"File"!==g.type&&n.locEnd(g)<=n.locEnd(t.node)))break;r=g}}catch(e){f=!0,d=e}finally{try{p||null==m.return||m.return()}finally{if(f)throw d}}return{startNode:r,endNode:i}}function findNodeAtOffset(e,t,n,r,i){r=r||function(){return!0},i=i||[];var o=n.locStart(e,n.locStart),a=n.locEnd(e,n.locEnd);if(o<=t&&t<=a){var s=!0,u=!1,c=void 0;try{for(var l,p=comments.getSortedChildNodes(e,n)[Symbol.iterator]();!(s=(l=p.next()).done);s=!0){var f=l.value,d=findNodeAtOffset(f,t,n,r,[e].concat(i));if(d)return d}}catch(e){u=!0,c=e}finally{try{s||null==p.return||p.return()}finally{if(u)throw c}}if(r(e))return{node:e,parentNodes:i}}}function isSourceElement(e,t){if(null==t)return!1;var n=["FunctionDeclaration","BlockStatement","BreakStatement","ContinueStatement","DebuggerStatement","DoWhileStatement","EmptyStatement","ExpressionStatement","ForInStatement","ForStatement","IfStatement","LabeledStatement","ReturnStatement","SwitchStatement","ThrowStatement","TryStatement","VariableDeclaration","WhileStatement","WithStatement","ClassDeclaration","ImportDeclaration","ExportDefaultDeclaration","ExportNamedDeclaration","ExportAllDeclaration","TypeAlias","InterfaceDeclaration","TypeAliasDeclaration","ExportAssignment","ExportDeclaration"],r=["ObjectExpression","ArrayExpression","StringLiteral","NumericLiteral","BooleanLiteral","NullLiteral"],i=["OperationDefinition","FragmentDefinition","VariableDefinition","TypeExtensionDefinition","ObjectTypeDefinition","FieldDefinition","DirectiveDefinition","EnumTypeDefinition","EnumValueDefinition","InputValueDefinition","InputObjectTypeDefinition","SchemaDefinition","OperationTypeDefinition","InterfaceTypeDefinition","UnionTypeDefinition","ScalarTypeDefinition"];switch(e.parser){case"flow":case"babylon":case"typescript":return n.indexOf(t.type)>-1;case"json":return r.indexOf(t.type)>-1;case"graphql":return i.indexOf(t.kind)>-1}return!1}function calculateRange(e,t,n){var r,i=e.slice(t.rangeStart,t.rangeEnd),o=Math.max(t.rangeStart+i.search(/\S/),t.rangeStart);for(r=t.rangeEnd;r>t.rangeStart&&!e[r-1].match(/\S/);--r);var a=findNodeAtOffset(n,o,t,function(e){return isSourceElement(t,e)}),s=findNodeAtOffset(n,r,t,function(e){return isSourceElement(t,e)});if(!a||!s)return{rangeStart:0,rangeEnd:0};var u=findSiblingAncestors(a,s,t),c=u.startNode,l=u.endNode;return{rangeStart:Math.min(t.locStart(c,t.locStart),t.locStart(l,t.locStart)),rangeEnd:Math.max(t.locEnd(c,t.locEnd),t.locEnd(l,t.locEnd))}}function guessLineEnding(e){var t=e.indexOf("\n");return t>=0&&"\r"===e.charAt(t-1)?"\r\n":"\n"}function ensureAllCommentsPrinted(e){if(e){for(var t=0;t=0){var o=rangeUtil.findNodeAtOffset(i,t.cursorOffset,t);o&&o.node&&(t.cursorNode=o.node)}var a=attachComments(e,i,t),s=astToDoc(i,t,n);t.newLine=guessLineEnding(e);var u=_printDocToString(s,t);if(ensureAllCommentsPrinted(a),n>0){var c=u.formatted.trim();void 0!==u.cursorNodeStart&&(u.cursorNodeStart-=u.formatted.indexOf(c)),u.formatted=c+t.newLine}if(t.cursorOffset>=0){var l,p,f,d,h;if(t.cursorNode&&u.cursorNodeText?(l=t.locStart(t.cursorNode),p=e.slice(l,t.locEnd(t.cursorNode)),f=t.cursorOffset-l,d=u.cursorNodeStart,h=u.cursorNodeText):(l=0,p=e,f=t.cursorOffset,d=0,h=u.formatted),p===h)return{formatted:u.formatted,cursorOffset:d+f};var m=p.split("");m.splice(f,0,CURSOR);var g=h.split(""),y=lib.diffArrays(m,g),v=d,b=!0,x=!1,C=void 0;try{for(var E,D=y[Symbol.iterator]();!(b=(E=D.next()).done);b=!0){var w=E.value;if(w.removed){if(w.value.indexOf(CURSOR)>-1)break}else v+=w.count}}catch(e){x=!0,C=e}finally{try{b||null==D.return||D.return()}finally{if(x)throw C}}return{formatted:u.formatted,cursorOffset:v}}return{formatted:u.formatted}}function formatRange(e,t){var n=parser.parse(e,t),r=n.ast;e=n.text;var i=rangeUtil.calculateRange(e,t,r),o=i.rangeStart,a=i.rangeEnd,s=e.slice(o,a),u=Math.min(o,e.lastIndexOf("\n",o)+1),c=e.slice(u,o),l=util.getAlignmentSize(c,t.tabWidth),p=coreFormat(s,Object.assign({},t,{rangeStart:0,rangeEnd:1/0,printWidth:t.printWidth-l,cursorOffset:t.cursorOffset>=o&&t.cursorOffset=a?h=t.cursorOffset-a+(o+f.length):void 0!==p.cursorOffset&&(h=p.cursorOffset+o),{formatted:d,cursorOffset:h}}function format(e,t){var n=parser.resolveParser(t),r=!n.hasPragma||n.hasPragma(e);if(t.requirePragma&&!r)return{formatted:e};if(t.rangeStart>0||t.rangeEnd2&&""===v[0].trim()&&""===v[1].trim(),E=b>2&&""===v[b-1].trim()&&""===v[b-2].trim(),D=v.every(function(e){return/^\s*(?:#[^\r\n]*)?$/.test(e)});if(!g&&/#[^\r\n]*$/.test(v[b-1]))return null;var w=null;w=D?printGraphqlComments(v):stripTrailingHardline$1(n(y,{parser:"graphql"})),w?(w=escapeBackticks(w),!m&&C&&f.push(""),f.push(w),!g&&E&&f.push("")):m||g||!C||f.push(""),x&&f.push(concat$5(["${",x,"}"]))}return concat$5(["`",indent$3(concat$5([hardline$4,join$3(hardline$4,f)])),hardline$4,"`"])}break;case"TemplateElement":if(a&&"TaggedTemplateExpression"===a.type&&1===o.quasis.length&&"Identifier"===a.tag.type&&("md"===a.tag.name||"markdown"===a.tag.name)){var S=o.quasis[0].value.raw.replace(/((?:\\\\)*)\\`/g,function(e,t){return"\\".repeat(t.length/2)+"`"}),k=getIndentation(S);return concat$5([""!==k?indent$3(concat$5([softline$2,r(S.replace(new RegExp("^".concat(k),"gm"),""))])):concat$5([literalline$2,dedentToRoot$1(r(S))]),softline$2])}}}function isPropertyWithinAngularComponentDecorator(e,t){var n=e.getParentNode(t);return!!(n&&"Decorator"===n.type&&n.expression&&"CallExpression"===n.expression.type&&n.expression.callee&&"Component"===n.expression.callee.name)}function getIndentation(e){var t=e.match(/^([^\S\n]*)\S/m);return null===t?"":t[1]}function escapeBackticks(e){return mapDoc$2(e,function(e){if(!e.parts)return e;var t=[];return e.parts.forEach(function(e){"string"===typeof e?t.push(e.replace(/(\\*)`/g,"$1$1\\`")):t.push(e)}),Object.assign({},e,{parts:t})})}function transformCssDoc(e,t,n){var r=t.getValue();if(1===r.quasis.length&&!r.quasis[0].value.raw.trim())return"``";var i=r.expressions?t.map(n,"expressions"):[],o=replacePlaceholders(e,i);if(!o)throw new Error("Couldn't insert all the expressions");return concat$5(["`",indent$3(concat$5([hardline$4,stripTrailingHardline$1(o)])),softline$2,"`"])}function replacePlaceholders(e,t){if(!t||!t.length)return e;var n=t.slice(),r=0,i=mapDoc$2(e,function(e){if(!e||!e.parts||!e.parts.length)return e;var t=e.parts,i=t.indexOf("@"),o=i+1;if(i>-1&&"string"===typeof t[o]&&t[o].startsWith("prettier-placeholder")){var a=t[i],s=t[o],u=t.slice(o+1);t=t.slice(0,i).concat([a+s]).concat(u)}var c=t.findIndex(function(e){return"string"===typeof e&&e.startsWith("@prettier-placeholder")});if(c>-1){var l=t[c],p=t.slice(c+1),f=l.match(/@prettier-placeholder-(.+)-id([\s\S]*)/),d=f[1],h=f[2],m=n[d];r++,t=t.slice(0,c).concat(["${",m,"}"+h]).concat(p)}return Object.assign({},e,{parts:t})});return n.length===r?i:null}function printGraphqlComments(e){var t=[],n=!1;return e.map(function(e){return e.trim()}).forEach(function(e,r,i){""!==e&&(""===i[r-1]&&n?t.push(concat$5([hardline$4,e])):t.push(e),n=!0)}),0===t.length?null:join$3(hardline$4,t)}function isStyledJsx(e){var t=e.getValue(),n=e.getParentNode(),r=e.getParentNode(1);return r&&t.quasis&&"JSXExpressionContainer"===n.type&&"JSXElement"===r.type&&"style"===r.openingElement.name.name&&r.openingElement.attributes.some(function(e){return"jsx"===e.name.name})}function isAngularComponentStyles(e){var t=e.getParentNode(),n=e.getParentNode(1);return!(!t||"ArrayExpression"!==t.type||"Property"!==n.type||!isPropertyWithinAngularComponentDecorator(e,4)||!n.key||"styles"!==n.key.name)}function isStyledComponents(e){var t=e.getParentNode();if(!t||"TaggedTemplateExpression"!==t.type)return!1;var n=t.tag;switch(n.type){case"MemberExpression":return isStyledIdentifier(n.object)||isStyledExtend(n);case"CallExpression":return isStyledIdentifier(n.callee)||"MemberExpression"===n.callee.type&&("MemberExpression"===n.callee.object.type&&(isStyledIdentifier(n.callee.object.object)||isStyledExtend(n.callee.object))||"CallExpression"===n.callee.object.type&&isStyledIdentifier(n.callee.object.callee));case"Identifier":return"css"===n.name;default:return!1}}function isCssProp(e){var t=e.getParentNode(),n=e.getParentNode(1);return n&&"JSXExpressionContainer"===t.type&&"JSXAttribute"===n.type&&"JSXIdentifier"===n.name.type&&"css"===n.name.name}function isStyledIdentifier(e){return"Identifier"===e.type&&"styled"===e.name}function isStyledExtend(e){return/^[A-Z]/.test(e.object.name)&&"extend"===e.property.name}function isGraphQL(e){var t=e.getValue(),n=e.getParentNode();return t.leadingComments&&t.leadingComments.some(function(e){return"CommentBlock"===e.type&&" GraphQL "===e.value})||n&&("TaggedTemplateExpression"===n.type&&("MemberExpression"===n.tag.type&&"graphql"===n.tag.object.name&&"experimental"===n.tag.property.name||"Identifier"===n.tag.type&&("gql"===n.tag.name||"graphql"===n.tag.name))||"CallExpression"===n.type&&"Identifier"===n.callee.type&&"graphql"===n.callee.name)}function clean(e,t,n){if(["range","raw","comments","leadingComments","trailingComments","extra","start","end","flags"].forEach(function(e){delete t[e]}),"EmptyStatement"===e.type)return null;if("JSXText"===e.type)return null;if("JSXExpressionContainer"===e.type&&"Literal"===e.expression.type&&" "===e.expression.value)return null;if("TSParameterProperty"===e.type&&null===e.accessibility&&!e.readonly)return{type:"Identifier",name:e.parameter.name,typeAnnotation:t.parameter.typeAnnotation,decorators:t.decorators};if("TSNamespaceExportDeclaration"===e.type&&e.specifiers&&0===e.specifiers.length&&delete t.specifiers,"TSParenthesizedType"===e.type&&"TSTypeAnnotation"===e.typeAnnotation.type)return t.typeAnnotation.typeAnnotation;if("JSXOpeningElement"===e.type&&delete t.selfClosing,"JSXElement"===e.type&&delete t.closingElement,"Property"!==e.type&&"ObjectProperty"!==e.type&&"MethodDefinition"!==e.type&&"ClassProperty"!==e.type&&"TSPropertySignature"!==e.type&&"ObjectTypeProperty"!==e.type||"object"!==_typeof(e.key)||!e.key||"Literal"!==e.key.type&&"StringLiteral"!==e.key.type&&"Identifier"!==e.key.type||delete t.key,"OptionalMemberExpression"===e.type&&!1===e.optional&&(t.type="MemberExpression",delete t.optional),"JSXElement"===e.type&&"style"===e.openingElement.name.name&&e.openingElement.attributes.some(function(e){return"jsx"===e.name.name})){t.children.filter(function(e){return"JSXExpressionContainer"===e.type&&"TemplateLiteral"===e.expression.type}).map(function(e){return e.expression}).reduce(function(e,t){return e.concat(t.quasis)},[]).forEach(function(e){return delete e.value})}"JSXAttribute"===e.type&&"css"===e.name.name&&"JSXExpressionContainer"===e.value.type&&"TemplateLiteral"===e.value.expression.type&&t.value.expression.quasis.forEach(function(e){return delete e.value});var r=e.expression||e.callee;if("Decorator"===e.type&&"CallExpression"===r.type&&"Component"===r.callee.name&&1===r.arguments.length&&r.arguments[0].properties.some(function(e){return"styles"===e.key.name&&"ArrayExpression"===e.value.type})&&t.expression.arguments[0].properties.forEach(function(e){"ArrayExpression"===e.value.type&&e.value.elements[0].quasis.forEach(function(e){return delete e.value})}),"TaggedTemplateExpression"!==e.type||"MemberExpression"!==e.tag.type&&("Identifier"!==e.tag.type||"gql"!==e.tag.name&&"graphql"!==e.tag.name&&"css"!==e.tag.name&&"md"!==e.tag.name&&"markdown"!==e.tag.name)&&"CallExpression"!==e.tag.type||t.quasi.quasis.forEach(function(e){return delete e.value}),"TemplateLiteral"===e.type){(e.leadingComments&&e.leadingComments.some(function(e){return"CommentBlock"===e.type&&" GraphQL "===e.value})||"CallExpression"===n.type&&"graphql"===n.callee.name)&&t.quasis.forEach(function(e){return delete e.value})}}function hasPragma(e){var t=Object.keys(build.parse(build.extract(e)));return-1!==t.indexOf("prettier")||-1!==t.indexOf("format")}function insertPragma$1(e){var t=build.parseWithComments(build.extract(e)),n=Object.assign({format:""},t.pragmas),r=build.print({pragmas:n,comments:t.comments.replace(/^(\s+?\r?\n)+/,"")}),i=build.strip(e);return r+(i.startsWith("\n")?"\n":"\n\n")+i}function handleOwnLineComment(e,t,n,r,i){var o=e.precedingNode,a=e.enclosingNode,s=e.followingNode;return!!(handleLastFunctionArgComments(t,o,a,s,e,n)||handleMemberExpressionComments(a,s,e)||handleIfStatementComments(t,o,a,s,e,n)||handleTryStatementComments(a,s,e)||handleClassComments(a,o,s,e)||handleImportSpecifierComments(a,e)||handleForComments(a,o,e)||handleUnionTypeComments(o,a,s,e)||handleOnlyComments(a,r,e,i)||handleImportDeclarationComments(t,a,o,e,n)||handleAssignmentPatternComments(a,e)||handleMethodNameComments(t,a,o,e,n))}function handleEndOfLineComment(e,t,n,r,i){var o=e.precedingNode,a=e.enclosingNode,s=e.followingNode;return!!(handleLastFunctionArgComments(t,o,a,s,e,n)||handleConditionalExpressionComments(a,o,s,e,t,n)||handleImportSpecifierComments(a,e)||handleIfStatementComments(t,o,a,s,e,n)||handleClassComments(a,o,s,e)||handleLabeledStatementComments(a,e)||handleCallExpressionComments(o,a,e)||handlePropertyComments(a,e)||handleOnlyComments(a,r,e,i)||handleTypeAliasComments(a,s,e)||handleVariableDeclaratorComments(a,s,e))}function handleRemainingComment(e,t,n,r,i){var o=e.precedingNode,a=e.enclosingNode,s=e.followingNode;return!!(handleIfStatementComments(t,o,a,s,e,n)||handleObjectPropertyAssignment(a,o,e)||handleCommentInEmptyParens(t,a,e,n)||handleMethodNameComments(t,a,o,e,n)||handleOnlyComments(a,r,e,i)||handleCommentAfterArrowParams(t,a,e,n)||handleFunctionNameComments(t,a,o,e,n)||handleTSMappedTypeComments(t,a,o,s,e)||handleBreakAndContinueStatementComments(a,e))}function addBlockStatementFirstComment(e,t){var n=e.body.filter(function(e){return"EmptyStatement"!==e.type});0===n.length?addDanglingComment$2(e,t):addLeadingComment$2(n[0],t)}function addBlockOrNotComment(e,t){"BlockStatement"===e.type?addBlockStatementFirstComment(e,t):addLeadingComment$2(e,t)}function handleIfStatementComments(e,t,n,r,i,o){if(!n||"IfStatement"!==n.type||!r)return!1;var a=util.getNextNonSpaceNonCommentCharacter(e,i,o.locEnd);return")"===a?(addTrailingComment$2(t,i),!0):t===n.consequent&&r===n.alternate?("BlockStatement"===t.type?addTrailingComment$2(t,i):addDanglingComment$2(n,i),!0):"BlockStatement"===r.type?(addBlockStatementFirstComment(r,i),!0):"IfStatement"===r.type?(addBlockOrNotComment(r.consequent,i),!0):("{"===a||n.consequent===r)&&(addLeadingComment$2(r,i),!0)}function handleTryStatementComments(e,t,n){return!(!e||"TryStatement"!==e.type||!t)&&("BlockStatement"===t.type?(addBlockStatementFirstComment(t,n),!0):"TryStatement"===t.type?(addBlockOrNotComment(t.finalizer,n),!0):"CatchClause"===t.type&&(addBlockOrNotComment(t.body,n),!0))}function handleMemberExpressionComments(e,t,n){return!(!e||"MemberExpression"!==e.type||!t||"Identifier"!==t.type)&&(addLeadingComment$2(e,n),!0)}function handleConditionalExpressionComments(e,t,n,r,i,o){var a=t&&!util.hasNewlineInRange(i,o.locEnd(t),o.locStart(r));return!(t&&a||!e||"ConditionalExpression"!==e.type||!n)&&(addLeadingComment$2(n,r),!0)}function handleObjectPropertyAssignment(e,t,n){return!(!e||"ObjectProperty"!==e.type&&"Property"!==e.type||!e.shorthand||e.key!==t||"AssignmentPattern"!==e.value.type)&&(addTrailingComment$2(e.value.left,n),!0)}function handleClassComments(e,t,n,r){return!(!(e&&("ClassDeclaration"===e.type||"ClassExpression"===e.type)&&e.decorators&&e.decorators.length>0)||n&&"Decorator"===n.type)&&(e.decorators&&0!==e.decorators.length?addTrailingComment$2(e.decorators[e.decorators.length-1],r):addLeadingComment$2(e,r),!0)}function handleMethodNameComments(e,t,n,r,i){return t&&n&&("Property"===t.type||"MethodDefinition"===t.type)&&"Identifier"===n.type&&t.key===n&&":"!==util.getNextNonSpaceNonCommentCharacter(e,n,i.locEnd)?(addTrailingComment$2(n,r),!0):!(!n||!t||"Decorator"!==n.type||"ClassMethod"!==t.type&&"ClassProperty"!==t.type&&"TSAbstractClassProperty"!==t.type&&"TSAbstractMethodDefinition"!==t.type&&"MethodDefinition"!==t.type)&&(addTrailingComment$2(n,r),!0)}function handleFunctionNameComments(e,t,n,r,i){return"("===util.getNextNonSpaceNonCommentCharacter(e,r,i.locEnd)&&(!(!n||!t||"FunctionDeclaration"!==t.type&&"FunctionExpression"!==t.type&&"ClassMethod"!==t.type&&"MethodDefinition"!==t.type&&"ObjectMethod"!==t.type)&&(addTrailingComment$2(n,r),!0))}function handleCommentAfterArrowParams(e,t,n,r){if(!t||"ArrowFunctionExpression"!==t.type)return!1;var i=utilShared.getNextNonSpaceNonCommentCharacterIndex(e,n,r);return"=>"===e.substr(i,2)&&(addDanglingComment$2(t,n),!0)}function handleCommentInEmptyParens(e,t,n,r){return")"===util.getNextNonSpaceNonCommentCharacter(e,n,r.locEnd)&&(t&&(("FunctionDeclaration"===t.type||"FunctionExpression"===t.type||"ArrowFunctionExpression"===t.type&&("CallExpression"!==t.body.type||0===t.body.arguments.length)||"ClassMethod"===t.type||"ObjectMethod"===t.type)&&0===t.params.length||"CallExpression"===t.type&&0===t.arguments.length)?(addDanglingComment$2(t,n),!0):!(!t||"MethodDefinition"!==t.type||0!==t.value.params.length)&&(addDanglingComment$2(t.value,n),!0))}function handleLastFunctionArgComments(e,t,n,r,i,o){return t&&"FunctionTypeParam"===t.type&&n&&"FunctionTypeAnnotation"===n.type&&r&&"FunctionTypeParam"!==r.type?(addTrailingComment$2(t,i),!0):!(!t||"Identifier"!==t.type&&"AssignmentPattern"!==t.type||!n||"ArrowFunctionExpression"!==n.type&&"FunctionExpression"!==n.type&&"FunctionDeclaration"!==n.type&&"ObjectMethod"!==n.type&&"ClassMethod"!==n.type||")"!==util.getNextNonSpaceNonCommentCharacter(e,i,o.locEnd))&&(addTrailingComment$2(t,i),!0)}function handleImportSpecifierComments(e,t){return!(!e||"ImportSpecifier"!==e.type)&&(addLeadingComment$2(e,t),!0)}function handleLabeledStatementComments(e,t){return!(!e||"LabeledStatement"!==e.type)&&(addLeadingComment$2(e,t),!0)}function handleBreakAndContinueStatementComments(e,t){return!(!e||"ContinueStatement"!==e.type&&"BreakStatement"!==e.type||e.label)&&(addTrailingComment$2(e,t),!0)}function handleCallExpressionComments(e,t,n){return!!(t&&"CallExpression"===t.type&&e&&t.callee===e&&t.arguments.length>0)&&(addLeadingComment$2(t.arguments[0],n),!0)}function handleUnionTypeComments(e,t,n,r){return!(!t||"UnionTypeAnnotation"!==t.type&&"TSUnionType"!==t.type)&&(addTrailingComment$2(e,r),!0)}function handlePropertyComments(e,t){return!(!e||"Property"!==e.type&&"ObjectProperty"!==e.type)&&(addLeadingComment$2(e,t),!0)}function handleOnlyComments(e,t,n,r){return t&&t.body&&0===t.body.length?(r?addDanglingComment$2(t,n):addLeadingComment$2(t,n),!0):!(!e||"Program"!==e.type||0!==e.body.length||!e.directives||0!==e.directives.length)&&(r?addDanglingComment$2(e,n):addLeadingComment$2(e,n),!0)}function handleForComments(e,t,n){return!(!e||"ForInStatement"!==e.type&&"ForOfStatement"!==e.type)&&(addLeadingComment$2(e,n),!0)}function handleImportDeclarationComments(e,t,n,r,i){return!!(n&&t&&"ImportDeclaration"===t.type&&util.hasNewline(e,i.locEnd(r)))&&(addTrailingComment$2(n,r),!0)}function handleAssignmentPatternComments(e,t){return!(!e||"AssignmentPattern"!==e.type)&&(addLeadingComment$2(e,t),!0)}function handleTypeAliasComments(e,t,n){return!(!e||"TypeAlias"!==e.type)&&(addLeadingComment$2(e,n),!0)}function handleVariableDeclaratorComments(e,t,n){return!(!e||"VariableDeclarator"!==e.type&&"AssignmentExpression"!==e.type||!t||"ObjectExpression"!==t.type&&"ArrayExpression"!==t.type&&"TemplateLiteral"!==t.type&&"TaggedTemplateExpression"!==t.type)&&(addLeadingComment$2(t,n),!0)}function handleTSMappedTypeComments(e,t,n,r,i){return!(!t||"TSMappedType"!==t.type)&&(r&&"TSTypeParameter"===r.type&&r.name?(addLeadingComment$2(r.name,i),!0):!(!n||"TSTypeParameter"!==n.type||!n.constraint)&&(addTrailingComment$2(n.constraint,i),!0))}function isBlockComment(e){return"Block"===e.type||"CommentBlock"===e.type}function hasClosureCompilerTypeCastComment(e,t,n){return t.comments&&t.comments.some(function(t){return t.leading&&comments$3.isBlockComment(t)&&t.value.match(/^\*\s*@type\s*{[^}]+}\s*$/)&&"("===util.getNextNonSpaceNonCommentCharacter(e,t,n)})}function needsParens(e,t){var n=e.getParentNode();if(!n)return!1;var r=e.getName(),i=e.getNode();if(e.getValue()!==i)return!1;if(isStatement(i))return!1;if(hasClosureCompilerTypeCastComment(t.originalText,i,t.locEnd))return!0;if("Identifier"===i.type)return!1;if("ParenthesizedExpression"===n.type)return!1;if(("ClassDeclaration"===n.type||"ClassExpression"===n.type)&&n.superClass===i&&("ArrowFunctionExpression"===i.type||"AssignmentExpression"===i.type||"AwaitExpression"===i.type||"BinaryExpression"===i.type||"ConditionalExpression"===i.type||"LogicalExpression"===i.type||"NewExpression"===i.type||"ObjectExpression"===i.type||"ParenthesizedExpression"===i.type||"SequenceExpression"===i.type||"TaggedTemplateExpression"===i.type||"UnaryExpression"===i.type||"UpdateExpression"===i.type||"YieldExpression"===i.type))return!0;if("ArrowFunctionExpression"===n.type&&n.body===i&&"SequenceExpression"!==i.type&&util.startsWithNoLookaheadToken(i,!1)||"ExpressionStatement"===n.type&&util.startsWithNoLookaheadToken(i,!0))return!0;switch(i.type){case"CallExpression":for(var o=n,a=0;o&&"MemberExpression"===o.type;)o=e.getParentNode(++a);return"NewExpression"===o.type&&o.callee===e.getParentNode(a-1);case"SpreadElement":case"SpreadProperty":return"MemberExpression"===n.type&&"object"===r&&n.object===i;case"UpdateExpression":if("UnaryExpression"===n.type)return i.prefix&&("++"===i.operator&&"+"===n.operator||"--"===i.operator&&"-"===n.operator);case"UnaryExpression":switch(n.type){case"UnaryExpression":return i.operator===n.operator&&("+"===i.operator||"-"===i.operator);case"MemberExpression":return"object"===r&&n.object===i;case"TaggedTemplateExpression":return!0;case"NewExpression":case"CallExpression":return"callee"===r&&n.callee===i;case"BinaryExpression":return"**"===n.operator&&"left"===r;case"TSNonNullExpression":return!0;default:return!1}case"BinaryExpression":if("UpdateExpression"===n.type)return!0;if("in"===i.operator&&function(t){for(var n=0;t;){var r=e.getParentNode(n++);if(!r)return!1;if("ForStatement"===r.type&&r.init===t)return!0;t=r}return!1}(i))return!0;case"TSTypeAssertionExpression":case"TSAsExpression":case"LogicalExpression":switch(n.type){case"ConditionalExpression":return"TSAsExpression"===i.type;case"CallExpression":case"NewExpression":return"callee"===r&&n.callee===i;case"ClassDeclaration":case"TSAbstractClassDeclaration":return"superClass"===r&&n.superClass===i;case"TSTypeAssertionExpression":case"TaggedTemplateExpression":case"UnaryExpression":case"SpreadElement":case"SpreadProperty":case"ExperimentalSpreadProperty":case"BindExpression":case"AwaitExpression":case"TSAsExpression":case"TSNonNullExpression":case"UpdateExpression":return!0;case"MemberExpression":return"object"===r&&n.object===i;case"AssignmentExpression":return n.left===i&&("TSTypeAssertionExpression"===i.type||"TSAsExpression"===i.type);case"Decorator":return n.expression===i&&("TSTypeAssertionExpression"===i.type||"TSAsExpression"===i.type);case"BinaryExpression":case"LogicalExpression":if(!i.operator&&"TSTypeAssertionExpression"!==i.type)return!0;var s=n.operator,u=util.getPrecedence(s),c=i.operator,l=util.getPrecedence(c);return u>l||(("||"===s||"??"===s)&&"&&"===c||(u===l&&"right"===r?(assert.strictEqual(n.right,i),!0):u===l&&!util.shouldFlatten(s,c)||(u0&&!getParentExportDeclaration$1(e)){var u=hardline$3;e.each(function(e){var t=e.getValue();t=t.expression?t.expression:t.callee,1!==i.decorators.length||"ClassDeclaration"===i.type||"MethodDefinition"===i.type||"ClassMethod"===i.type||"Identifier"!==t.type&&"MemberExpression"!==t.type&&"OptionalMemberExpression"!==t.type&&("CallExpression"!==t.type&&"OptionalCallExpression"!==t.type||0!==t.arguments.length&&(1!==t.arguments.length||!isStringLiteral(t.arguments[0])&&"Identifier"!==t.arguments[0].type&&"MemberExpression"!==t.arguments[0].type&&"OptionalMemberExpression"!==t.arguments[0].type))||(u=line$3),s.push(n(e),u)},"decorators")}else isExportDeclaration$1(i)&&i.declaration&&i.declaration.decorators?e.each(function(e){var t=e.getValue(),r="Decorator"===t.type?"":"@";s.push(r,n(e),hardline$3)},"declaration","decorators"):o=needsParens_1(e,t);var c=[];return o&&c.unshift("("),c.push(a),o&&c.push(")"),s.length>0?group$1(concat$4(s.concat(c))):concat$4(c)}function hasPrettierIgnore(e){return hasIgnoreComment$1(e)||hasJsxIgnoreComment(e)}function hasJsxIgnoreComment(e){var t=e.getValue(),n=e.getParentNode();if(!n||!t||!isJSXNode(t)||!isJSXNode(n))return!1;for(var r=n.children.indexOf(t),i=null,o=r;o>0;o--){var a=n.children[o-1];if("JSXText"!==a.type||isMeaningfulJSXText(a)){i=a;break}}return i&&"JSXExpressionContainer"===i.type&&"JSXEmptyExpression"===i.expression.type&&i.expression.comments&&i.expression.comments.find(function(e){return"prettier-ignore"===e.value.trim()})}function formatTernaryOperator(e,t,n,r){var i,o,a=e.getValue(),s=[],u=Object.assign({beforeParts:function(){return[""]},afterParts:function(){return[""]},shouldCheckJsx:!0,operatorName:"ConditionalExpression",consequentNode:"consequent",alternateNode:"alternate",testNode:"test",breakNested:!0},r||{}),c=!1,l=e.getParentNode(),p=l.type===u.operatorName,f=0;do{o=i||a,i=e.getParentNode(f),f++}while(i&&i.type===u.operatorName);var d=i||l,h=o;if(u.shouldCheckJsx&&isJSXNode(a[u.testNode])||isJSXNode(a[u.consequentNode])||isJSXNode(a[u.alternateNode])||conditionalExpressionChainContainsJSX(h)){c=!0,p=!0;var m=function(e){return concat$4([ifBreak$1("(",""),indent$2(concat$4([softline$1,e])),softline$1,ifBreak$1(")","")])},g=function(e){return"NullLiteral"===e.type||"Literal"===e.type&&null===e.value};s.push(" ? ",g(a[u.consequentNode])?e.call(n,u.consequentNode):m(e.call(n,u.consequentNode))," : ",a[u.alternateNode].type===u.operatorName||g(a[u.alternateNode])?e.call(n,u.alternateNode):m(e.call(n,u.alternateNode)))}else{var y=concat$4([line$3,"? ",a[u.consequentNode].type===u.operatorName?ifBreak$1("","("):"",align$1(2,e.call(n,u.consequentNode)),a[u.consequentNode].type===u.operatorName?ifBreak$1("",")"):"",line$3,": ",align$1(2,e.call(n,u.alternateNode))]);s.push(l.type===u.operatorName?t.useTabs?dedent$2(indent$2(y)):align$1(Math.max(0,t.tabWidth-2),y):y)}var v=!c&&("MemberExpression"===l.type||"OptionalMemberExpression"===l.type)&&!l.computed;return function(e){return u.breakNested?l===d?group$1(e):e:group$1(e)}(concat$4([].concat(u.beforeParts(),p?concat$4(s):indent$2(concat$4(s)),u.afterParts(v))))}function getTypeScriptMappedTypeModifier(e,t){return"TSPlusToken"===e.type?"+"+t:"TSMinusToken"===e.type?"-"+t:t}function printPathNoParens(e,t,n,r){var i=e.getValue(),o=t.semi?";":"";if(!i)return"";if("string"===typeof i)return i;var a=[];switch(i.type){case"File":return i.program&&i.program.interpreter&&a.push(e.call(function(e){return e.call(n,"interpreter")},"program")),a.push(e.call(n,"program")),concat$4(a);case"Program":return i.directives&&e.each(function(e){a.push(n(e),o,hardline$3),isNextLineEmpty$2(t.originalText,e.getValue(),t)&&a.push(hardline$3)},"directives"),a.push(e.call(function(e){return printStatementSequence(e,t,n)},"body")),a.push(comments.printDanglingComments(e,t,!0)),(i.body.length||i.comments)&&a.push(hardline$3),concat$4(a);case"EmptyStatement":return"";case"ExpressionStatement":return concat$4(i.directive?[nodeStr(i.expression,t,!0),o]:[e.call(n,"expression"),isTheOnlyJSXElementInMarkdown(t,e)?"":o]);case"ParenthesizedExpression":return concat$4(["(",e.call(n,"expression"),")"]);case"AssignmentExpression":return printAssignment(i.left,e.call(n,"left"),concat$4([" ",i.operator]),i.right,e.call(n,"right"),t);case"BinaryExpression":case"LogicalExpression":var s=e.getParentNode(),u=e.getParentNode(1),c=i!==s.body&&("IfStatement"===s.type||"WhileStatement"===s.type||"DoWhileStatement"===s.type),l=printBinaryishExpressions(e,n,t,!1,c);if(c)return concat$4(l);if("UnaryExpression"===s.type||("MemberExpression"===s.type||"OptionalMemberExpression"===s.type)&&!s.computed)return group$1(concat$4([indent$2(concat$4([softline$1,concat$4(l)])),softline$1]));var p="ReturnStatement"===s.type||"JSXExpressionContainer"===s.type&&"JSXAttribute"===u.type||i===s.body&&"ArrowFunctionExpression"===s.type||i!==s.body&&"ForStatement"===s.type||"ConditionalExpression"===s.type&&"ReturnStatement"!==u.type,f="AssignmentExpression"===s.type||"VariableDeclarator"===s.type||"ClassProperty"===s.type||"TSAbstractClassProperty"===s.type||"ClassPrivateProperty"===s.type||"ObjectProperty"===s.type||"Property"===s.type,d=isBinaryish(i.left)&&shouldFlatten$1(i.operator,i.left.operator);if(p||shouldInlineLogicalExpression(i)&&!d||!shouldInlineLogicalExpression(i)&&f)return group$1(concat$4(l));var h=concat$4(l.slice(1));return group$1(concat$4([l.length>0?l[0]:"",indent$2(h)]));case"AssignmentPattern":return concat$4([e.call(n,"left")," = ",e.call(n,"right")]);case"TSTypeAssertionExpression":var m=!("ArrayExpression"===i.expression.type||"ObjectExpression"===i.expression.type),g=group$1(concat$4(["<",indent$2(concat$4([softline$1,e.call(n,"typeAnnotation")])),softline$1,">"])),y=concat$4([ifBreak$1("("),indent$2(concat$4([softline$1,e.call(n,"expression")])),softline$1,ifBreak$1(")")]);return m?conditionalGroup$1([concat$4([g,e.call(n,"expression")]),concat$4([g,group$1(y,{shouldBreak:!0})]),concat$4([g,e.call(n,"expression")])]):group$1(concat$4([g,e.call(n,"expression")]));case"OptionalMemberExpression":case"MemberExpression":var v,b=e.getParentNode(),x=0;do{v=e.getParentNode(x),x++}while(v&&("MemberExpression"===v.type||"OptionalMemberExpression"===v.type||"TSNonNullExpression"===v.type));var C=v&&("NewExpression"===v.type||"BindExpression"===v.type||"VariableDeclarator"===v.type&&"Identifier"!==v.id.type||"AssignmentExpression"===v.type&&"Identifier"!==v.left.type)||i.computed||"Identifier"===i.object.type&&"Identifier"===i.property.type&&"MemberExpression"!==b.type&&"OptionalMemberExpression"!==b.type;return concat$4([e.call(n,"object"),C?printMemberLookup(e,t,n):group$1(indent$2(concat$4([softline$1,printMemberLookup(e,t,n)])))]);case"MetaProperty":return concat$4([e.call(n,"meta"),".",e.call(n,"property")]);case"BindExpression":return i.object&&a.push(e.call(n,"object")),a.push(group$1(indent$2(concat$4([softline$1,printBindExpressionCallee(e,t,n)])))),concat$4(a);case"Identifier":return concat$4([i.name,printOptionalToken(e),printTypeAnnotation(e,t,n)]);case"SpreadElement":case"SpreadElementPattern":case"RestProperty":case"ExperimentalRestProperty":case"ExperimentalSpreadProperty":case"SpreadProperty":case"SpreadPropertyPattern":case"RestElement":case"ObjectTypeSpreadProperty":return concat$4(["...",e.call(n,"argument"),printTypeAnnotation(e,t,n)]);case"FunctionDeclaration":case"FunctionExpression":return isNodeStartingWithDeclare(i,t)&&a.push("declare "),a.push(printFunctionDeclaration(e,n,t)),i.body||a.push(o),concat$4(a);case"ArrowFunctionExpression":i.async&&a.push("async "),shouldPrintParamsWithoutParens(e,t)?a.push(e.call(n,"params",0)):a.push(group$1(concat$4([printFunctionParams(e,n,t,r&&(r.expandLastArg||r.expandFirstArg),!0),printReturnType(e,n,t)])));var E=comments.printDanglingComments(e,t,!0,function(e){var n=getNextNonSpaceNonCommentCharacterIndex$2(t.originalText,e,t);return"=>"===t.originalText.substr(n,2)});E&&a.push(" ",E),a.push(" =>");var D=e.call(function(e){return n(e,r)},"body");if(!hasLeadingOwnLineComment(t.originalText,i.body,t)&&("ArrayExpression"===i.body.type||"ObjectExpression"===i.body.type||"BlockStatement"===i.body.type||isJSXNode(i.body)||isTemplateOnItsOwnLine(i.body,t.originalText,t)||"ArrowFunctionExpression"===i.body.type||"DoExpression"===i.body.type))return group$1(concat$4([concat$4(a)," ",D]));if("SequenceExpression"===i.body.type)return group$1(concat$4([concat$4(a),group$1(concat$4([" (",indent$2(concat$4([softline$1,D])),softline$1,")"]))]));var w=(r&&r.expandLastArg||"JSXExpressionContainer"===e.getParentNode().type)&&!(i.comments&&i.comments.length),S=r&&r.expandLastArg&&shouldPrintComma(t,"all"),k="ConditionalExpression"===i.body.type&&!startsWithNoLookaheadToken$1(i.body,!1);return group$1(concat$4([concat$4(a),group$1(concat$4([indent$2(concat$4([line$3,k?ifBreak$1("","("):"",D,k?ifBreak$1("",")"):""])),w?concat$4([ifBreak$1(S?",":""),softline$1]):""]))]));case"MethodDefinition":case"TSAbstractMethodDefinition":return i.accessibility&&a.push(i.accessibility+" "),i.static&&a.push("static "),"TSAbstractMethodDefinition"===i.type&&a.push("abstract "),a.push(printMethod(e,t,n)),concat$4(a);case"YieldExpression":return a.push("yield"),i.delegate&&a.push("*"),i.argument&&a.push(" ",e.call(n,"argument")),concat$4(a);case"AwaitExpression":return concat$4(["await ",e.call(n,"argument")]);case"ImportSpecifier":return i.importKind&&a.push(e.call(n,"importKind")," "),a.push(e.call(n,"imported")),i.local&&i.local.name!==i.imported.name&&a.push(" as ",e.call(n,"local")),concat$4(a);case"ExportSpecifier":return a.push(e.call(n,"local")),i.exported&&i.exported.name!==i.local.name&&a.push(" as ",e.call(n,"exported")),concat$4(a);case"ImportNamespaceSpecifier":return a.push("* as "),i.local?a.push(e.call(n,"local")):i.id&&a.push(e.call(n,"id")),concat$4(a);case"ImportDefaultSpecifier":return i.local?e.call(n,"local"):e.call(n,"id");case"TSExportAssignment":return concat$4(["export = ",e.call(n,"expression"),o]);case"ExportDefaultDeclaration":case"ExportNamedDeclaration":return printExportDeclaration(e,t,n);case"ExportAllDeclaration":return a.push("export "),"type"===i.exportKind&&a.push("type "),a.push("* from ",e.call(n,"source"),o),concat$4(a);case"ExportNamespaceSpecifier":case"ExportDefaultSpecifier":return e.call(n,"exported");case"ImportDeclaration":a.push("import "),i.importKind&&"value"!==i.importKind&&a.push(i.importKind+" ");var A=[],_=[];return i.specifiers&&i.specifiers.length>0?(e.each(function(e){var t=e.getValue();"ImportDefaultSpecifier"===t.type||"ImportNamespaceSpecifier"===t.type?A.push(n(e)):_.push(n(e))},"specifiers"),A.length>0&&a.push(join$2(", ",A)),A.length>0&&_.length>0&&a.push(", "),1===_.length&&0===A.length&&i.specifiers&&!i.specifiers.some(function(e){return e.comments})?a.push(concat$4(["{",t.bracketSpacing?" ":"",concat$4(_),t.bracketSpacing?" ":"","}"])):_.length>=1&&a.push(group$1(concat$4(["{",indent$2(concat$4([t.bracketSpacing?line$3:softline$1,join$2(concat$4([",",line$3]),_)])),ifBreak$1(shouldPrintComma(t)?",":""),t.bracketSpacing?line$3:softline$1,"}"]))),a.push(" from ")):(i.importKind&&"type"===i.importKind||/{\s*}/.test(t.originalText.slice(t.locStart(i),t.locStart(i.source))))&&a.push("{} from "),a.push(e.call(n,"source"),o),concat$4(a);case"Import":return"import";case"BlockStatement":var T=e.call(function(e){return printStatementSequence(e,t,n)},"body"),O=i.body.find(function(e){return"EmptyStatement"!==e.type}),F=i.directives&&i.directives.length>0,N=e.getParentNode(),I=e.getParentNode(1);return O||F||hasDanglingComments(i)||"ArrowFunctionExpression"!==N.type&&"FunctionExpression"!==N.type&&"FunctionDeclaration"!==N.type&&"ObjectMethod"!==N.type&&"ClassMethod"!==N.type&&"ForStatement"!==N.type&&"WhileStatement"!==N.type&&"DoWhileStatement"!==N.type&&"DoExpression"!==N.type&&("CatchClause"!==N.type||I.finalizer)?(a.push("{"),F&&e.each(function(e){a.push(indent$2(concat$4([hardline$3,n(e),o]))),isNextLineEmpty$2(t.originalText,e.getValue(),t)&&a.push(hardline$3)},"directives"),O&&a.push(indent$2(concat$4([hardline$3,T]))),a.push(comments.printDanglingComments(e,t)),a.push(hardline$3,"}"),concat$4(a)):"{}";case"ReturnStatement":return a.push("return"),i.argument&&(returnArgumentHasLeadingComment(t,i.argument)?a.push(concat$4([" (",indent$2(concat$4([hardline$3,e.call(n,"argument")])),hardline$3,")"])):"LogicalExpression"===i.argument.type||"BinaryExpression"===i.argument.type||"SequenceExpression"===i.argument.type?a.push(group$1(concat$4([ifBreak$1(" ("," "),indent$2(concat$4([softline$1,e.call(n,"argument")])),softline$1,ifBreak$1(")")]))):a.push(" ",e.call(n,"argument"))),hasDanglingComments(i)&&a.push(" ",comments.printDanglingComments(e,t,!0)),a.push(o),concat$4(a);case"NewExpression":case"OptionalCallExpression":case"CallExpression":var L="NewExpression"===i.type,P=printOptionalToken(e);return!L&&"Identifier"===i.callee.type&&("require"===i.callee.name||"define"===i.callee.name)||"Import"===i.callee.type||1===i.arguments.length&&isTemplateOnItsOwnLine(i.arguments[0],t.originalText,t)||!L&&isTestCall(i,e.getParentNode())?concat$4([L?"new ":"",e.call(n,"callee"),P,printFunctionTypeParameters(e,t,n),concat$4(["(",join$2(", ",e.map(n,"arguments")),")"])]):!L&&isMemberish(i.callee)?printMemberChain(e,t,n):concat$4([L?"new ":"",e.call(n,"callee"),P,printFunctionTypeParameters(e,t,n),printArgumentsList(e,t,n)]);case"TSInterfaceDeclaration":return isNodeStartingWithDeclare(i,t)&&a.push("declare "),a.push(i.abstract?"abstract ":"",printTypeScriptModifiers(e,t,n),"interface ",e.call(n,"id"),i.typeParameters?e.call(n,"typeParameters"):""," "),i.heritage.length&&a.push(group$1(indent$2(concat$4([softline$1,"extends ",indent$2(join$2(concat$4([",",line$3]),e.map(n,"heritage")))," "])))),a.push(e.call(n,"body")),concat$4(a);case"ObjectExpression":case"ObjectPattern":case"ObjectTypeAnnotation":case"TSInterfaceBody":case"TSTypeLiteral":var M,j="ObjectTypeAnnotation"===i.type,R=e.getParentNode(0),B="TSInterfaceBody"===i.type||"ObjectPattern"===i.type&&"FunctionDeclaration"!==R.type&&"FunctionExpression"!==R.type&&"ArrowFunctionExpression"!==R.type&&"AssignmentPattern"!==R.type&&"CatchClause"!==R.type&&i.properties.some(function(e){return e.value&&("ObjectPattern"===e.value.type||"ArrayPattern"===e.value.type)})||"ObjectPattern"!==i.type&&hasNewlineInRange$1(t.originalText,t.locStart(i),t.locEnd(i)),$=j&&R&&("InterfaceDeclaration"===R.type||"DeclareInterface"===R.type||"DeclareClass"===R.type)&&"body"===e.getName(),U=$?";":"TSInterfaceBody"===i.type||"TSTypeLiteral"===i.type?ifBreak$1(o,";"):",",z=[],G=i.exact?"{|":"{",V=i.exact?"|}":"}";M="TSTypeLiteral"===i.type?"members":"TSInterfaceBody"===i.type?"body":"properties",j&&z.push("indexers","callProperties"),z.push(M);var q=[];z.forEach(function(r){e.each(function(e){var r=e.getValue();q.push({node:r,printed:n(e),loc:t.locStart(r)})},r)});var H,W=[],Q=q.sort(function(e,t){return e.loc-t.loc}).map(function(e){var n=concat$4(W.concat(group$1(e.printed)));return W=[U,line$3],"TSPropertySignature"===e.node.type&&hasNodeIgnoreComment$1(e.node)&&W.shift(),isNextLineEmpty$2(t.originalText,e.node,t)&&W.push(hardline$3),n}),K=getLast$4(i[M]),J=!(K&&("RestProperty"===K.type||"RestElement"===K.type||"ExperimentalRestProperty"===K.type||hasNodeIgnoreComment$1(K)));if(0!==Q.length||i.typeAnnotation)H=concat$4([G,indent$2(concat$4([t.bracketSpacing?line$3:softline$1,concat$4(Q)])),ifBreak$1(J&&(","!==U||shouldPrintComma(t))?U:""),concat$4([t.bracketSpacing?line$3:softline$1,V]),printOptionalToken(e),printTypeAnnotation(e,t,n)]);else{if(!hasDanglingComments(i))return concat$4([G,V]);H=group$1(concat$4([G,comments.printDanglingComments(e,t),softline$1,V,printOptionalToken(e)]))}var Y=e.getParentNode(2);return"ObjectPattern"===i.type&&R&&shouldHugArguments(R)&&R.params[0]===i||shouldHugType(i)&&Y&&shouldHugArguments(Y)&&Y.params[0].typeAnnotation&&Y.params[0].typeAnnotation.typeAnnotation===i?H:group$1(H,{shouldBreak:B});case"ObjectProperty":case"Property":if(i.method||"get"===i.kind||"set"===i.kind)return printMethod(e,t,n);if(i.shorthand)a.push(e.call(n,"value"));else{var X;X=i.computed?concat$4(["[",e.call(n,"key"),"]"]):printPropertyKey(e,t,n),a.push(printAssignment(i.key,X,":",i.value,e.call(n,"value"),t))}return concat$4(a);case"ClassMethod":return i.static&&a.push("static "),a=a.concat(printObjectMethod(e,t,n)),concat$4(a);case"ObjectMethod":return printObjectMethod(e,t,n);case"Decorator":return concat$4(["@",e.call(n,"expression"),e.call(n,"callee")]);case"ArrayExpression":case"ArrayPattern":if(0===i.elements.length)hasDanglingComments(i)?a.push(group$1(concat$4(["[",comments.printDanglingComments(e,t),softline$1,"]"]))):a.push("[]");else{var Z=getLast$4(i.elements),ee=!(Z&&"RestElement"===Z.type),te=ee&&null===Z;a.push(group$1(concat$4(["[",indent$2(concat$4([softline$1,printArrayItems(e,t,"elements",n)])),te?",":"",ifBreak$1(ee&&!te&&shouldPrintComma(t)?",":""),comments.printDanglingComments(e,t,!0),softline$1,"]"])))}return a.push(printOptionalToken(e),printTypeAnnotation(e,t,n)),concat$4(a);case"SequenceExpression":var ne=e.getParentNode(0);if("ExpressionStatement"===ne.type||"ForStatement"===ne.type){var re=[];return e.each(function(e){0===e.getName()?re.push(n(e)):re.push(",",indent$2(concat$4([line$3,n(e)])))},"expressions"),group$1(concat$4(re))}return group$1(concat$4([join$2(concat$4([",",line$3]),e.map(n,"expressions"))]));case"ThisExpression":return"this";case"Super":return"super";case"NullLiteral":return"null";case"RegExpLiteral":return printRegex(i);case"NumericLiteral":return printNumber$1(i.extra.raw);case"BooleanLiteral":case"StringLiteral":case"Literal":if(i.regex)return printRegex(i.regex);if("number"===typeof i.value)return printNumber$1(i.raw);if("string"!==typeof i.value)return""+i.value;var ie=e.getParentNode(1),oe="typescript"===t.parser&&"string"===typeof i.value&&ie&&("Program"===ie.type||"BlockStatement"===ie.type);return nodeStr(i,t,oe);case"Directive":return e.call(n,"value");case"DirectiveLiteral":return nodeStr(i,t);case"UnaryExpression":return a.push(i.operator),/[a-z]$/.test(i.operator)&&a.push(" "),a.push(e.call(n,"argument")),concat$4(a);case"UpdateExpression":return a.push(e.call(n,"argument"),i.operator),i.prefix&&a.reverse(),concat$4(a);case"ConditionalExpression":return formatTernaryOperator(e,t,n,{beforeParts:function(){return[e.call(n,"test")]},afterParts:function(e){return[e?softline$1:""]}});case"VariableDeclaration":var ae,se=e.map(function(e){return n(e)},"declarations"),ue=e.getParentNode(),ce="ForStatement"===ue.type||"ForInStatement"===ue.type||"ForOfStatement"===ue.type||"ForAwaitStatement"===ue.type,le=i.declarations.some(function(e){return e.init});return 1===se.length?ae=se[0]:se.length>1&&(ae=indent$2(se[0])),a=[isNodeStartingWithDeclare(i,t)?"declare ":"",i.kind,ae?concat$4([" ",ae]):"",indent$2(concat$4(se.slice(1).map(function(e){return concat$4([",",le&&!ce?hardline$3:line$3,e])})))],ce&&ue.body!==i||a.push(o),group$1(concat$4(a));case"VariableDeclarator":return printAssignment(i.id,concat$4([e.call(n,"id"),e.call(n,"typeParameters")])," =",i.init,i.init&&e.call(n,"init"),t);case"WithStatement":return group$1(concat$4(["with (",e.call(n,"object"),")",adjustClause(i.body,e.call(n,"body"))]));case"IfStatement":var pe=adjustClause(i.consequent,e.call(n,"consequent")),fe=group$1(concat$4(["if (",group$1(concat$4([indent$2(concat$4([softline$1,e.call(n,"test")])),softline$1])),")",pe]));if(a.push(fe),i.alternate){var de=hasTrailingComment(i.consequent)&&i.consequent.comments.some(function(e){return e.trailing&&!comments$3.isBlockComment(e)})||needsHardlineAfterDanglingComment(i),he="BlockStatement"===i.consequent.type&&!de;a.push(he?" ":hardline$3),hasDanglingComments(i)&&a.push(comments.printDanglingComments(e,t,!0),de?hardline$3:" "),a.push("else",group$1(adjustClause(i.alternate,e.call(n,"alternate"),"IfStatement"===i.alternate.type)))}return concat$4(a);case"ForStatement":var me=adjustClause(i.body,e.call(n,"body")),ge=comments.printDanglingComments(e,t,!0),ye=ge?concat$4([ge,softline$1]):"";return concat$4(i.init||i.test||i.update?[ye,group$1(concat$4(["for (",group$1(concat$4([indent$2(concat$4([softline$1,e.call(n,"init"),";",line$3,e.call(n,"test"),";",line$3,e.call(n,"update")])),softline$1])),")",me]))]:[ye,group$1(concat$4(["for (;;)",me]))]);case"WhileStatement":return group$1(concat$4(["while (",group$1(concat$4([indent$2(concat$4([softline$1,e.call(n,"test")])),softline$1])),")",adjustClause(i.body,e.call(n,"body"))]));case"ForInStatement":return group$1(concat$4([i.each?"for each (":"for (",e.call(n,"left")," in ",e.call(n,"right"),")",adjustClause(i.body,e.call(n,"body"))]));case"ForOfStatement":case"ForAwaitStatement":var ve="ForAwaitStatement"===i.type||i.await;return group$1(concat$4(["for",ve?" await":""," (",e.call(n,"left")," of ",e.call(n,"right"),")",adjustClause(i.body,e.call(n,"body"))]));case"DoWhileStatement":var be=adjustClause(i.body,e.call(n,"body")),xe=group$1(concat$4(["do",be]));return a=[xe],"BlockStatement"===i.body.type?a.push(" "):a.push(hardline$3),a.push("while ("),a.push(group$1(concat$4([indent$2(concat$4([softline$1,e.call(n,"test")])),softline$1])),")",o),concat$4(a);case"DoExpression":return concat$4(["do ",e.call(n,"body")]);case"BreakStatement":return a.push("break"),i.label&&a.push(" ",e.call(n,"label")),a.push(o),concat$4(a);case"ContinueStatement":return a.push("continue"),i.label&&a.push(" ",e.call(n,"label")),a.push(o),concat$4(a);case"LabeledStatement":return concat$4("EmptyStatement"===i.body.type?[e.call(n,"label"),":;"]:[e.call(n,"label"),": ",e.call(n,"body")]);case"TryStatement":return concat$4(["try ",e.call(n,"block"),i.handler?concat$4([" ",e.call(n,"handler")]):"",i.finalizer?concat$4([" finally ",e.call(n,"finalizer")]):""]);case"CatchClause":return concat$4(["catch ",i.param?concat$4(["(",e.call(n,"param"),") "]):"",e.call(n,"body")]);case"ThrowStatement":return concat$4(["throw ",e.call(n,"argument"),o]);case"SwitchStatement":return concat$4([group$1(concat$4(["switch (",indent$2(concat$4([softline$1,e.call(n,"discriminant")])),softline$1,")"]))," {",i.cases.length>0?indent$2(concat$4([hardline$3,join$2(hardline$3,e.map(function(e){var r=e.getValue();return concat$4([e.call(n),i.cases.indexOf(r)!==i.cases.length-1&&isNextLineEmpty$2(t.originalText,r,t)?hardline$3:""])},"cases"))])):"",hardline$3,"}"]);case"SwitchCase":i.test?a.push("case ",e.call(n,"test"),":"):a.push("default:");var Ce=i.consequent.filter(function(e){return"EmptyStatement"!==e.type});if(Ce.length>0){var Ee=e.call(function(e){return printStatementSequence(e,t,n)},"consequent");a.push(1===Ce.length&&"BlockStatement"===Ce[0].type?concat$4([" ",Ee]):indent$2(concat$4([hardline$3,Ee])))}return concat$4(a);case"DebuggerStatement":return concat$4(["debugger",o]);case"JSXAttribute":if(a.push(e.call(n,"name")),i.value){var De;if(isStringLiteral(i.value)){De='"'+rawText(i.value).slice(1,-1).replace(/"/g,""")+'"'}else De=e.call(n,"value");a.push("=",De)}return concat$4(a);case"JSXIdentifier":return i.name?""+i.name:"this";case"JSXNamespacedName":return join$2(":",[e.call(n,"namespace"),e.call(n,"name")]);case"JSXMemberExpression":return join$2(".",[e.call(n,"object"),e.call(n,"property")]);case"TSQualifiedName":return join$2(".",[e.call(n,"left"),e.call(n,"right")]);case"JSXSpreadAttribute":case"JSXSpreadChild":return concat$4(["{",e.call(function(e){var r=concat$4(["...",n(e)]),i=e.getValue();return i.comments&&i.comments.length?concat$4([indent$2(concat$4([softline$1,comments.printComments(e,function(){return r},t)])),softline$1]):r},"JSXSpreadAttribute"===i.type?"argument":"expression"),"}"]);case"JSXExpressionContainer":var we=e.getParentNode(0),Se="JSXAttribute"===we.type&&i.expression.comments&&i.expression.comments.length>0,ke=!Se&&("ArrayExpression"===i.expression.type||"ObjectExpression"===i.expression.type||"ArrowFunctionExpression"===i.expression.type||"CallExpression"===i.expression.type||"OptionalCallExpression"===i.expression.type||"FunctionExpression"===i.expression.type||"JSXEmptyExpression"===i.expression.type||"TemplateLiteral"===i.expression.type||"TaggedTemplateExpression"===i.expression.type||"DoExpression"===i.expression.type||isJSXNode(we)&&("ConditionalExpression"===i.expression.type||isBinaryish(i.expression)));return group$1(ke?concat$4(["{",e.call(n,"expression"),lineSuffixBoundary$1,"}"]):concat$4(["{",indent$2(concat$4([softline$1,e.call(n,"expression")])),softline$1,lineSuffixBoundary$1,"}"]));case"JSXFragment":case"TSJsxFragment":case"JSXElement":var Ae=comments.printComments(e,function(){return printJSXElement(e,t,n)},t);return maybeWrapJSXElementInParens(e,Ae);case"JSXOpeningElement":var _e=e.getValue(),Te=_e.name&&_e.name.comments&&_e.name.comments.length>0;if(_e.selfClosing&&!_e.attributes.length&&!Te)return concat$4(["<",e.call(n,"name"),e.call(n,"typeParameters")," />"]);if(_e.attributes&&1===_e.attributes.length&&_e.attributes[0].value&&isStringLiteral(_e.attributes[0].value)&&!_e.attributes[0].value.value.includes("\n")&&!Te&&(!_e.attributes[0].comments||!_e.attributes[0].comments.length))return group$1(concat$4(["<",e.call(n,"name"),e.call(n,"typeParameters")," ",concat$4(e.map(n,"attributes")),_e.selfClosing?" />":">"]));var Oe=_e.attributes.length&&hasTrailingComment(getLast$4(_e.attributes)),Fe=t.jsxBracketSameLine&&(!Te||_e.attributes.length)&&!Oe,Ne=_e.attributes&&_e.attributes.some(function(e){return e.value&&isStringLiteral(e.value)&&e.value.value.includes("\n")});return group$1(concat$4(["<",e.call(n,"name"),e.call(n,"typeParameters"),concat$4([indent$2(concat$4(e.map(function(e){return concat$4([line$3,n(e)])},"attributes"))),_e.selfClosing?line$3:Fe?">":softline$1]),_e.selfClosing?"/>":Fe?"":">"]),{shouldBreak:Ne});case"JSXClosingElement":return concat$4([""]);case"JSXOpeningFragment":case"JSXClosingFragment":case"TSJsxOpeningFragment":case"TSJsxClosingFragment":var Ie=i.comments&&i.comments.length,Le=Ie&&!i.comments.every(comments$3.isBlockComment),Pe="JSXOpeningFragment"===i.type||"TSJsxOpeningFragment"===i.type;return concat$4([Pe?"<":""]);case"JSXText":throw new Error("JSXTest should be handled by JSXElement");case"JSXEmptyExpression":var Me=i.comments&&!i.comments.every(comments$3.isBlockComment);return concat$4([comments.printDanglingComments(e,t,!Me),Me?hardline$3:""]);case"ClassBody":return i.comments||0!==i.body.length?concat$4(["{",i.body.length>0?indent$2(concat$4([hardline$3,e.call(function(e){return printStatementSequence(e,t,n)},"body")])):comments.printDanglingComments(e,t),hardline$3,"}"]):"{}";case"ClassProperty":case"TSAbstractClassProperty":case"ClassPrivateProperty":i.accessibility&&a.push(i.accessibility+" "),i.static&&a.push("static "),"TSAbstractClassProperty"===i.type&&a.push("abstract "),i.readonly&&a.push("readonly ");var je=getFlowVariance(i);return je&&a.push(je),i.computed?a.push("[",e.call(n,"key"),"]"):a.push(printPropertyKey(e,t,n)),a.push(printTypeAnnotation(e,t,n)),i.value&&a.push(" =",printAssignmentRight(i.key,i.value,e.call(n,"value"),t)),a.push(o),group$1(concat$4(a));case"ClassDeclaration":case"ClassExpression":case"TSAbstractClassDeclaration":return isNodeStartingWithDeclare(i,t)&&a.push("declare "),a.push(concat$4(printClass(e,t,n))),concat$4(a);case"TSInterfaceHeritage":return a.push(e.call(n,"id")),i.typeParameters&&a.push(e.call(n,"typeParameters")),concat$4(a);case"TemplateElement":return join$2(literalline$1,i.value.raw.split(/\r?\n/g));case"TemplateLiteral":var Re=e.map(n,"expressions"),Be=e.getParentNode(),$e=/^[xf]?(describe|it|test)$/;if("TaggedTemplateExpression"===Be.type&&Be.quasi===i&&"MemberExpression"===Be.tag.type&&"Identifier"===Be.tag.property.type&&"each"===Be.tag.property.name&&("Identifier"===Be.tag.object.type&&$e.test(Be.tag.object.name)||"MemberExpression"===Be.tag.object.type&&"Identifier"===Be.tag.object.property.type&&("only"===Be.tag.object.property.name||"skip"===Be.tag.object.property.name)&&"Identifier"===Be.tag.object.object.type&&$e.test(Be.tag.object.object.name))){var Ue=i.quasis[0].value.raw.trim().split(/\s*\|\s*/);if(Ue.length>1||Ue.some(function(e){return 0!==e.length})){for(var ze=Re.map(function(e){return"${"+printDocToString$1(e,Object.assign({},t,{printWidth:1/0})).formatted+"}"}),Ge=[{hasLineBreak:!1,cells:[]}],Ve=1;Ve ":": ",e.call(n,"returnType"),e.call(n,"predicate"),e.call(n,"typeAnnotation")),nt&&a.push(")"),group$1(concat$4(a));case"FunctionTypeParam":return concat$4([e.call(n,"name"),printOptionalToken(e),i.name?": ":"",e.call(n,"typeAnnotation")]);case"GenericTypeAnnotation":return concat$4([e.call(n,"id"),e.call(n,"typeParameters")]);case"DeclareInterface":case"InterfaceDeclaration":case"InterfaceType":case"InterfaceTypeAnnotation":return("DeclareInterface"===i.type||isNodeStartingWithDeclare(i,t))&&a.push("declare "),a.push("interface"),"DeclareInterface"!==i.type&&"InterfaceDeclaration"!==i.type||a.push(" ",e.call(n,"id"),e.call(n,"typeParameters")),i.extends.length>0&&a.push(group$1(indent$2(concat$4([line$3,"extends ",join$2(", ",e.map(n,"extends"))])))),a.push(" ",e.call(n,"body")),group$1(concat$4(a));case"ClassImplements":case"InterfaceExtends":return concat$4([e.call(n,"id"),e.call(n,"typeParameters")]);case"TSIntersectionType":case"IntersectionTypeAnnotation":for(var rt=e.map(n,"types"),it=[],ot=!1,at=0;at1&&(ot=!0),it.push(" & ",at>1?indent$2(rt[at]):rt[at])):it.push(indent$2(concat$4([" &",line$3,rt[at]])));return group$1(concat$4(it));case"TSUnionType":case"UnionTypeAnnotation":var st=e.getParentNode(),ut=e.getParentNode(1),ct="TypeParameterInstantiation"!==st.type&&"TSTypeParameterInstantiation"!==st.type&&"GenericTypeAnnotation"!==st.type&&"TSTypeReference"!==st.type&&!("FunctionTypeParam"===st.type&&!st.name)&&"TSTypeAssertionExpression"!==ut.type&&!(("TypeAlias"===st.type||"VariableDeclarator"===st.type)&&hasLeadingOwnLineComment(t.originalText,i,t)),lt=shouldHugType(i),pt=e.map(function(e){var r=e.call(n);return lt||(r=align$1(2,r)),comments.printComments(e,function(){return r},t)},"types");if(lt)return join$2(" | ",pt);var ft,dt=concat$4([ifBreak$1(concat$4([ct?line$3:"","| "])),join$2(concat$4([line$3,"| "]),pt)]);if("TSUnionType"===i.type){var ht=e.getParentNode(2),mt=e.getParentNode(3);ft=ht&&"TSParenthesizedType"===ht.type&&mt&&("TSUnionType"===mt.type||"TSIntersectionType"===mt.type)}else ft=needsParens_1(e,t);return group$1(ft?concat$4([indent$2(dt),softline$1]):ct?indent$2(dt):dt);case"NullableTypeAnnotation":return concat$4(["?",e.call(n,"typeAnnotation")]);case"TSNullKeyword":case"NullLiteralTypeAnnotation":return"null";case"ThisTypeAnnotation":return"this";case"NumberTypeAnnotation":return"number";case"ObjectTypeCallProperty":return i.static&&a.push("static "),a.push(e.call(n,"value")),concat$4(a);case"ObjectTypeIndexer":var gt=getFlowVariance(i);return concat$4([gt||"","[",e.call(n,"id"),i.id?": ":"",e.call(n,"key"),"]: ",e.call(n,"value")]);case"ObjectTypeProperty":var yt=getFlowVariance(i),vt="";return i.proto?vt="proto ":i.static&&(vt="static "),concat$4([vt,isGetterOrSetter(i)?i.kind+" ":"",yt||"",printPropertyKey(e,t,n),printOptionalToken(e),isFunctionNotation(i,t)?"":": ",e.call(n,"value")]);case"QualifiedTypeIdentifier":return concat$4([e.call(n,"qualification"),".",e.call(n,"id")]);case"StringLiteralTypeAnnotation":return nodeStr(i,t);case"NumberLiteralTypeAnnotation":return assert.strictEqual(_typeof(i.value),"number"),printNumber$1(null!=i.extra?i.extra.raw:i.raw);case"StringTypeAnnotation":return"string";case"DeclareTypeAlias":case"TypeAlias":("DeclareTypeAlias"===i.type||isNodeStartingWithDeclare(i,t))&&a.push("declare ");var bt=printAssignmentRight(i.id,i.right,e.call(n,"right"),t);return a.push("type ",e.call(n,"id"),e.call(n,"typeParameters")," =",bt,o),group$1(concat$4(a));case"TypeCastExpression":return concat$4(["(",e.call(n,"expression"),": ",e.call(n,"typeAnnotation"),")"]);case"TypeParameterDeclaration":case"TypeParameterInstantiation":case"TSTypeParameterDeclaration":case"TSTypeParameterInstantiation":return printTypeParameters(e,t,n,"params");case"TSTypeParameter":case"TypeParameter":if("TSMappedType"===e.getParentNode().type)return a.push("[",e.call(n,"name")),i.constraint&&a.push(" in ",e.call(n,"constraint")),a.push("]"),concat$4(a);var xt=getFlowVariance(i);return xt&&a.push(xt),a.push(e.call(n,"name")),i.bound&&(a.push(": "),a.push(e.call(n,"bound"))),i.constraint&&a.push(" extends ",e.call(n,"constraint")),i.default&&a.push(" = ",e.call(n,"default")),concat$4(a);case"TypeofTypeAnnotation":return concat$4(["typeof ",e.call(n,"argument")]);case"VoidTypeAnnotation":return"void";case"InferredPredicate":return"%checks";case"DeclaredPredicate":return concat$4(["%checks(",e.call(n,"value"),")"]);case"TSAbstractKeyword":return"abstract";case"TSAnyKeyword":return"any";case"TSAsyncKeyword":return"async";case"TSBooleanKeyword":return"boolean";case"TSConstKeyword":return"const";case"TSDeclareKeyword":return"declare";case"TSExportKeyword":return"export";case"TSNeverKeyword":return"never";case"TSNumberKeyword":return"number";case"TSObjectKeyword":return"object";case"TSProtectedKeyword":return"protected";case"TSPrivateKeyword":return"private";case"TSPublicKeyword":return"public";case"TSReadonlyKeyword":return"readonly";case"TSSymbolKeyword":return"symbol";case"TSStaticKeyword":return"static";case"TSStringKeyword":return"string";case"TSUndefinedKeyword":return"undefined";case"TSVoidKeyword":return"void";case"TSAsExpression":return concat$4([e.call(n,"expression")," as ",e.call(n,"typeAnnotation")]);case"TSArrayType":return concat$4([e.call(n,"elementType"),"[]"]);case"TSPropertySignature":return i.export&&a.push("export "),i.accessibility&&a.push(i.accessibility+" "),i.static&&a.push("static "),i.readonly&&a.push("readonly "),i.computed&&a.push("["),a.push(printPropertyKey(e,t,n)),i.computed&&a.push("]"),a.push(printOptionalToken(e)),i.typeAnnotation&&(a.push(": "),a.push(e.call(n,"typeAnnotation"))),i.initializer&&a.push(" = ",e.call(n,"initializer")),concat$4(a);case"TSParameterProperty":return i.accessibility&&a.push(i.accessibility+" "),i.export&&a.push("export "),i.static&&a.push("static "),i.readonly&&a.push("readonly "),a.push(e.call(n,"parameter")),concat$4(a);case"TSTypeReference":return concat$4([e.call(n,"typeName"),printTypeParameters(e,t,n,"typeParameters")]);case"TSTypeQuery":return concat$4(["typeof ",e.call(n,"exprName")]);case"TSParenthesizedType":return e.call(n,"typeAnnotation");case"TSIndexSignature":var Ct=e.getParentNode();return concat$4([i.export?"export ":"",i.accessibility?concat$4([i.accessibility," "]):"",i.static?"static ":"",i.readonly?"readonly ":"","[",e.call(n,"index"),"]: ",e.call(n,"typeAnnotation"),"ClassBody"===Ct.type?o:""]);case"TSTypePredicate":return concat$4([e.call(n,"parameterName")," is ",e.call(n,"typeAnnotation")]);case"TSNonNullExpression":return concat$4([e.call(n,"expression"),"!"]);case"TSThisType":return"this";case"TSLastTypeNode":return concat$4([i.isTypeOf?"typeof ":"","import(",e.call(n,"argument"),")",i.qualifier?concat$4([".",e.call(n,"qualifier")]):""]);case"TSLiteralType":return e.call(n,"literal");case"TSIndexedAccessType":return concat$4([e.call(n,"objectType"),"[",e.call(n,"indexType"),"]"]);case"TSConstructSignature":case"TSConstructorType":case"TSCallSignature":if("TSCallSignature"!==i.type&&a.push("new "),a.push(group$1(printFunctionParams(e,n,t,!1,!0))),i.typeAnnotation){var Et="TSConstructorType"===i.type;a.push(Et?" => ":": ",e.call(n,"typeAnnotation"))}return concat$4(a);case"TSTypeOperator":return concat$4([i.operator," ",e.call(n,"typeAnnotation")]);case"TSMappedType":return group$1(concat$4(["{",indent$2(concat$4([t.bracketSpacing?line$3:softline$1,i.readonlyToken?concat$4([getTypeScriptMappedTypeModifier(i.readonlyToken,"readonly")," "]):"",printTypeScriptModifiers(e,t,n),e.call(n,"typeParameter"),i.questionToken?getTypeScriptMappedTypeModifier(i.questionToken,"?"):"",": ",e.call(n,"typeAnnotation")])),comments.printDanglingComments(e,t,!0),t.bracketSpacing?line$3:softline$1,"}"]));case"TSMethodSignature":return a.push(i.accessibility?concat$4([i.accessibility," "]):"",i.export?"export ":"",i.static?"static ":"",i.readonly?"readonly ":"",i.computed?"[":"",e.call(n,"key"),i.computed?"]":"",printOptionalToken(e),printFunctionParams(e,n,t,!1,!0)),i.typeAnnotation&&a.push(": ",e.call(n,"typeAnnotation")),group$1(concat$4(a));case"TSNamespaceExportDeclaration":return a.push("export as namespace ",e.call(n,"name")),t.semi&&a.push(";"),group$1(concat$4(a));case"TSEnumDeclaration":return isNodeStartingWithDeclare(i,t)&&a.push("declare "),i.modifiers&&a.push(printTypeScriptModifiers(e,t,n)),i.const&&a.push("const "),a.push("enum ",e.call(n,"id")," "),0===i.members.length?a.push(group$1(concat$4(["{",comments.printDanglingComments(e,t),softline$1,"}"]))):a.push(group$1(concat$4(["{",indent$2(concat$4([hardline$3,printArrayItems(e,t,"members",n),shouldPrintComma(t,"es5")?",":""])),comments.printDanglingComments(e,t,!0),hardline$3,"}"]))),concat$4(a);case"TSEnumMember":return a.push(e.call(n,"id")),i.initializer&&a.push(" = ",e.call(n,"initializer")),concat$4(a);case"TSImportEqualsDeclaration":return a.push(printTypeScriptModifiers(e,t,n),"import ",e.call(n,"name")," = ",e.call(n,"moduleReference")),t.semi&&a.push(";"),group$1(concat$4(a));case"TSExternalModuleReference":return concat$4(["require(",e.call(n,"expression"),")"]);case"TSModuleDeclaration":var Dt=e.getParentNode(),wt=isLiteral(i.id),St="TSModuleDeclaration"===Dt.type,kt=i.body&&"TSModuleDeclaration"===i.body.type;if(St)a.push(".");else{!0===i.declare&&a.push("declare "),a.push(printTypeScriptModifiers(e,t,n));"Identifier"===i.id.type&&"global"===i.id.name&&!/namespace|module/.test(t.originalText.slice(t.locStart(i),t.locStart(i.id)))||a.push(wt?"module ":"namespace ")}return a.push(e.call(n,"id")),kt?a.push(e.call(n,"body")):i.body?a.push(" {",indent$2(concat$4([line$3,e.call(function(e){return comments.printDanglingComments(e,t,!0)},"body"),group$1(e.call(n,"body"))])),line$3,"}"):a.push(o),concat$4(a);case"TSModuleBlock":return e.call(function(e){return printStatementSequence(e,t,n)},"body");case"PrivateName":return concat$4(["#",e.call(n,"id")]);case"TSConditionalType":return formatTernaryOperator(e,t,n,{beforeParts:function(){return[e.call(n,"checkType")," ","extends"," ",e.call(n,"extendsType")]},shouldCheckJsx:!1,operatorName:"TSConditionalType",consequentNode:"trueType",alternateNode:"falseType",testNode:"checkType",breakNested:!1});case"TSInferType":return concat$4(["infer"," ",e.call(n,"typeParameter")]);case"InterpreterDirective":return a.push("#!",i.value,hardline$3),isNextLineEmpty$2(t.originalText,i,t)&&a.push(hardline$3),concat$4(a);default:throw new Error("unknown type: "+JSON.stringify(i.type))}}function printStatementSequence(e,t,n){var r=[],i=e.getNode(),o="ClassBody"===i.type;return e.map(function(e,a){var s=e.getValue();if(s&&"EmptyStatement"!==s.type){var u=n(e),c=t.originalText,l=[];if(t.semi||o||isTheOnlyJSXElementInMarkdown(t,e)||!stmtNeedsASIProtection(e,t)?l.push(u):s.comments&&s.comments.some(function(e){return e.leading})?l.push(n(e,{needsSemi:!0})):l.push(";",u),!t.semi&&o)if(classPropMayCauseASIProblems(e))l.push(";");else if("ClassProperty"===s.type){var p=i.body[a+1];classChildNeedsASIProtection(p)&&l.push(";")}isNextLineEmpty$2(c,s,t)&&!isLastStatement(e)&&l.push(hardline$3),r.push(concat$4(l))}}),join$2(hardline$3,r)}function printPropertyKey(e,t,n){var r=e.getNode(),i=r.key;return"Identifier"!==i.type||r.computed||"json"!==t.parser?!isStringLiteral(i)||!isIdentifierName(i.value)||r.computed||"json"===t.parser||"typescript"===t.parser&&"ClassProperty"===r.type?e.call(n,"key"):e.call(function(e){return comments.printComments(e,function(){return i.value},t)},"key"):e.call(function(e){return comments.printComments(e,function(){return JSON.stringify(i.name)},t)},"key")}function printMethod(e,t,n){var r=e.getNode(),i=t.semi?";":"",o=r.kind,a=[];"ObjectMethod"!==r.type&&"ClassMethod"!==r.type||(r.value=r),r.value.async&&a.push("async "),o&&"init"!==o&&"method"!==o&&"constructor"!==o?(assert.ok("get"===o||"set"===o),a.push(o," ")):r.value.generator&&a.push("*");var s=printPropertyKey(e,t,n);return r.computed&&(s=concat$4(["[",s,"]"])),a.push(s,concat$4(e.call(function(e){return[printFunctionTypeParameters(e,t,n),group$1(concat$4([printFunctionParams(e,n,t),printReturnType(e,n,t)]))]},"value"))),r.value.body&&0!==r.value.body.length?a.push(" ",e.call(n,"value","body")):a.push(i),concat$4(a)}function couldGroupArg(e){return"ObjectExpression"===e.type&&(e.properties.length>0||e.comments)||"ArrayExpression"===e.type&&(e.elements.length>0||e.comments)||"TSTypeAssertionExpression"===e.type||"TSAsExpression"===e.type||"FunctionExpression"===e.type||"ArrowFunctionExpression"===e.type&&!e.returnType&&("BlockStatement"===e.body.type||"ArrowFunctionExpression"===e.body.type||"ObjectExpression"===e.body.type||"ArrayExpression"===e.body.type||"CallExpression"===e.body.type||"OptionalCallExpression"===e.body.type||isJSXNode(e.body))}function shouldGroupLastArg(e){var t=getLast$4(e),n=getPenultimate$1(e);return!hasLeadingComment(t)&&!hasTrailingComment(t)&&couldGroupArg(t)&&(!n||n.type!==t.type)}function shouldGroupFirstArg(e){if(2!==e.length)return!1;var t=e[0],n=e[1];return(!t.comments||!t.comments.length)&&("FunctionExpression"===t.type||"ArrowFunctionExpression"===t.type&&"BlockStatement"===t.body.type)&&!couldGroupArg(n)}function isFunctionCompositionFunction(e){switch(e.type){case"OptionalMemberExpression":case"MemberExpression":return isFunctionCompositionFunction(e.property);case"Identifier":return functionCompositionFunctionNames[e.name];case"StringLiteral":case"Literal":return functionCompositionFunctionNames[e.value]}}function printArgumentsList(e,t,n){function r(){return group$1(concat$4(["(",indent$2(concat$4([line$3,concat$4(c)])),l,line$3,")"]),{shouldBreak:!0})}var i=e.getValue(),o=i.arguments;if(0===o.length)return concat$4(["(",comments.printDanglingComments(e,t,!0),")"]);var a=!1,s=!1,u=o.length-1,c=e.map(function(e,r){var i=e.getNode(),o=[n(e)];return r===u||(isNextLineEmpty$2(t.originalText,i,t)?(0===r&&(s=!0),a=!0,o.push(",",hardline$3,hardline$3)):o.push(",",line$3)),concat$4(o)},"arguments"),l=shouldPrintComma(t,"all")?",":"";if(isFunctionCompositionFunction(i.callee)&&o.length>1)return r();var p=shouldGroupFirstArg(o),f=shouldGroupLastArg(o);if(p||f){var d,h=(p?c.slice(1).some(willBreak$1):c.slice(0,-1).some(willBreak$1))||a,m=0;e.each(function(e){p&&0===m&&(d=[concat$4([e.call(function(e){return n(e,{expandFirstArg:!0})}),c.length>1?",":"",s?hardline$3:line$3,s?hardline$3:""])].concat(c.slice(1))),f&&m===o.length-1&&(d=c.slice(0,-1).concat(e.call(function(e){return n(e,{expandLastArg:!0})}))),m++},"arguments");var g=c.some(willBreak$1);return concat$4([g?breakParent$2:"",conditionalGroup$1([concat$4([ifBreak$1(indent$2(concat$4(["(",softline$1,concat$4(d)])),concat$4(["(",concat$4(d)])),g?concat$4([ifBreak$1(l),softline$1]):"",")"]),concat$4(p?["(",group$1(d[0],{shouldBreak:!0}),concat$4(d.slice(1)),")"]:["(",concat$4(c.slice(0,-1)),group$1(getLast$4(d),{shouldBreak:!0}),")"]),r()],{shouldBreak:h})])}return group$1(concat$4(["(",indent$2(concat$4([softline$1,concat$4(c)])),ifBreak$1(shouldPrintComma(t,"all")?",":""),softline$1,")"]),{shouldBreak:c.some(willBreak$1)||a})}function printTypeAnnotation(e,t,n){var r=e.getValue();if(!r.typeAnnotation)return"";var i=e.getParentNode(),o=r.definite||i&&"VariableDeclarator"===i.type&&i.definite,a="DeclareFunction"===i.type&&i.id===r;return concat$4(isFlowAnnotationComment(t.originalText,r.typeAnnotation,t)?[" /*: ",e.call(n,"typeAnnotation")," */"]:[a?"":o?"!: ":": ",e.call(n,"typeAnnotation")])}function printFunctionTypeParameters(e,t,n){var r=e.getValue();return r.typeArguments?e.call(n,"typeArguments"):r.typeParameters?e.call(n,"typeParameters"):""}function printFunctionParams(e,t,n,r,i){var o=e.getValue(),a=o.parameters?"parameters":"params",s=i?printFunctionTypeParameters(e,n,t):"",u=[];if(o[a]&&(u=e.map(t,a)),o.rest&&u.push(concat$4(["...",e.call(t,"rest")])),0===u.length)return concat$4([s,"(",comments.printDanglingComments(e,n,!0,function(e){return")"===getNextNonSpaceNonCommentCharacter$1(n.originalText,e,n.locEnd)}),")"]);var c=getLast$4(o[a]);if(r&&(!o[a]||!o[a].some(function(e){return e.comments})))return group$1(concat$4([removeLines$1(s),"(",join$2(", ",u.map(removeLines$1)),")"]));if(shouldHugArguments(o))return concat$4([s,"(",join$2(", ",u),")"]);var l=e.getParentNode();if(isTestCall(l))return concat$4([s,"(",join$2(", ",u),")"]);var p=["AnyTypeAnnotation","NullLiteralTypeAnnotation","GenericTypeAnnotation","ThisTypeAnnotation","NumberTypeAnnotation","VoidTypeAnnotation","EmptyTypeAnnotation","MixedTypeAnnotation","BooleanTypeAnnotation","BooleanLiteralTypeAnnotation","StringTypeAnnotation"];if((isObjectTypePropertyAFunction(l,n)||isTypeAnnotationAFunction(l,n)||"TypeAlias"===l.type||"UnionTypeAnnotation"===l.type||"TSUnionType"===l.type||"IntersectionTypeAnnotation"===l.type||"FunctionTypeAnnotation"===l.type&&l.returnType===o)&&1===o[a].length&&null===o[a][0].name&&o[a][0].typeAnnotation&&null===o.typeParameters&&-1!==p.indexOf(o[a][0].typeAnnotation.type)&&!("GenericTypeAnnotation"===o[a][0].typeAnnotation.type&&o[a][0].typeAnnotation.typeParameters)&&!o.rest)return concat$4("always"===n.arrowParens?["(",concat$4(u),")"]:u);var f=!(c&&"RestElement"===c.type)&&!o.rest;return concat$4([s,"(",indent$2(concat$4([softline$1,join$2(concat$4([",",line$3]),u)])),ifBreak$1(f&&shouldPrintComma(n,"all")?",":""),softline$1,")"])}function shouldPrintParamsWithoutParens(e,t){if("always"===t.arrowParens)return!1;if("avoid"===t.arrowParens){return canPrintParamsWithoutParens(e.getValue())}return!1}function canPrintParamsWithoutParens(e){return 1===e.params.length&&!e.rest&&!e.typeParameters&&!hasDanglingComments(e)&&"Identifier"===e.params[0].type&&!e.params[0].typeAnnotation&&!e.params[0].comments&&!e.params[0].optional&&!e.predicate&&!e.returnType}function printFunctionDeclaration(e,t,n){var r=e.getValue(),i=[];return r.async&&i.push("async "),i.push("function"),r.generator&&i.push("*"),r.id&&i.push(" ",e.call(t,"id")),i.push(printFunctionTypeParameters(e,n,t),group$1(concat$4([printFunctionParams(e,t,n),printReturnType(e,t,n)])),r.body?" ":"",e.call(t,"body")),concat$4(i)}function printObjectMethod(e,t,n){var r=e.getValue(),i=[];if(r.async&&i.push("async "),r.generator&&i.push("*"),r.method||"get"===r.kind||"set"===r.kind)return printMethod(e,t,n);var o=printPropertyKey(e,t,n);return r.computed?i.push("[",o,"]"):i.push(o),i.push(printFunctionTypeParameters(e,t,n),group$1(concat$4([printFunctionParams(e,n,t),printReturnType(e,n,t)]))," ",e.call(n,"body")),concat$4(i)}function printReturnType(e,t,n){var r=e.getValue(),i=e.call(t,"returnType");if(r.returnType&&isFlowAnnotationComment(n.originalText,r.returnType,n))return concat$4([" /*: ",i," */"]);var o=[i];return r.returnType&&r.returnType.typeAnnotation&&o.unshift(": "),r.predicate&&o.push(r.returnType?" ":": ",e.call(t,"predicate")),concat$4(o)}function printExportDeclaration(e,t,n){var r=e.getValue(),i=t.semi?";":"",o=["export "],a=r.default||"ExportDefaultDeclaration"===r.type;if(a&&o.push("default "),o.push(comments.printDanglingComments(e,t,!0)),needsHardlineAfterDanglingComment(r)&&o.push(hardline$3),r.declaration)o.push(e.call(n,"declaration")),a&&"ClassDeclaration"!==r.declaration.type&&"FunctionDeclaration"!==r.declaration.type&&"TSAbstractClassDeclaration"!==r.declaration.type&&"TSInterfaceDeclaration"!==r.declaration.type&&"DeclareClass"!==r.declaration.type&&"DeclareFunction"!==r.declaration.type&&o.push(i);else{if(r.specifiers&&r.specifiers.length>0){var s=[],u=[],c=[];e.each(function(t){var r=e.getValue().type;"ExportSpecifier"===r?s.push(n(t)):"ExportDefaultSpecifier"===r?u.push(n(t)):"ExportNamespaceSpecifier"===r&&c.push(concat$4(["* as ",n(t)]))},"specifiers");var l=0!==c.length&&0!==s.length,p=0!==u.length&&(0!==c.length||0!==s.length);o.push("type"===r.exportKind?"type ":"",concat$4(u),concat$4([p?", ":""]),concat$4(c),concat$4([l?", ":""]),0!==s.length?group$1(concat$4(["{",indent$2(concat$4([t.bracketSpacing?line$3:softline$1,join$2(concat$4([",",line$3]),s)])),ifBreak$1(shouldPrintComma(t)?",":""),t.bracketSpacing?line$3:softline$1,"}"])):"")}else o.push("{}");r.source&&o.push(" from ",e.call(n,"source")),o.push(i)}return concat$4(o)}function printFlowDeclaration(e,t){var n=getParentExportDeclaration$1(e);return n?assert.strictEqual(n.type,"DeclareExportDeclaration"):t.unshift("declare "),concat$4(t)}function getFlowVariance(e){if(!e.variance)return null;var t=e.variance.kind||e.variance;switch(t){case"plus":return"+";case"minus":return"-";default:return t}}function printTypeScriptModifiers(e,t,n){var r=e.getValue();return r.modifiers&&r.modifiers.length?concat$4([join$2(" ",e.map(n,"modifiers"))," "]):""}function printTypeParameters(e,t,n,r){var i=e.getValue();if(!i[r])return"";if(!Array.isArray(i[r]))return e.call(n,r);var o=e.getNode(2);return null!=o&&isTestCall(o)||0===i[r].length||1===i[r].length&&(shouldHugType(i[r][0])||"GenericTypeAnnotation"===i[r][0].type&&shouldHugType(i[r][0].id)||"TSTypeReference"===i[r][0].type&&shouldHugType(i[r][0].typeName)||"NullableTypeAnnotation"===i[r][0].type)?concat$4(["<",join$2(", ",e.map(n,r)),">"]):group$1(concat$4(["<",indent$2(concat$4([softline$1,join$2(concat$4([",",line$3]),e.map(n,r))])),ifBreak$1("typescript"!==t.parser&&shouldPrintComma(t,"all")?",":""),softline$1,">"]))}function printClass(e,t,n){var r=e.getValue(),i=[];"TSAbstractClassDeclaration"===r.type&&i.push("abstract "),i.push("class"),r.id&&i.push(" ",e.call(n,"id")),i.push(e.call(n,"typeParameters"));var o=[];if(r.superClass){var a=concat$4(["extends ",e.call(n,"superClass"),e.call(n,"superTypeParameters")]);r.implements&&0!==r.implements.length||r.superClass.comments&&0!==r.superClass.comments.length?o.push(group$1(concat$4([line$3,e.call(function(e){return comments.printComments(e,function(){return a},t)},"superClass")]))):i.push(concat$4([" ",e.call(function(e){return comments.printComments(e,function(){return a},t)},"superClass")]))}else r.extends&&r.extends.length>0&&i.push(" extends ",join$2(", ",e.map(n,"extends")));return r.mixins&&r.mixins.length>0&&o.push(line$3,"mixins ",group$1(indent$2(join$2(concat$4([",",line$3]),e.map(n,"mixins"))))),r.implements&&r.implements.length>0&&o.push(line$3,"implements",group$1(indent$2(concat$4([line$3,join$2(concat$4([",",line$3]),e.map(n,"implements"))])))),o.length>0&&i.push(group$1(indent$2(concat$4(o)))),r.body&&r.body.comments&&hasLeadingOwnLineComment(t.originalText,r.body,t)?i.push(hardline$3):i.push(" "),i.push(e.call(n,"body")),i}function printOptionalToken(e){var t=e.getValue();return t.optional?"OptionalCallExpression"===t.type||"OptionalMemberExpression"===t.type&&t.computed?"?.":"?":""}function printMemberLookup(e,t,n){var r=e.call(n,"property"),i=e.getValue(),o=printOptionalToken(e);return i.computed?!i.property||isNumericLiteral(i.property)?concat$4([o,"[",r,"]"]):group$1(concat$4([o,"[",indent$2(concat$4([softline$1,r])),softline$1,"]"])):concat$4([o,".",r])}function printBindExpressionCallee(e,t,n){return concat$4(["::",e.call(n,"callee")])}function printMemberChain(e,t,n){function r(e){var n=t.originalText,r=getNextNonSpaceNonCommentCharacterIndex$2(n,e,t);return")"==n.charAt(r)?isNextLineEmptyAfterIndex$1(n,r+1,t):isNextLineEmpty$2(n,e,t)}function i(e){var o=e.getValue();"CallExpression"!==o.type&&"OptionalCallExpression"!==o.type||!isMemberish(o.callee)&&"CallExpression"!==o.callee.type&&"OptionalCallExpression"!==o.callee.type?isMemberish(o)?(u.unshift({node:o,needsParens:needsParens_1(e,t),printed:comments.printComments(e,function(){return"OptionalMemberExpression"===o.type||"MemberExpression"===o.type?printMemberLookup(e,t,n):printBindExpressionCallee(e,t,n)},t)}),e.call(function(e){return i(e)},"object")):"TSNonNullExpression"===o.type?(u.unshift({node:o,printed:comments.printComments(e,function(){return"!"},t)}),e.call(function(e){return i(e)},"expression")):u.unshift({node:o,printed:e.call(n)}):(u.unshift({node:o,printed:concat$4([comments.printComments(e,function(){return concat$4([printOptionalToken(e),printFunctionTypeParameters(e,t,n),printArgumentsList(e,t,n)])},t),r(o)?hardline$3:""])}),e.call(function(e){return i(e)},"callee"))}function o(e){return/^[A-Z]/.test(e)}function a(e){return e.length<=t.tabWidth}function s(e){for(var t=[],n=0;n0&&l.push(p);var h=l.length>=2&&!l[1][0].node.comments&&function(t){var n=e.getParentNode(),r=n&&"ExpressionStatement"===n.type,i=t[1].length&&t[1][0].node.computed;if(1===t[0].length){var s=t[0][0].node;return"ThisExpression"===s.type||"Identifier"===s.type&&(o(s.name)||r&&a(s.name)||i)}var u=getLast$4(t[0]).node;return("MemberExpression"===u.type||"OptionalMemberExpression"===u.type)&&"Identifier"===u.property.type&&(o(u.property.name)||i)}(l),m=l.map(s),g=concat$4(m),y=h?3:2,v=l.slice(0,y).reduce(function(e,t){return e.concat(t)},[]),b=v.slice(1,-1).some(function(e){return hasLeadingComment(e.node)})||v.slice(0,-1).some(function(e){return hasTrailingComment(e.node)})||l[y]&&hasLeadingComment(l[y][0].node);if(l.length<=y&&!b)return group$1(g);var x=getLast$4(h?l.slice(1,2)[0]:l[0]).node,C="CallExpression"!==x.type&&"OptionalCallExpression"!==x.type&&r(x),E=concat$4([s(l[0]),h?concat$4(l.slice(1,2).map(s)):"",C?hardline$3:"",function(e){return 0===e.length?"":indent$2(group$1(concat$4([hardline$3,join$2(hardline$3,e.map(s))])))}(l.slice(h?2:1))]),D=u.filter(function(e){return"CallExpression"===e.node.type||"OptionalCallExpression"===e.node.type}).length;return b||D>=3||m.slice(0,-1).some(willBreak$1)?group$1(E):concat$4([willBreak$1(g)||C?breakParent$2:"",conditionalGroup$1([g,E])])}function isJSXNode(e){return"JSXElement"===e.type||"JSXFragment"===e.type||"TSJsxFragment"===e.type}function isEmptyJSXElement(e){if(0===e.children.length)return!0;if(e.children.length>1)return!1;var t=e.children[0];return isLiteral(t)&&!isMeaningfulJSXText(t)}function isMeaningfulJSXText(e){return isLiteral(e)&&(containsNonJsxWhitespaceRegex.test(rawText(e))||!/\n/.test(rawText(e)))}function conditionalExpressionChainContainsJSX(e){return Boolean(getConditionalChainContents(e).find(isJSXNode))}function getConditionalChainContents(e){function t(e){"ConditionalExpression"===e.type?(t(e.test),t(e.consequent),t(e.alternate)):n.push(e)}var n=[];return t(e),n}function isJSXWhitespaceExpression(e){return"JSXExpressionContainer"===e.type&&isLiteral(e.expression)&&" "===e.expression.value&&!e.expression.comments}function printJSXChildren(e,t,n,r){var i=e.getValue(),o=[];return e.map(function(e,t){var a=e.getValue();if(isLiteral(a)){var s=rawText(a);if(isMeaningfulJSXText(a)){var u=s.split(matchJsxWhitespaceRegex);""===u[0]&&(o.push(""),u.shift(),/\n/.test(u[0])?o.push(hardline$3):o.push(r),u.shift());var c;if(""===getLast$4(u)&&(u.pop(),c=u.pop()),0===u.length)return;u.forEach(function(e,t){t%2===1?o.push(line$3):o.push(e)}),void 0!==c?/\n/.test(c)?o.push(hardline$3):o.push(r):o.push("")}else/\n/.test(s)?s.match(/\n/g).length>1&&(o.push(""),o.push(hardline$3)):(o.push(""),o.push(r))}else{var l=n(e);o.push(l);var p=i.children[t+1];p&&isMeaningfulJSXText(p)&&!/^[ \n\r\t]/.test(rawText(p))?o.push(""):o.push(hardline$3)}},"children"),o}function printJSXElement(e,t,n){var r=e.getValue();if("JSXElement"===r.type&&isEmptyJSXElement(r))return r.openingElement.selfClosing=!0,e.call(n,"openingElement");var i="JSXElement"===r.type?e.call(n,"openingElement"):e.call(n,"openingFragment"),o="JSXElement"===r.type?e.call(n,"closingElement"):e.call(n,"closingFragment");if(1===r.children.length&&"JSXExpressionContainer"===r.children[0].type&&("TemplateLiteral"===r.children[0].expression.type||"TaggedTemplateExpression"===r.children[0].expression.type))return concat$4([i,concat$4(e.map(n,"children")),o]);r.children=r.children.map(function(e){return isJSXWhitespaceExpression(e)?{type:"JSXText",value:" ",raw:" "}:e});for(var a=r.children.filter(isJSXNode).length>0,s=r.children.filter(function(e){return"JSXExpressionContainer"===e.type}).length>1,u="JSXElement"===r.type&&r.openingElement.attributes.length>1,c=willBreak$1(i)||a||u||s,l=t.singleQuote?"{' '}":'{" "}',p=ifBreak$1(concat$4([l,softline$1])," "),f=printJSXChildren(e,t,n,p),d=r.children.filter(function(e){return isMeaningfulJSXText(e)}).length>0,h=f.length-2;h>=0;h--){var m=""===f[h]&&""===f[h+1],g=f[h]===hardline$3&&""===f[h+1]&&f[h+2]===hardline$3,y=(f[h]===softline$1||f[h]===hardline$3)&&""===f[h+1]&&f[h+2]===p,v=f[h]===p&&""===f[h+1]&&(f[h+2]===softline$1||f[h+2]===hardline$3),b=f[h]===p&&""===f[h+1]&&f[h+2]===p;g&&d||m||y||b?f.splice(h,2):v&&f.splice(h+1,2)}for(;f.length&&(isLineNext$1(getLast$4(f))||isEmpty$1(getLast$4(f)));)f.pop();for(;f.length&&(isLineNext$1(f[0])||isEmpty$1(f[0]))&&(isLineNext$1(f[1])||isEmpty$1(f[1]));)f.shift(),f.shift();var x=[];f.forEach(function(e,t){if(e===p){if(1===t&&""===f[t-1])return 2===f.length?void x.push(l):void x.push(concat$4([l,hardline$3]));if(t===f.length-1)return void x.push(l);if(""===f[t-1]&&f[t-2]===hardline$3)return void x.push(l)}x.push(e),willBreak$1(e)&&(c=!0)});var C=d?fill$2(x):group$1(concat$4(x),{shouldBreak:!0}),E=group$1(concat$4([i,indent$2(concat$4([hardline$3,C])),hardline$3,o]));return c?E:conditionalGroup$1([group$1(concat$4([i,concat$4(f),o])),E])}function maybeWrapJSXElementInParens(e,t){var n=e.getParentNode();return n?{ArrayExpression:!0,JSXAttribute:!0,JSXElement:!0,JSXExpressionContainer:!0,JSXFragment:!0,TSJsxFragment:!0,ExpressionStatement:!0,CallExpression:!0,OptionalCallExpression:!0,ConditionalExpression:!0}[n.type]?t:group$1(concat$4([ifBreak$1("("),indent$2(concat$4([softline$1,t])),softline$1,ifBreak$1(")")])):t}function isBinaryish(e){return"BinaryExpression"===e.type||"LogicalExpression"===e.type}function isMemberish(e){return"MemberExpression"===e.type||"OptionalMemberExpression"===e.type||"BindExpression"===e.type&&e.object}function shouldInlineLogicalExpression(e){return"LogicalExpression"===e.type&&("ObjectExpression"===e.right.type&&0!==e.right.properties.length||("ArrayExpression"===e.right.type&&0!==e.right.elements.length||!!isJSXNode(e.right)))}function printBinaryishExpressions(e,t,n,r,i){var o=[],a=e.getValue();if(isBinaryish(a)){shouldFlatten$1(a.operator,a.left.operator)?o=o.concat(e.call(function(e){return printBinaryishExpressions(e,t,n,!0,i)},"left")):o.push(e.call(t,"left"));var s=shouldInlineLogicalExpression(a),u="|>"===a.operator,c=concat$4(s?[a.operator," ",e.call(t,"right")]:[u?softline$1:"",a.operator,u?" ":line$3,e.call(t,"right")]),l=e.getParentNode(),p=!(i&&"LogicalExpression"===a.type)&&l.type!==a.type&&a.left.type!==a.type&&a.right.type!==a.type;o.push(" ",p?group$1(c):c),r&&a.comments&&(o=comments.printComments(e,function(){return concat$4(o)},n))}else o.push(e.call(t));return o}function printAssignmentRight(e,t,n,r){return hasLeadingOwnLineComment(r.originalText,t,r)?indent$2(concat$4([hardline$3,n])):isBinaryish(t)&&!shouldInlineLogicalExpression(t)||"ConditionalExpression"===t.type&&isBinaryish(t.test)&&!shouldInlineLogicalExpression(t.test)||"StringLiteralTypeAnnotation"===t.type||("Identifier"===e.type||isStringLiteral(e)||"MemberExpression"===e.type)&&(isStringLiteral(t)||isMemberExpressionChain(t))?indent$2(concat$4([line$3,n])):concat$4([" ",n])}function printAssignment(e,t,n,r,i,o){if(!r)return t;var a=printAssignmentRight(e,r,i,o);return group$1(concat$4([t,n,a]))}function adjustClause(e,t,n){return"EmptyStatement"===e.type?";":"BlockStatement"===e.type||n?concat$4([" ",t]):indent$2(concat$4([line$3,t]))}function nodeStr(e,t,n){var r=rawText(e),i=n||"DirectiveLiteral"===e.type;return printString$1(r,t,i)}function printRegex(e){var t=e.flags.split("").sort().join("");return"/".concat(e.pattern,"/").concat(t)}function isLastStatement(e){var t=e.getParentNode();if(!t)return!0;var n=e.getValue(),r=(t.body||t.consequent).filter(function(e){return"EmptyStatement"!==e.type});return r&&r[r.length-1]===n}function hasLeadingComment(e){return e.comments&&e.comments.some(function(e){return e.leading})}function hasTrailingComment(e){return e.comments&&e.comments.some(function(e){return e.trailing})}function hasLeadingOwnLineComment(e,t,n){return isJSXNode(t)?hasNodeIgnoreComment$1(t):t.comments&&t.comments.some(function(t){return t.leading&&hasNewline$2(e,n.locEnd(t))})}function hasNakedLeftSide(e){return"AssignmentExpression"===e.type||"BinaryExpression"===e.type||"LogicalExpression"===e.type||"ConditionalExpression"===e.type||"CallExpression"===e.type||"OptionalCallExpression"===e.type||"MemberExpression"===e.type||"OptionalMemberExpression"===e.type||"SequenceExpression"===e.type||"TaggedTemplateExpression"===e.type||"BindExpression"===e.type&&!e.object||"UpdateExpression"===e.type&&!e.prefix}function isFlowAnnotationComment(e,t,n){var r=n.locStart(t),i=skipWhitespace$1(e,n.locEnd(t));return"/*"===e.substr(r,2)&&"*/"===e.substr(i,2)}function getLeftSide(e){return e.expressions?e.expressions[0]:e.left||e.test||e.callee||e.object||e.tag||e.argument||e.expression}function getLeftSidePathName(e,t){if(t.expressions)return["expressions",0];if(t.left)return["left"];if(t.test)return["test"];if(t.callee)return["callee"];if(t.object)return["object"];if(t.tag)return["tag"];if(t.argument)return["argument"];if(t.expression)return["expression"];throw new Error("Unexpected node has no left side",t)}function exprNeedsASIProtection(e,t){var n=e.getValue();return!!(needsParens_1(e,t)||"ParenthesizedExpression"===n.type||"TypeCastExpression"===n.type||"ArrowFunctionExpression"===n.type&&!shouldPrintParamsWithoutParens(e,t)||"ArrayExpression"===n.type||"ArrayPattern"===n.type||"UnaryExpression"===n.type&&n.prefix&&("+"===n.operator||"-"===n.operator)||"TemplateLiteral"===n.type||"TemplateElement"===n.type||isJSXNode(n)||"BindExpression"===n.type||"RegExpLiteral"===n.type||"Literal"===n.type&&n.pattern||"Literal"===n.type&&n.regex)||!!hasNakedLeftSide(n)&&e.call.apply(e,[function(e){return exprNeedsASIProtection(e,t)}].concat(getLeftSidePathName(e,n)))}function stmtNeedsASIProtection(e,t){return"ExpressionStatement"===e.getNode().type&&e.call(function(e){return exprNeedsASIProtection(e,t)},"expression")}function classPropMayCauseASIProblems(e){var t=e.getNode();if("ClassProperty"!==t.type)return!1;var n=t.key&&t.key.name;return!("static"!==n&&"get"!==n&&"set"!==n||t.value||t.typeAnnotation)||void 0}function classChildNeedsASIProtection(e){if(e){if(!e.computed){var t=e.key&&e.key.name;if("in"===t||"instanceof"===t)return!0}switch(e.type){case"ClassProperty":case"TSAbstractClassProperty":return e.computed;case"MethodDefinition":case"TSAbstractMethodDefinition":case"ClassMethod":var n=e.value?e.value.async:e.async,r=e.value?e.value.generator:e.generator;return!n&&!e.static&&"get"!==e.kind&&"set"!==e.kind&&!(!e.computed&&!r);default:return!1}}}function returnArgumentHasLeadingComment(e,t){if(hasLeadingOwnLineComment(e.originalText,t,e))return!0;if(hasNakedLeftSide(t))for(var n,r=t;n=getLeftSide(r);)if(r=n,hasLeadingOwnLineComment(e.originalText,r,e))return!0;return!1}function isMemberExpressionChain(e){return("MemberExpression"===e.type||"OptionalMemberExpression"===e.type)&&("Identifier"===e.object.type||isMemberExpressionChain(e.object))}function isObjectTypePropertyAFunction(e,t){return"ObjectTypeProperty"===e.type&&"FunctionTypeAnnotation"===e.value.type&&!e.static&&!isFunctionNotation(e,t)}function isFunctionNotation(e,t){return isGetterOrSetter(e)||sameLocStart(e,e.value,t)}function isGetterOrSetter(e){return"get"===e.kind||"set"===e.kind}function sameLocStart(e,t,n){return n.locStart(e)===n.locStart(t)}function isTypeAnnotationAFunction(e,t){return("TypeAnnotation"===e.type||"TSTypeAnnotation"===e.type)&&"FunctionTypeAnnotation"===e.typeAnnotation.type&&!e.static&&!sameLocStart(e,e.typeAnnotation,t)}function isNodeStartingWithDeclare(e,t){return("flow"===t.parser||"typescript"===t.parser)&&(t.originalText.slice(0,t.locStart(e)).match(/declare[ \t]*$/)||t.originalText.slice(e.range[0],e.range[1]).startsWith("declare "))}function shouldHugType(e){if(isObjectType(e))return!0;if("UnionTypeAnnotation"===e.type||"TSUnionType"===e.type){var t=e.types.filter(function(e){return"VoidTypeAnnotation"===e.type||"TSVoidKeyword"===e.type||"NullLiteralTypeAnnotation"===e.type||"TSNullKeyword"===e.type}).length,n=e.types.filter(function(e){return"ObjectTypeAnnotation"===e.type||"TSTypeLiteral"===e.type||"GenericTypeAnnotation"===e.type||"TSTypeReference"===e.type}).length;if(e.types.length-1===t&&n>0)return!0}return!1}function shouldHugArguments(e){return e&&e.params&&1===e.params.length&&!e.params[0].comments&&("ObjectPattern"===e.params[0].type||"ArrayPattern"===e.params[0].type||"Identifier"===e.params[0].type&&e.params[0].typeAnnotation&&("TypeAnnotation"===e.params[0].typeAnnotation.type||"TSTypeAnnotation"===e.params[0].typeAnnotation.type)&&isObjectType(e.params[0].typeAnnotation.typeAnnotation)||"FunctionTypeParam"===e.params[0].type&&isObjectType(e.params[0].typeAnnotation)||"AssignmentPattern"===e.params[0].type&&("ObjectPattern"===e.params[0].left.type||"ArrayPattern"===e.params[0].left.type)&&("Identifier"===e.params[0].right.type||"ObjectExpression"===e.params[0].right.type&&0===e.params[0].right.properties.length||"ArrayExpression"===e.params[0].right.type&&0===e.params[0].right.elements.length))&&!e.rest}function templateLiteralHasNewLines(e){return e.quasis.some(function(e){return e.value.raw.includes("\n")})}function isTemplateOnItsOwnLine(e,t,n){return("TemplateLiteral"===e.type&&templateLiteralHasNewLines(e)||"TaggedTemplateExpression"===e.type&&templateLiteralHasNewLines(e.quasi))&&!hasNewline$2(t,n.locStart(e),{backwards:!0})}function printArrayItems(e,t,n,r){var i=[],o=[];return e.each(function(e){i.push(concat$4(o)),i.push(group$1(r(e))),o=[",",line$3],e.getValue()&&isNextLineEmpty$2(t.originalText,e.getValue(),t)&&o.push(softline$1)},n),concat$4(i)}function hasDanglingComments(e){return e.comments&&e.comments.some(function(e){return!e.leading&&!e.trailing})}function needsHardlineAfterDanglingComment(e){if(!e.comments)return!1;var t=getLast$4(e.comments.filter(function(e){return!e.leading&&!e.trailing}));return t&&!comments$3.isBlockComment(t)}function isLiteral(e){return"BooleanLiteral"===e.type||"DirectiveLiteral"===e.type||"Literal"===e.type||"NullLiteral"===e.type||"NumericLiteral"===e.type||"RegExpLiteral"===e.type||"StringLiteral"===e.type||"TemplateLiteral"===e.type||"TSTypeLiteral"===e.type||"JSXText"===e.type}function isNumericLiteral(e){return"NumericLiteral"===e.type||"Literal"===e.type&&"number"===typeof e.value}function isStringLiteral(e){return"StringLiteral"===e.type||"Literal"===e.type&&"string"===typeof e.value}function isObjectType(e){return"ObjectTypeAnnotation"===e.type||"TSTypeLiteral"===e.type}function isTestCall(e,t){if("CallExpression"!==e.type)return!1;if(1===e.arguments.length){if(isAngularTestWrapper(e)&&t&&isTestCall(t))return isFunctionOrArrowExpression(e.arguments[0].type);if(isUnitTestSetUp(e))return isFunctionOrArrowExpression(e.arguments[0].type)||isAngularTestWrapper(e.arguments[0])}else if(2===e.arguments.length&&("Identifier"===e.callee.type&&unitTestRe.test(e.callee.name)||isSkipOrOnlyBlock(e))&&(isTemplateLiteral(e.arguments[0])||isStringLiteral(e.arguments[0])))return isFunctionOrArrowExpression(e.arguments[1].type)&&e.arguments[1].params.length<=1||isAngularTestWrapper(e.arguments[1]);return!1}function isSkipOrOnlyBlock(e){return("MemberExpression"===e.callee.type||"OptionalMemberExpression"===e.callee.type)&&"Identifier"===e.callee.object.type&&"Identifier"===e.callee.property.type&&unitTestRe.test(e.callee.object.name)&&("only"===e.callee.property.name||"skip"===e.callee.property.name)}function isTemplateLiteral(e){return"TemplateLiteral"===e.type}function isAngularTestWrapper(e){return("CallExpression"===e.type||"OptionalCallExpression"===e.type)&&"Identifier"===e.callee.type&&("async"===e.callee.name||"inject"===e.callee.name)}function isFunctionOrArrowExpression(e){return"FunctionExpression"===e||"ArrowFunctionExpression"===e}function isUnitTestSetUp(e){var t=/^(before|after)(Each|All)$/;return"Identifier"===e.callee.type&&t.test(e.callee.name)&&1===e.arguments.length}function isTheOnlyJSXElementInMarkdown(e,t){if("markdown"!==e.parentParser)return!1;var n=t.getNode();if(!n.expression||!isJSXNode(n.expression))return!1;var r=t.getParentNode();return"Program"===r.type&&1==r.body.length}function willPrintOwnComments(e){var t=e.getValue(),n=e.getParentNode();return(t&&isJSXNode(t)||n&&("JSXSpreadAttribute"===n.type||"JSXSpreadChild"===n.type||"UnionTypeAnnotation"===n.type||"TSUnionType"===n.type||("ClassDeclaration"===n.type||"ClassExpression"===n.type)&&n.superClass===t))&&!hasIgnoreComment$1(e)}function canAttachComment(e){return e.type&&"CommentBlock"!==e.type&&"CommentLine"!==e.type&&"Line"!==e.type&&"Block"!==e.type&&"EmptyStatement"!==e.type&&"TemplateElement"!==e.type&&"Import"!==e.type&&!(e.callee&&"Import"===e.callee.type)}function printComment$1(e,t){var n=e.getValue();switch(n.type){case"CommentBlock":case"Block":if(isJsDocComment(n)){var r=printJsDocComment(n);return n.trailing&&!hasNewline$2(t.originalText,t.locStart(n),{backwards:!0})?concat$4([hardline$3,r]):r}var i="*-/"===t.originalText.substr(t.locEnd(n)-3,3);return"/*"+n.value+(i?"*-/":"*/");case"CommentLine":case"Line":return t.originalText.slice(t.locStart(n)).startsWith("#!")?"#!"+n.value.trimRight():"//"+n.value.trimRight();default:throw new Error("Not a comment: "+JSON.stringify(n))}}function isJsDocComment(e){var t=e.value.split("\n");return t.length>1&&t.slice(0,t.length-1).every(function(e){return"*"===e.trim()[0]})}function printJsDocComment(e){var t=e.value.split("\n");return concat$4(["/*",join$2(hardline$3,t.map(function(e,n){return(n>0?" ":"")+(n","<=",">="].indexOf(e.value)}function isSCSSControlDirectiveNode$1(e){return"css-atrule"===e.type&&-1!==["if","else","for","each","while"].indexOf(e.name)}function isSCSSNestedPropertyNode(e){return!!e.selector&&e.selector.replace(/\/\*.*?\*\//,"").replace(/\/\/.*?\n/,"").trim().endsWith(":")}function isDetachedRulesetCallNode$1(e){return e.raws&&e.raws.params&&/^\(\s*\)$/.test(e.raws.params)}function isPostcssSimpleVarNode$1(e,t){return"$$"===e.value&&"value-func"===e.type&&t&&"value-word"===t.type&&!t.raws.before}function hasComposesNode$1(e){return e.value&&"value-root"===e.value.type&&e.value.group&&"value-value"===e.value.group.type&&"composes"===e.prop.toLowerCase()}function hasParensAroundNode$1(e){return e.value&&e.value.group&&e.value.group.group&&"value-paren_group"===e.value.group.group.type&&null!==e.value.group.group.open&&null!==e.value.group.group.close}function hasEmptyRawBefore$1(e){return e.raws&&""===e.raws.before}function isKeyValuePairNode$1(e){return"value-comma_group"===e.type&&e.groups&&e.groups[1]&&"value-colon"===e.groups[1].type}function isKeyValuePairInParenGroupNode(e){return"value-paren_group"===e.type&&e.groups&&e.groups[0]&&isKeyValuePairNode$1(e.groups[0])}function isSCSSMapItemNode$1(e){var t=e.getValue();if(0===t.groups.length)return!1;var n=e.getParentNode(1);if(!isKeyValuePairInParenGroupNode(t)&&(!n||!isKeyValuePairInParenGroupNode(n)))return!1;var r=getAncestorNode$1(e,"css-decl");return!!(r&&r.prop&&r.prop.startsWith("$"))||(!!isKeyValuePairInParenGroupNode(n)||"value-func"===n.type)}function isInlineValueCommentNode$1(e){return"value-comment"===e.type&&e.inline}function isHashNode$1(e){return"value-word"===e.type&&"#"===e.value}function isLeftCurlyBraceNode$1(e){return"value-word"===e.type&&"{"===e.value}function isRightCurlyBraceNode$1(e){return"value-word"===e.type&&"}"===e.value}function isWordNode$1(e){return-1!==["value-word","value-atword"].indexOf(e.type)}function isColonNode$1(e){return"value-colon"===e.type}function isMediaAndSupportsKeywords$1(e){return e.value&&-1!==["not","and","or"].indexOf(e.value.toLowerCase())}function shouldPrintComma$1(e){switch(e.trailingComma){case"all":case"es5":return!0;case"none":default:return!1}}function genericPrint$3(e,t,n){var r=e.getValue();if(!r)return"";if("string"===typeof r)return r;switch(r.type){case"front-matter":return concat$7([r.value,hardline$6]);case"css-root":var i=printNodeSequence(e,t,n);return i.parts.length?concat$7([i,hardline$6]):i;case"css-comment":if(r.raws.content)return r.raws.content;var o=t.originalText.slice(t.locStart(r),t.locEnd(r)),a=r.raws.text||r.text;return-1===o.indexOf(a)?concat$7(r.raws.inline?["// ",a]:["/* ",a," */"]):o;case"css-rule":return concat$7([e.call(n,"selector"),r.important?" !important":"",r.nodes?concat$7([" {",r.nodes.length>0?indent$5(concat$7([hardline$6,printNodeSequence(e,t,n)])):"",hardline$6,"}",isDetachedRulesetDeclarationNode(r)?";":""]):";"]);case"css-decl":return concat$7([r.raws.before.replace(/[\s;]/g,""),insideICSSRuleNode(e)?r.prop:maybeToLowerCase(r.prop),":"===r.raws.between.trim()?":":r.raws.between.trim(),r.extend?"":" ",hasComposesNode(r)?removeLines$2(e.call(n,"value")):e.call(n,"value"),r.raws.important?r.raws.important.replace(/\s*!\s*important/i," !important"):r.important?" !important":"",r.raws.scssDefault?r.raws.scssDefault.replace(/\s*!default/i," !default"):r.scssDefault?" !default":"",r.raws.scssGlobal?r.raws.scssGlobal.replace(/\s*!global/i," !global"):r.scssGlobal?" !global":"",r.nodes?concat$7([" {",indent$5(concat$7([softline$3,printNodeSequence(e,t,n)])),softline$3,"}"]):";"]);case"css-atrule":return concat$7(["@",isDetachedRulesetCallNode(r)||r.name.endsWith(":")?r.name:maybeToLowerCase(r.name),r.params?concat$7([isDetachedRulesetCallNode(r)?"":" ",e.call(n,"params")]):"",r.selector?indent$5(concat$7([" ",e.call(n,"selector")])):"",r.value?group$2(concat$7([" ",e.call(n,"value"),isSCSSControlDirectiveNode(r)?hasParensAroundNode(r)?" ":line$4:""])):"else"===r.name?" ":"",r.nodes?concat$7([isSCSSControlDirectiveNode(r)?"":" ","{",indent$5(concat$7([r.nodes.length>0?softline$3:"",printNodeSequence(e,t,n)])),softline$3,"}"]):";"]);case"media-query-list":var s=[];return e.each(function(e){var t=e.getValue();"media-query"===t.type&&""===t.value||s.push(e.call(n))},"nodes"),group$2(indent$5(join$5(line$4,s)));case"media-query":return concat$7([join$5(" ",e.map(n,"nodes")),isLastNode(e,r)?"":","]);case"media-type":return adjustNumbers(adjustStrings(r.value,t));case"media-feature-expression":return r.nodes?concat$7(["(",concat$7(e.map(n,"nodes")),")"]):r.value;case"media-feature":return maybeToLowerCase(adjustStrings(r.value.replace(/ +/g," "),t));case"media-colon":return concat$7([r.value," "]);case"media-value":return adjustNumbers(adjustStrings(r.value,t));case"media-keyword":return adjustStrings(r.value,t);case"media-url":return adjustStrings(r.value.replace(/^url\(\s+/gi,"url(").replace(/\s+\)$/gi,")"),t);case"media-unknown":return r.value;case"selector-root":return group$2(concat$7([insideAtRuleNode(e,"custom-selector")?concat$7([getAncestorNode(e,"css-atrule").customSelector,line$4]):"",join$5(concat$7([",",insideAtRuleNode(e,["extend","custom-selector","nest"])?line$4:hardline$6]),e.map(n,"nodes"))]));case"selector-selector":return group$2(indent$5(concat$7(e.map(n,"nodes"))));case"selector-comment":return r.value;case"selector-string":return adjustStrings(r.value,t);case"selector-tag":var u=e.getParentNode(),c=u&&u.nodes.indexOf(r),l=c&&u.nodes[c-1];return concat$7([r.namespace?concat$7([!0===r.namespace?"":r.namespace.trim(),"|"]):"","selector-nesting"===l.type?r.value:adjustNumbers(isHTMLTag(r.value)||isKeyframeAtRuleKeywords(e,r.value)?r.value.toLowerCase():r.value)]);case"selector-id":return concat$7(["#",r.value]);case"selector-class":return concat$7([".",adjustNumbers(adjustStrings(r.value,t))]);case"selector-attribute":return concat$7(["[",r.namespace?concat$7([!0===r.namespace?"":r.namespace.trim(),"|"]):"",r.attribute.trim(),r.operator?r.operator:"",r.value?quoteAttributeValue(adjustStrings(r.value.trim(),t),t):"",r.insensitive?" i":"","]"]);case"selector-combinator":if("+"===r.value||">"===r.value||"~"===r.value||">>>"===r.value){var p=e.getParentNode(),f="selector-selector"===p.type&&p.nodes[0]===r?"":line$4;return concat$7([f,r.value,isLastNode(e,r)?"":" "])}var d=r.value.trim().startsWith("(")?line$4:"",h=adjustNumbers(adjustStrings(r.value.trim(),t))||line$4;return concat$7([d,h]);case"selector-universal":return concat$7([r.namespace?concat$7([!0===r.namespace?"":r.namespace.trim(),"|"]):"",adjustNumbers(r.value)]);case"selector-pseudo":return concat$7([maybeToLowerCase(r.value),r.nodes&&r.nodes.length>0?concat$7(["(",join$5(", ",e.map(n,"nodes")),")"]):""]);case"selector-nesting":return r.value;case"selector-unknown":var m=getAncestorNode(e,"css-rule");return m&&m.isSCSSNesterProperty?adjustNumbers(adjustStrings(maybeToLowerCase(r.value),t)):r.value;case"value-value":case"value-root":return e.call(n,"group");case"value-comment":return concat$7([r.inline?"//":"/*",r.value,r.inline?"":"*/"]);case"value-comma_group":for(var g=e.getParentNode(),y=getPropOfDeclNode(e),v=y&&"value-value"===g.type&&("grid"===y||y.startsWith("grid-template")),b=getAncestorNode(e,"css-atrule"),x=b&&isSCSSControlDirectiveNode(b),C=e.map(n,"groups"),E=[],D=insideValueFunctionNode(e,"url"),w=!1,S=!1,k=0;k0&&"value-comma_group"===r.groups[0].type&&r.groups[0].groups.length>0&&"value-word"===r.groups[0].groups[0].type&&r.groups[0].groups[0].value.startsWith("data:")))return concat$7([r.open?e.call(n,"open"):"",join$5(",",e.map(n,"groups")),r.close?e.call(n,"close"):""]);if(!r.open){for(var B=e.map(n,"groups"),$=[],U=0;U0?group$3(concat$8(["(",indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3("",", "),softline$4]),e.call(function(e){return printSequence(e,t,n)},"arguments"))])),softline$4,")"])):"",printDirectives(e,n,r),r.selectionSet?" ":"",e.call(n,"selectionSet")]));case"Name":return r.value;case"StringValue":return concat$8(r.block?['"""',hardline$7,join$6(hardline$7,r.value.replace(/"""/g,"\\$&").split("\n")),hardline$7,'"""']:['"',r.value.replace(/["\\]/g,"\\$&"),'"']);case"IntValue":case"FloatValue":case"EnumValue":return r.value;case"BooleanValue":return r.value?"true":"false";case"NullValue":return"null";case"Variable":return concat$8(["$",e.call(n,"name")]);case"ListValue":return group$3(concat$8(["[",indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3("",", "),softline$4]),e.map(n,"values"))])),softline$4,"]"]));case"ObjectValue":return group$3(concat$8(["{",t.bracketSpacing&&r.fields.length>0?" ":"",indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3("",", "),softline$4]),e.map(n,"fields"))])),softline$4,ifBreak$3("",t.bracketSpacing&&r.fields.length>0?" ":""),"}"]));case"ObjectField":case"Argument":return concat$8([e.call(n,"name"),": ",e.call(n,"value")]);case"Directive":return concat$8(["@",e.call(n,"name"),r.arguments.length>0?group$3(concat$8(["(",indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3("",", "),softline$4]),e.call(function(e){return printSequence(e,t,n)},"arguments"))])),softline$4,")"])):""]);case"NamedType":return e.call(n,"name");case"VariableDefinition":return concat$8([e.call(n,"variable"),": ",e.call(n,"type"),r.defaultValue?concat$8([" = ",e.call(n,"defaultValue")]):""]);case"TypeExtensionDefinition":return concat$8(["extend ",e.call(n,"definition")]);case"ObjectTypeExtension":case"ObjectTypeDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"","ObjectTypeExtension"===r.kind?"extend ":"","type ",e.call(n,"name"),r.interfaces.length>0?concat$8([" implements ",join$6(determineInterfaceSeparator(t.originalText.substr(t.locStart(r),t.locEnd(r))),e.map(n,"interfaces"))]):"",printDirectives(e,n,r),r.fields.length>0?concat$8([" {",indent$6(concat$8([hardline$7,join$6(hardline$7,e.call(function(e){return printSequence(e,t,n)},"fields"))])),hardline$7,"}"]):""]);case"FieldDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"",e.call(n,"name"),r.arguments.length>0?group$3(concat$8(["(",indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3("",", "),softline$4]),e.call(function(e){return printSequence(e,t,n)},"arguments"))])),softline$4,")"])):"",": ",e.call(n,"type"),printDirectives(e,n,r)]);case"DirectiveDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"","directive ","@",e.call(n,"name"),r.arguments.length>0?group$3(concat$8(["(",indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3("",", "),softline$4]),e.call(function(e){return printSequence(e,t,n)},"arguments"))])),softline$4,")"])):"",concat$8([" on ",join$6(" | ",e.map(n,"locations"))])]);case"EnumTypeExtension":case"EnumTypeDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"","EnumTypeExtension"===r.kind?"extend ":"","enum ",e.call(n,"name"),printDirectives(e,n,r),r.values.length>0?concat$8([" {",indent$6(concat$8([hardline$7,join$6(hardline$7,e.call(function(e){return printSequence(e,t,n)},"values"))])),hardline$7,"}"]):""]);case"EnumValueDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"",e.call(n,"name"),printDirectives(e,n,r)]);case"InputValueDefinition":return concat$8([e.call(n,"description"),r.description?r.description.block?hardline$7:line$5:"",e.call(n,"name"),": ",e.call(n,"type"),r.defaultValue?concat$8([" = ",e.call(n,"defaultValue")]):"",printDirectives(e,n,r)]);case"InputObjectTypeExtension":case"InputObjectTypeDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"","InputObjectTypeExtension"===r.kind?"extend ":"","input ",e.call(n,"name"),printDirectives(e,n,r),r.fields.length>0?concat$8([" {",indent$6(concat$8([hardline$7,join$6(hardline$7,e.call(function(e){return printSequence(e,t,n)},"fields"))])),hardline$7,"}"]):""]);case"SchemaDefinition":return concat$8(["schema",printDirectives(e,n,r)," {",r.operationTypes.length>0?indent$6(concat$8([hardline$7,join$6(hardline$7,e.call(function(e){return printSequence(e,t,n)},"operationTypes"))])):"",hardline$7,"}"]);case"OperationTypeDefinition":return concat$8([e.call(n,"operation"),": ",e.call(n,"type")]);case"InterfaceTypeExtension":case"InterfaceTypeDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"","InterfaceTypeExtension"===r.kind?"extend ":"","interface ",e.call(n,"name"),printDirectives(e,n,r),r.fields.length>0?concat$8([" {",indent$6(concat$8([hardline$7,join$6(hardline$7,e.call(function(e){return printSequence(e,t,n)},"fields"))])),hardline$7,"}"]):""]);case"FragmentSpread":return concat$8(["...",e.call(n,"name"),printDirectives(e,n,r)]);case"InlineFragment":return concat$8(["...",r.typeCondition?concat$8([" on ",e.call(n,"typeCondition")]):"",printDirectives(e,n,r)," ",e.call(n,"selectionSet")]);case"UnionTypeExtension":case"UnionTypeDefinition":return group$3(concat$8([e.call(n,"description"),r.description?hardline$7:"",group$3(concat$8(["UnionTypeExtension"===r.kind?"extend ":"","union ",e.call(n,"name"),printDirectives(e,n,r),r.types.length>0?concat$8([" =",ifBreak$3(""," "),indent$6(concat$8([ifBreak$3(concat$8([line$5," "])),join$6(concat$8([line$5,"| "]),e.map(n,"types"))]))]):""]))]));case"ScalarTypeExtension":case"ScalarTypeDefinition":return concat$8([e.call(n,"description"),r.description?hardline$7:"","ScalarTypeExtension"===r.kind?"extend ":"","scalar ",e.call(n,"name"),printDirectives(e,n,r)]);case"NonNullType":return concat$8([e.call(n,"type"),"!"]);case"ListType":return concat$8(["[",e.call(n,"type"),"]"]);default:throw new Error("unknown graphql type: "+JSON.stringify(r.kind))}}function printDirectives(e,t,n){return 0===n.directives.length?"":concat$8([" ",group$3(indent$6(concat$8([softline$4,join$6(concat$8([ifBreak$3(""," "),softline$4]),e.map(t,"directives"))])))])}function printSequence(e,t,n){var r=e.getValue().length;return e.map(function(e,i){var o=n(e);return isNextLineEmpty$4(t.originalText,e.getValue(),t)&&i|^([-+*]|#{1,6}|[0-9]+[.)])$/.test(a.value)?"never":t.proseWrap;return printLine(e,r.value,{proseWrap:s});case"emphasis":var u=e.getParentNode(),c=u.children.indexOf(r),l=u.children[c-1],p=u.children[c+1],f=l&&"sentence"===l.type&&l.children.length>0&&"word"===util.getLast(l.children).type&&!util.getLast(l.children).hasTrailingPunctuation||p&&"sentence"===p.type&&p.children.length>0&&"word"===p.children[0].type&&!p.children[0].hasLeadingPunctuation,d=f||getAncestorNode$2(e,"emphasis")?"*":"_";return concat$9([d,printChildren(e,t,n),d]);case"strong":return concat$9(["**",printChildren(e,t,n),"**"]);case"delete":return concat$9(["~~",printChildren(e,t,n),"~~"]);case"inlineCode":var h=util.getMaxContinuousCount(r.value,"`"),m=1===h?"``":"`",g=h?" ":"";return concat$9([m,g,r.value,g,m]);case"link":switch(t.originalText[r.position.start.offset]){case"<":return concat$9(["<",r.url,">"]);case"[":return concat$9(["[",printChildren(e,t,n),"](",printUrl(r.url,")"),printTitle(r.title,t),")"]);default:return t.originalText.slice(r.position.start.offset,r.position.end.offset)}case"image":return concat$9(["![",r.alt||"","](",printUrl(r.url,")"),printTitle(r.title,t),")"]);case"blockquote":return concat$9(["> ",align$2("> ",printChildren(e,t,n))]);case"heading":return concat$9(["#".repeat(r.depth)+" ",printChildren(e,t,n)]);case"code":if(/^\n?( {4,}|\t)/.test(t.originalText.slice(r.position.start.offset,r.position.end.offset))){var y=" ".repeat(4);return align$2(y,concat$9([y,join$7(hardline$8,r.value.split("\n"))]))}var v=t.__inJsTemplate?"~":"`",b=v.repeat(Math.max(3,util.getMaxContinuousCount(r.value,v)+1));return concat$9([b,r.lang||"",hardline$8,join$7(hardline$8,r.value.split("\n")),hardline$8,b]);case"front-matter":return r.value;case"html":var x=e.getParentNode();return replaceNewlinesWithHardlines("root"===x.type&&util.getLast(x.children)===r?r.value.trimRight():r.value);case"list":var C=getNthListSiblingIndex(r,e.getParentNode()),E=r.ordered&&r.children.length>1&&/^\s*1(\.|\))/.test(t.originalText.slice(r.children[1].position.start.offset,r.children[1].position.end.offset));return printChildren(e,t,n,{processor:function(e,i){var o=function(){var n=r.ordered?(0===i?r.start:E?1:r.start+i)+(C%2===0?". ":") "):C%2===0?"- ":"* ";return e.getValue().children.length?alignListPrefix(n,t):n}();return concat$9([o,align$2(" ".repeat(o.length),printListItem(e,t,n,o))])}});case"thematicBreak":var D=getAncestorCounter$1(e,"list");if(-1===D)return"---";return getNthListSiblingIndex(e.getParentNode(D),e.getParentNode(D+1))%2===0?"***":"---";case"linkReference":return concat$9(["[",printChildren(e,t,n),"]","full"===r.referenceType?concat$9(["[",r.identifier,"]"]):"collapsed"===r.referenceType?"[]":""]);case"imageReference":switch(r.referenceType){case"full":return concat$9(["![",r.alt||"","][",r.identifier,"]"]);default:return concat$9(["![",r.alt,"]","collapsed"===r.referenceType?"[]":""])}case"definition":var w="always"===t.proseWrap?line$6:" ";return group$4(concat$9([concat$9(["[",r.identifier,"]:"]),indent$7(concat$9([w,printUrl(r.url),null===r.title?"":concat$9([w,printTitle(r.title,t,!1)])]))]));case"footnote":return concat$9(["[^",printChildren(e,t,n),"]"]);case"footnoteReference":return concat$9(["[^",r.identifier,"]"]);case"footnoteDefinition":var S=e.getParentNode().children[e.getName()+1];return concat$9(["[^",r.identifier,"]: ",group$4(concat$9([align$2(" ".repeat(t.tabWidth),printChildren(e,t,n,{processor:function(e,t){return 0===t?group$4(concat$9([softline$5,softline$5,e.call(n)])):e.call(n)}})),S&&"footnoteDefinition"===S.type?softline$5:""]))]);case"table":return printTable(e,t,n);case"tableCell":return printChildren(e,t,n);case"break":return concat$9([/\s/.test(t.originalText[r.position.start.offset])?" ":"\\",hardline$8]);case"liquidNode":return replaceNewlinesWithHardlines(r.value);case"tableRow":case"listItem":default:throw new Error("Unknown markdown type ".concat(JSON.stringify(r.type)))}}function printListItem(e,t,n,r){var i=e.getValue(),o=null===i.checked?"":i.checked?"[x] ":"[ ] ";return concat$9([o,printChildren(e,t,n,{processor:function(e,i){if(0===i&&"list"!==e.getValue().type)return align$2(" ".repeat(o.length),e.call(n));var a=" ".repeat(clamp(t.tabWidth-r.length,0,3));return concat$9([a,align$2(a,e.call(n))])}})])}function alignListPrefix(e,t){var n=function(){var n=e.length%t.tabWidth;return 0===n?0:t.tabWidth-n}();return e+" ".repeat(n>=4?0:n)}function getNthListSiblingIndex(e,t){return getNthSiblingIndex(e,t,function(t){return t.ordered===e.ordered})}function replaceNewlinesWithHardlines(e){return join$7(hardline$8,e.split("\n"))}function getNthSiblingIndex(e,t,n){n=n||function(){return!0};var r=-1,i=!0,o=!1,a=void 0;try{for(var s,u=t.children[Symbol.iterator]();!(i=(s=u.next()).done);i=!0){var c=s.value;if(c.type===e.type&&n(c)?r++:r=-1,c===e)return r}}catch(e){o=!0,a=e}finally{try{i||null==u.return||u.return()}finally{if(o)throw a}}}function getAncestorCounter$1(e,t){for(var n,r=[].concat(t),i=-1;n=e.getParentNode(++i);)if(-1!==r.indexOf(n.type))return i;return-1}function getAncestorNode$2(e,t){var n=getAncestorCounter$1(e,t);return-1===n?null:e.getParentNode(n)}function printLine(e,t,n){if("preserve"===n.proseWrap&&"\n"===t)return hardline$8;var r="always"===n.proseWrap&&!getAncestorNode$2(e,SINGLE_LINE_NODE_TYPES);return""!==t?r?line$6:" ":r?softline$5:""}function printTable(e,t,n){function r(e){return concat$9(["| ",join$7(" | ",e.map(function(e,t){switch(s.align[t]){case"right":return o(e,c[t]);case"center":return a(e,c[t]);default:return i(e,c[t])}}))," |"])}function i(e,t){return concat$9([e," ".repeat(t-util.getStringWidth(e))])}function o(e,t){return concat$9([" ".repeat(t-util.getStringWidth(e)),e])}function a(e,t){var n=t-util.getStringWidth(e),r=Math.floor(n/2),i=n-r;return concat$9([" ".repeat(r),e," ".repeat(i)])}var s=e.getValue(),u=[];e.map(function(e){var r=[];e.map(function(e){r.push(printDocToString$2(e.call(n),t).formatted)},"children"),u.push(r)},"children");var c=u.reduce(function(e,t){return e.map(function(e,n){return Math.max(e,util.getStringWidth(t[n]))})},u[0].map(function(){return 3}));return join$7(hardline$8,[r(u[0]),function(){return concat$9(["| ",join$7(" | ",c.map(function(e,t){switch(s.align[t]){case"left":return":"+"-".repeat(e-1);case"right":return"-".repeat(e-1)+":";case"center":return":"+"-".repeat(e-2)+":";default:return"-".repeat(e)}}))," |"])}(),join$7(hardline$8,u.slice(1).map(r))])}function printRoot(e,t,n){var r=[],i=null,o=e.getValue().children;return o.forEach(function(e,t){switch(isPrettierIgnore(e)){case"start":null===i&&(i={index:t,offset:e.position.end.offset});break;case"end":null!==i&&(r.push({start:i,end:{index:t,offset:e.position.start.offset}}),i=null)}}),printChildren(e,t,n,{processor:function(e,i){if(0!==r.length){var a=r[0];if(i===a.start.index)return concat$9([o[a.start.index].value,t.originalText.slice(a.start.offset,a.end.offset),o[a.end.index].value]);if(a.start.index$/);return null!==t&&(t[1]?t[1]:"next")}function shouldNotPrePrintHardline(e,t){var n=0===t.parts.length,r=-1!==INLINE_NODE_TYPES.indexOf(e.type),i="html"===e.type&&-1!==INLINE_NODE_WRAPPER_TYPES.indexOf(t.parentNode.type);return n||r||i}function shouldPrePrintDoubleHardline(e,t){var n=(t.prevNode&&t.prevNode.type)===e.type,r=n&&-1!==SIBLING_NODE_TYPES.indexOf(e.type),i="listItem"===t.parentNode.type&&!t.parentNode.loose,o=t.prevNode&&"listItem"===t.prevNode.type&&t.prevNode.loose,a="next"===isPrettierIgnore(t.prevNode);return o||!(r||i||a)}function shouldPrePrintTripleHardline(e,t){var n=t.prevNode&&"list"===t.prevNode.type,r="code"===e.type&&/\s/.test(t.options.originalText[e.position.start.offset]);return n&&r}function shouldRemainTheSameContent(e){var t=getAncestorNode$2(e,["linkReference","imageReference"]);return t&&("linkReference"!==t.type||"full"!==t.referenceType)}function normalizeDoc(e){return mapDoc$3(e,function(e){if(!e.parts)return e;if("concat"===e.type&&1===e.parts.length)return e.parts[0];var t=[];return e.parts.forEach(function(e){"concat"===e.type?t.push.apply(t,e.parts):""!==e&&t.push(e)}),Object.assign({},e,{parts:normalizeParts(t)})})}function printUrl(e,t){var n=[" "].concat(t||[]);return new RegExp(n.map(function(e){return"\\".concat(e)}).join("|")).test(e)?"<".concat(e,">"):e}function printTitle(e,t,n){if(null==n&&(n=!0),!e)return"";if(n)return" "+printTitle(e,t,!1);if(e.includes('"')&&e.includes("'")&&!e.includes(")"))return"(".concat(e,")");var r=e.split("'").length-1,i=e.split('"').length-1,o=r>i?'"':i>r?"'":t.singleQuote?"'":'"';return e=e.replace(new RegExp("(".concat(o,")"),"g"),"\\$1"),"".concat(o).concat(e).concat(o)}function normalizeParts(e){return e.reduce(function(e,t){var n=util.getLast(e);return"string"===typeof n&&"string"===typeof t?e.splice(-1,1,n+t):e.push(t),e},[])}function clamp(e,t,n){return en?n:e}function clean$6(e,t,n){if(delete t.position,"code"===e.type&&delete t.value,"whitespace"===e.type&&"\n"===e.value&&(t.value=" "),n&&"root"===n.type&&n.children.length>0&&(n.children[0]===e||"front-matter"===n.children[0].type&&n.children[1]===e)&&"html"===e.type&&pragma$2.startWithPragma(e.value))return null}function hasPrettierIgnore$1(e){var t=+e.getName();return 0!==t&&"next"===isPrettierIgnore(e.getParentNode().children[t-1])}function embed$4(e,t,n,r){var i=e.getValue(),o=e.getParentNode();if(!o||"root"!==o.tag||i.unary)return null;var a;if("style"===i.tag){var s=i.attrs.find(function(e){return"lang"===e.name});s&&"postcss"!==s.value?"scss"===s.value?a="scss":"less"===s.value&&(a="less"):a="css"}if("script"===i.tag){var u=i.attrs.find(function(e){return"lang"===e.name});u?"ts"!==u.value&&"tsx"!==u.value||(a="typescript"):a="babylon"}return a?concat$12([r.originalText.slice(i.start,i.contentStart),hardline$11,n(r.originalText.slice(i.contentStart,i.contentEnd),{parser:a}),r.originalText.slice(i.contentEnd,i.end)]):null}function genericPrint$6(e,t,n){var r=e.getValue(),i=[],o=r.start;return e.each(function(e){var r=e.getValue();i.push(t.originalText.slice(o,r.start)),i.push(e.call(n)),o=r.end},"children"),i.push(t.originalText.slice(o,r.end)),"root"===r.tag&&r.children.length&&i.push(hardline$10),concat$11(i)}function withPlugins(e){return function(){var t=Array.from(arguments),n=t[1]&&t[1].plugins||[];return isArray(n)||(n=Object.values(n)),t[1]=Object.assign({},t[1],{plugins:internalPlugins.concat(n)}),e.apply(null,t)}}var name="prettier",version$1="1.13.2",description="Prettier is an opinionated code formatter",bin={prettier:"./bin/prettier.js"},repository="prettier/prettier",homepage="https://prettier.io",author="James Long",license="MIT",main="./index.js",engines={node:">=6"},dependencies={"@babel/code-frame":"7.0.0-beta.49","@babel/parser":"7.0.0-beta.49","@glimmer/syntax":"0.30.3",camelcase:"4.1.0",chalk:"2.1.0","cjk-regex":"1.0.2",cosmiconfig:"3.1.0",dashify:"0.2.2",dedent:"0.7.0",diff:"3.2.0",editorconfig:"0.15.0","editorconfig-to-prettier":"0.0.6","emoji-regex":"6.5.1","escape-string-regexp":"1.0.5",esutils:"2.0.2","find-parent-dir":"0.3.0","find-project-root":"1.1.1","flow-parser":"0.73.0","get-stream":"3.0.0",globby:"6.1.0",graphql:"0.13.2","html-tag-names":"1.1.2",ignore:"3.3.7","jest-docblock":"22.2.2","json-stable-stringify":"1.0.1",leven:"2.1.0","lodash.uniqby":"4.7.0",mem:"1.1.0",minimatch:"3.0.4",minimist:"1.2.0",parse5:"3.0.3","postcss-less":"1.1.5","postcss-media-query-parser":"0.2.3","postcss-scss":"1.0.5","postcss-selector-parser":"2.2.3","postcss-values-parser":"1.5.0","remark-parse":"5.0.0",resolve:"1.5.0",semver:"5.4.1","string-width":"2.1.1",typescript:"2.9.0-dev.20180421","typescript-eslint-parser":"eslint/typescript-eslint-parser#2960b002746c01fb9cb15bb5f4c1e7e925c6519a","unicode-regex":"1.0.1",unified:"6.1.6"},devDependencies={"@babel/cli":"7.0.0-beta.49","@babel/core":"7.0.0-beta.49","@babel/preset-env":"7.0.0-beta.49","builtin-modules":"2.0.0",codecov:"2.2.0","cross-env":"5.0.5",eslint:"4.18.2","eslint-config-prettier":"2.9.0","eslint-friendly-formatter":"3.0.0","eslint-plugin-import":"2.9.0","eslint-plugin-prettier":"2.6.0","eslint-plugin-react":"7.7.0",jest:"21.1.0",mkdirp:"0.5.1",prettier:"1.13.0",prettylint:"1.0.0",rimraf:"2.6.2",rollup:"0.47.6","rollup-plugin-babel":"4.0.0-beta.4","rollup-plugin-commonjs":"8.2.6","rollup-plugin-json":"2.1.1","rollup-plugin-node-builtins":"2.0.0","rollup-plugin-node-globals":"1.1.0","rollup-plugin-node-resolve":"2.0.0","rollup-plugin-replace":"1.2.1","rollup-plugin-uglify":"3.0.0",shelljs:"0.8.1","snapshot-diff":"0.2.2","strip-ansi":"4.0.0",tempy:"0.2.1",webpack:"2.6.1"},scripts={prepublishOnly:'echo "Error: must publish from dist/" && exit 1',"prepare-release":"yarn && yarn build && yarn test:dist",test:"jest","test:dist":"node ./scripts/test-dist.js","test-integration":"jest tests_integration",lint:"cross-env EFF_NO_LINK_RULES=true eslint . --format node_modules/eslint-friendly-formatter","lint-docs":"prettylint {.,docs,website,website/blog}/*.md",build:"node ./scripts/build/build.js","build-docs":"node ./scripts/build-docs.js","check-deps":"node ./scripts/check-deps.js"},_package={name:name,version:version$1,description:description,bin:bin,repository:repository,homepage:homepage,author:author,license:license,main:main,engines:engines,dependencies:dependencies,devDependencies:devDependencies,scripts:scripts},_package$1=Object.freeze({name:name,version:version$1,description:description,bin:bin,repository:repository,homepage:homepage,author:author,license:license,main:main,engines:engines,dependencies:dependencies,devDependencies:devDependencies,scripts:scripts,default:_package}),commonjsGlobal="undefined"!==typeof window?window:"undefined"!==typeof global?global:"undefined"!==typeof self?self:{},base=createCommonjsModule(function(e,t){function n(){}function r(e,t,n,r,i){for(var o=0,a=t.length,s=0,u=0;oe.length?n:e}),c.value=e.join(p)}else c.value=e.join(n.slice(s,s+c.count));s+=c.count,c.added||(u+=c.count)}}var f=t[a-1];return a>1&&(f.added||f.removed)&&e.equals("",f.value)&&(t[a-2].value+=f.value,t.pop()),t}function i(e){return{newPos:e.newPos,components:e.components.slice(0)}}t.__esModule=!0,t.default=n,n.prototype={diff:function(e,t){function n(e){return s?(setTimeout(function(){s(void 0,e)},0),!0):e}function o(){for(var o=-1*p;o<=p;o+=2){var a=void 0,s=d[o-1],f=d[o+1],h=(f?f.newPos:0)-o;s&&(d[o-1]=void 0);var m=s&&s.newPos+1=c&&h+1>=l)return n(r(u,a.components,t,e,u.useLongestToken));d[o]=a}else d[o]=void 0}p++}var a=arguments.length<=2||void 0===arguments[2]?{}:arguments[2],s=a.callback;"function"===typeof a&&(s=a,a={}),this.options=a;var u=this;e=this.castInput(e),t=this.castInput(t),e=this.removeEmpty(this.tokenize(e)),t=this.removeEmpty(this.tokenize(t));var c=t.length,l=e.length,p=1,f=c+l,d=[{newPos:-1,components:[]}],h=this.extractCommon(d[0],t,e,0);if(d[0].newPos+1>=c&&h+1>=l)return n([{value:this.join(t),count:t.length}]);if(s)!function e(){setTimeout(function(){if(p>f)return s();o()||e()},0)}();else for(;p<=f;){var m=o();if(m)return m}},pushComponent:function(e,t,n){var r=e[e.length-1];r&&r.added===t&&r.removed===n?e[e.length-1]={count:r.count+1,added:t,removed:n}:e.push({count:1,added:t,removed:n})},extractCommon:function(e,t,n,r){for(var i=t.length,o=n.length,a=e.newPos,s=a-r,u=0;a+11)throw new Error("applyPatch only works with a single input.");t=t[0]}for(var r=e.split(/\r\n|[\n\v\f\r\x85]/),o=e.match(/\r\n|[\n\v\f\r\x85]/g)||[],a=t.hunks,s=n.compareLine||function(e,t,n,r){return t===r},u=0,c=n.fuzzFactor||0,l=0,p=0,f=void 0,d=void 0,h=0;hc)return!1;t++}}return!0}(m,v+y)){m.offset=p+=y;break}if(void 0===y)return!1;l=m.offset+m.oldStart+m.oldLines}for(var x=0;x0?u(g.lines.slice(-s.context)):[],p-=d.length,f-=d.length)}(a=d).push.apply(a,n(o.map(function(e){return(t.added?"+":"-")+e}))),t.added?m+=o.length:h+=o.length}else{if(p)if(o.length<=2*s.context&&e=c.length-2&&o.length<=s.context){var C=/\n$/.test(r),E=/\n$/.test(i);0!=o.length||C?C&&E||d.push("\\ No newline at end of file"):d.splice(x.oldLines,0,"\\ No newline at end of file")}l.push(x),p=0,f=0,d=[]}h+=o.length,m+=o.length}}(g);return{oldFileName:e,newFileName:t,oldHeader:o,newHeader:a,hunks:l}}function i(e,t,n,i,o,a,s){var u=r(e,t,n,i,o,a,s),c=[];e==t&&c.push("Index: "+e),c.push("==================================================================="),c.push("--- "+u.oldFileName+("undefined"===typeof u.oldHeader?"":"\t"+u.oldHeader)),c.push("+++ "+u.newFileName+("undefined"===typeof u.newHeader?"":"\t"+u.newHeader));for(var l=0;l"):i.removed&&t.push(""),t.push(r(i.value)),i.added?t.push(""):i.removed&&t.push("")}return t.join("")}function r(e){var t=e;return t=t.replace(/&/g,"&"),t=t.replace(//g,">"),t=t.replace(/"/g,""")}t.__esModule=!0,t.convertChangesToXML=n});unwrapExports(xml);var lib=createCommonjsModule(function(e,t){t.__esModule=!0,t.canonicalize=t.convertChangesToXML=t.convertChangesToDMP=t.parsePatch=t.applyPatches=t.applyPatch=t.createPatch=t.createTwoFilesPatch=t.structuredPatch=t.diffArrays=t.diffJson=t.diffCss=t.diffSentences=t.diffTrimmedLines=t.diffLines=t.diffWordsWithSpace=t.diffWords=t.diffChars=t.Diff=void 0;var n=function(e){return e&&e.__esModule?e:{default:e}}(base);t.Diff=n.default,t.diffChars=character.diffChars,t.diffWords=word.diffWords,t.diffWordsWithSpace=word.diffWordsWithSpace,t.diffLines=line.diffLines,t.diffTrimmedLines=line.diffTrimmedLines,t.diffSentences=sentence.diffSentences,t.diffCss=css.diffCss,t.diffJson=json.diffJson,t.diffArrays=array.diffArrays,t.structuredPatch=create.structuredPatch,t.createTwoFilesPatch=create.createTwoFilesPatch,t.createPatch=create.createPatch,t.applyPatch=apply.applyPatch,t.applyPatches=apply.applyPatches,t.parsePatch=parse.parsePatch,t.convertChangesToDMP=dmp.convertChangesToDMP,t.convertChangesToXML=xml.convertChangesToXML,t.canonicalize=json.canonicalize});unwrapExports(lib);var ConfigError=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,_getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),t}(_wrapNativeSuper(Error)),DebugError=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,_getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),t}(_wrapNativeSuper(Error)),UndefinedParserError$1=function(e){function t(){return _classCallCheck(this,t),_possibleConstructorReturn(this,_getPrototypeOf(t).apply(this,arguments))}return _inherits(t,e),t}(_wrapNativeSuper(Error)),errors={ConfigError:ConfigError,DebugError:DebugError,UndefinedParserError:UndefinedParserError$1},global$1="undefined"!==typeof global?global:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{},cachedSetTimeout=defaultSetTimout,cachedClearTimeout=defaultClearTimeout;"function"===typeof global$1.setTimeout&&(cachedSetTimeout=setTimeout),"function"===typeof global$1.clearTimeout&&(cachedClearTimeout=clearTimeout);var queue=[],draining=!1,currentQueue,queueIndex=-1;Item.prototype.run=function(){this.fun.apply(null,this.array)};var title="browser",platform="browser",browser=!0,env={},argv=[],version$2="",versions={},release={},config={},on=noop,addListener=noop,once=noop,off=noop,removeListener=noop,removeAllListeners=noop,emit=noop,performance=global$1.performance||{},performanceNow=performance.now||performance.mozNow||performance.msNow||performance.oNow||performance.webkitNow||function(){return(new Date).getTime()},startTime=new Date,process={nextTick:nextTick,title:title,browser:browser,env:env,argv:argv,version:version$2,versions:versions,on:on,addListener:addListener,once:once,off:off,removeListener:removeListener,removeAllListeners:removeAllListeners,emit:emit,binding:binding,cwd:cwd,chdir:chdir,umask:umask,hrtime:hrtime,platform:platform,release:release,config:config,uptime:uptime},semver=createCommonjsModule(function(e,t){function n(e,t){if(e instanceof o)return e;if("string"!==typeof e)return null;if(e.length>K)return null;if(!(t?Y[he]:Y[pe]).test(e))return null;try{return new o(e,t)}catch(e){return null}}function r(e,t){var r=n(e,t);return r?r.version:null}function i(e,t){var r=n(e.trim().replace(/^[=v]+/,""),t);return r?r.version:null}function o(e,t){if(e instanceof o){if(e.loose===t)return e;e=e.version}else if("string"!==typeof e)throw new TypeError("Invalid Version: "+e);if(e.length>K)throw new TypeError("version is longer than "+K+" characters");if(!(this instanceof o))return new o(e,t);Q("SemVer",e,t),this.loose=t;var n=e.trim().match(t?Y[he]:Y[pe]);if(!n)throw new TypeError("Invalid Version: "+e);if(this.raw=e,this.major=+n[1],this.minor=+n[2],this.patch=+n[3],this.major>J||this.major<0)throw new TypeError("Invalid major version");if(this.minor>J||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>J||this.patch<0)throw new TypeError("Invalid patch version");n[4]?this.prerelease=n[4].split(".").map(function(e){if(/^[0-9]+$/.test(e)){var t=+e;if(t>=0&&tt?1:0}function c(e,t){return u(t,e)}function l(e,t){return new o(e,t).major}function p(e,t){return new o(e,t).minor}function f(e,t){return new o(e,t).patch}function d(e,t,n){return new o(e,n).compare(new o(t,n))}function h(e,t){return d(e,t,!0)}function m(e,t,n){return d(t,e,n)}function g(e,n){return e.sort(function(e,r){return t.compare(e,r,n)})}function y(e,n){return e.sort(function(e,r){return t.rcompare(e,r,n)})}function v(e,t,n){return d(e,t,n)>0}function b(e,t,n){return d(e,t,n)<0}function x(e,t,n){return 0===d(e,t,n)}function C(e,t,n){return 0!==d(e,t,n)}function E(e,t,n){return d(e,t,n)>=0}function D(e,t,n){return d(e,t,n)<=0}function w(e,t,n,r){var i;switch(t){case"===":"object"===_typeof(e)&&(e=e.version),"object"===_typeof(n)&&(n=n.version),i=e===n;break;case"!==":"object"===_typeof(e)&&(e=e.version),"object"===_typeof(n)&&(n=n.version),i=e!==n;break;case"":case"=":case"==":i=x(e,n,r);break;case"!=":i=C(e,n,r);break;case">":i=v(e,n,r);break;case">=":i=E(e,n,r);break;case"<":i=b(e,n,r);break;case"<=":i=D(e,n,r);break;default:throw new TypeError("Invalid operator: "+t)}return i}function S(e,t){if(e instanceof S){if(e.loose===t)return e;e=e.value}if(!(this instanceof S))return new S(e,t);Q("comparator",e,t),this.loose=t,this.parse(e),this.semver===Re?this.value="":this.value=this.operator+this.semver.version,Q("comp",this)}function k(e,t){if(e instanceof k)return e.loose===t?e:new k(e.raw,t);if(e instanceof S)return new k(e.value,t);if(!(this instanceof k))return new k(e,t);if(this.loose=t,this.raw=e,this.set=e.split(/\s*\|\|\s*/).map(function(e){return this.parseRange(e.trim())},this).filter(function(e){return e.length}),!this.set.length)throw new TypeError("Invalid SemVer Range: "+e);this.format()}function A(e,t){return new k(e,t).set.map(function(e){return e.map(function(e){return e.value}).join(" ").trim().split(" ")})}function _(e,t){return Q("comp",e),e=N(e,t),Q("caret",e),e=O(e,t),Q("tildes",e),e=L(e,t),Q("xrange",e),e=M(e,t),Q("stars",e),e}function T(e){return!e||"x"===e.toLowerCase()||"*"===e}function O(e,t){return e.trim().split(/\s+/).map(function(e){return F(e,t)}).join(" ")}function F(e,t){var n=t?Y[Se]:Y[we];return e.replace(n,function(t,n,r,i,o){Q("tilde",e,t,n,r,i,o);var a;return T(n)?a="":T(r)?a=">="+n+".0.0 <"+(+n+1)+".0.0":T(i)?a=">="+n+"."+r+".0 <"+n+"."+(+r+1)+".0":o?(Q("replaceTilde pr",o),"-"!==o.charAt(0)&&(o="-"+o),a=">="+n+"."+r+"."+i+o+" <"+n+"."+(+r+1)+".0"):a=">="+n+"."+r+"."+i+" <"+n+"."+(+r+1)+".0",Q("tilde return",a),a})}function N(e,t){return e.trim().split(/\s+/).map(function(e){return I(e,t)}).join(" ")}function I(e,t){Q("caret",e,t);var n=t?Y[Te]:Y[_e];return e.replace(n,function(t,n,r,i,o){Q("caret",e,t,n,r,i,o);var a;return T(n)?a="":T(r)?a=">="+n+".0.0 <"+(+n+1)+".0.0":T(i)?a="0"===n?">="+n+"."+r+".0 <"+n+"."+(+r+1)+".0":">="+n+"."+r+".0 <"+(+n+1)+".0.0":o?(Q("replaceCaret pr",o),"-"!==o.charAt(0)&&(o="-"+o),a="0"===n?"0"===r?">="+n+"."+r+"."+i+o+" <"+n+"."+r+"."+(+i+1):">="+n+"."+r+"."+i+o+" <"+n+"."+(+r+1)+".0":">="+n+"."+r+"."+i+o+" <"+(+n+1)+".0.0"):(Q("no pr"),a="0"===n?"0"===r?">="+n+"."+r+"."+i+" <"+n+"."+r+"."+(+i+1):">="+n+"."+r+"."+i+" <"+n+"."+(+r+1)+".0":">="+n+"."+r+"."+i+" <"+(+n+1)+".0.0"),Q("caret return",a),a})}function L(e,t){return Q("replaceXRanges",e,t),e.split(/\s+/).map(function(e){return P(e,t)}).join(" ")}function P(e,t){e=e.trim();var n=t?Y[Ce]:Y[xe];return e.replace(n,function(t,n,r,i,o,a){Q("xRange",e,t,n,r,i,o,a);var s=T(r),u=s||T(i),c=u||T(o),l=c;return"="===n&&l&&(n=""),s?t=">"===n||"<"===n?"<0.0.0":"*":n&&l?(u&&(i=0),c&&(o=0),">"===n?(n=">=",u?(r=+r+1,i=0,o=0):c&&(i=+i+1,o=0)):"<="===n&&(n="<",u?r=+r+1:i=+i+1),t=n+r+"."+i+"."+o):u?t=">="+r+".0.0 <"+(+r+1)+".0.0":c&&(t=">="+r+"."+i+".0 <"+r+"."+(+i+1)+".0"),Q("xRange return",t),t})}function M(e,t){return Q("replaceStars",e,t),e.trim().replace(Y[Pe],"")}function j(e,t,n,r,i,o,a,s,u,c,l,p,f){return t=T(n)?"":T(r)?">="+n+".0.0":T(i)?">="+n+"."+r+".0":">="+t,s=T(u)?"":T(c)?"<"+(+u+1)+".0.0":T(l)?"<"+u+"."+(+c+1)+".0":p?"<="+u+"."+c+"."+l+"-"+p:"<="+s,(t+" "+s).trim()}function R(e,t){for(var n=0;n0){var r=e[n].semver;if(r.major===t.major&&r.minor===t.minor&&r.patch===t.patch)return!0}return!1}return!0}function B(e,t,n){try{t=new k(t,n)}catch(e){return!1}return t.test(e)}function $(e,t,n){var r=null,i=null;try{var a=new k(t,n)}catch(e){return null}return e.forEach(function(e){a.test(e)&&(r&&-1!==i.compare(e)||(r=e,i=new o(r,n)))}),r}function U(e,t,n){var r=null,i=null;try{var a=new k(t,n)}catch(e){return null}return e.forEach(function(e){a.test(e)&&(r&&1!==i.compare(e)||(r=e,i=new o(r,n)))}),r}function z(e,t){try{return new k(e,t).range||"*"}catch(e){return null}}function G(e,t,n){return q(e,t,"<",n)}function V(e,t,n){return q(e,t,">",n)}function q(e,t,n,r){e=new o(e,r),t=new k(t,r);var i,a,s,u,c;switch(n){case">":i=v,a=D,s=b,u=">",c=">=";break;case"<":i=b,a=E,s=v,u="<",c="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(B(e,t,r))return!1;for(var l=0;l=0.0.0")),f=f||e,d=d||e,i(e.semver,f.semver,r)?f=e:s(e.semver,d.semver,r)&&(d=e)}),f.operator===u||f.operator===c)return!1;if((!d.operator||d.operator===u)&&a(e,d.semver))return!1;if(d.operator===c&&s(e,d.semver))return!1}return!0}function H(e,t){var r=n(e,t);return r&&r.prerelease.length?r.prerelease:null}function W(e,t,n){return e=new k(e,n),t=new k(t,n),e.intersects(t)}t=e.exports=o;var Q;Q="object"===_typeof(process)&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var e=Array.prototype.slice.call(arguments,0);e.unshift("SEMVER"),console.log.apply(console,e)}:function(){},t.SEMVER_SPEC_VERSION="2.0.0";var K=256,J=Number.MAX_SAFE_INTEGER||9007199254740991,Y=t.re=[],X=t.src=[],Z=0,ee=Z++;X[ee]="0|[1-9]\\d*";var te=Z++;X[te]="[0-9]+";var ne=Z++;X[ne]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var re=Z++;X[re]="("+X[ee]+")\\.("+X[ee]+")\\.("+X[ee]+")";var ie=Z++;X[ie]="("+X[te]+")\\.("+X[te]+")\\.("+X[te]+")";var oe=Z++;X[oe]="(?:"+X[ee]+"|"+X[ne]+")";var ae=Z++;X[ae]="(?:"+X[te]+"|"+X[ne]+")";var se=Z++;X[se]="(?:-("+X[oe]+"(?:\\."+X[oe]+")*))";var ue=Z++;X[ue]="(?:-?("+X[ae]+"(?:\\."+X[ae]+")*))";var ce=Z++;X[ce]="[0-9A-Za-z-]+";var le=Z++;X[le]="(?:\\+("+X[ce]+"(?:\\."+X[ce]+")*))";var pe=Z++,fe="v?"+X[re]+X[se]+"?"+X[le]+"?";X[pe]="^"+fe+"$";var de="[v=\\s]*"+X[ie]+X[ue]+"?"+X[le]+"?",he=Z++;X[he]="^"+de+"$";var me=Z++;X[me]="((?:<|>)?=?)";var ge=Z++;X[ge]=X[te]+"|x|X|\\*";var ye=Z++;X[ye]=X[ee]+"|x|X|\\*";var ve=Z++;X[ve]="[v=\\s]*("+X[ye]+")(?:\\.("+X[ye]+")(?:\\.("+X[ye]+")(?:"+X[se]+")?"+X[le]+"?)?)?";var be=Z++;X[be]="[v=\\s]*("+X[ge]+")(?:\\.("+X[ge]+")(?:\\.("+X[ge]+")(?:"+X[ue]+")?"+X[le]+"?)?)?";var xe=Z++;X[xe]="^"+X[me]+"\\s*"+X[ve]+"$";var Ce=Z++;X[Ce]="^"+X[me]+"\\s*"+X[be]+"$";var Ee=Z++;X[Ee]="(?:~>?)";var De=Z++;X[De]="(\\s*)"+X[Ee]+"\\s+",Y[De]=new RegExp(X[De],"g");var we=Z++;X[we]="^"+X[Ee]+X[ve]+"$";var Se=Z++;X[Se]="^"+X[Ee]+X[be]+"$";var ke=Z++;X[ke]="(?:\\^)";var Ae=Z++;X[Ae]="(\\s*)"+X[ke]+"\\s+",Y[Ae]=new RegExp(X[Ae],"g");var _e=Z++;X[_e]="^"+X[ke]+X[ve]+"$";var Te=Z++;X[Te]="^"+X[ke]+X[be]+"$";var Oe=Z++;X[Oe]="^"+X[me]+"\\s*("+de+")$|^$";var Fe=Z++;X[Fe]="^"+X[me]+"\\s*("+fe+")$|^$";var Ne=Z++;X[Ne]="(\\s*)"+X[me]+"\\s*("+de+"|"+X[ve]+")",Y[Ne]=new RegExp(X[Ne],"g");var Ie=Z++;X[Ie]="^\\s*("+X[ve]+")\\s+-\\s+("+X[ve]+")\\s*$";var Le=Z++;X[Le]="^\\s*("+X[be]+")\\s+-\\s+("+X[be]+")\\s*$";var Pe=Z++;X[Pe]="(<|>)?=?\\s*\\*";for(var Me=0;Me=0;)"number"===typeof this.prerelease[n]&&(this.prerelease[n]++,n=-2);-1===n&&this.prerelease.push(0)}t&&(this.prerelease[0]===t?isNaN(this.prerelease[1])&&(this.prerelease=[t,0]):this.prerelease=[t,0]);break;default:throw new Error("invalid increment argument: "+e)}return this.format(),this.raw=this.version,this},t.inc=a,t.diff=s,t.compareIdentifiers=u;var je=/^[0-9]+$/;t.rcompareIdentifiers=c,t.major=l,t.minor=p,t.patch=f,t.compare=d,t.compareLoose=h,t.rcompare=m,t.sort=g,t.rsort=y,t.gt=v,t.lt=b,t.eq=x,t.neq=C,t.gte=E,t.lte=D,t.cmp=w,t.Comparator=S;var Re={};S.prototype.parse=function(e){var t=this.loose?Y[Oe]:Y[Fe],n=e.match(t);if(!n)throw new TypeError("Invalid comparator: "+e);this.operator=n[1],"="===this.operator&&(this.operator=""),n[2]?this.semver=new o(n[2],this.loose):this.semver=Re},S.prototype.toString=function(){return this.value},S.prototype.test=function(e){return Q("Comparator.test",e,this.loose),this.semver===Re||("string"===typeof e&&(e=new o(e,this.loose)),w(e,this.operator,this.semver,this.loose))},S.prototype.intersects=function(e,t){if(!(e instanceof S))throw new TypeError("a Comparator is required");var n;if(""===this.operator)return n=new k(e.value,t),B(this.value,n,t);if(""===e.operator)return n=new k(this.value,t),B(e.semver,n,t);var r=(">="===this.operator||">"===this.operator)&&(">="===e.operator||">"===e.operator),i=("<="===this.operator||"<"===this.operator)&&("<="===e.operator||"<"===e.operator),o=this.semver.version===e.semver.version,a=(">="===this.operator||"<="===this.operator)&&(">="===e.operator||"<="===e.operator),s=w(this.semver,"<",e.semver,t)&&(">="===this.operator||">"===this.operator)&&("<="===e.operator||"<"===e.operator),u=w(this.semver,">",e.semver,t)&&("<="===this.operator||"<"===this.operator)&&(">="===e.operator||">"===e.operator);return r||i||o&&a||s||u},t.Range=k,k.prototype.format=function(){return this.range=this.set.map(function(e){return e.join(" ").trim()}).join("||").trim(),this.range},k.prototype.toString=function(){return this.range},k.prototype.parseRange=function(e){var t=this.loose;e=e.trim(),Q("range",e,t);var n=t?Y[Le]:Y[Ie];e=e.replace(n,j),Q("hyphen replace",e),e=e.replace(Y[Ne],"$1$2$3"),Q("comparator trim",e,Y[Ne]),e=e.replace(Y[De],"$1~"),e=e.replace(Y[Ae],"$1^"),e=e.split(/\s+/).join(" ");var r=t?Y[Oe]:Y[Fe],i=e.split(" ").map(function(e){return _(e,t)}).join(" ").split(/\s+/);return this.loose&&(i=i.filter(function(e){return!!e.match(r)})),i=i.map(function(e){return new S(e,t)})},k.prototype.intersects=function(e,t){if(!(e instanceof k))throw new TypeError("a Range is required");return this.set.some(function(n){return n.every(function(n){return e.set.some(function(e){return e.every(function(e){return n.intersects(e,t)})})})})},t.toComparators=A,k.prototype.test=function(e){if(!e)return!1;"string"===typeof e&&(e=new o(e,this.loose));for(var t=0;tt.length&&(e=t,t=n);var r=e.length,i=t.length;if(0===r)return i;if(0===i)return r;for(;r>0&&e.charCodeAt(~-r)===t.charCodeAt(~-i);)r--,i--;if(0===r)return i;for(var o=0;os?c>s?s+1:c:c>u?u+1:c;return s},optionsDescriptor={apiDescriptor:apiDescriptor,cliDescriptor:cliDescriptor},optionsValidator={validateOption:validateOption},optionsNormalizer={normalizeApiOptions:normalizeApiOptions,normalizeCliOptions:normalizeCliOptions},getLast=function(e){return e.length>0?e[e.length-1]:null},loc={locStart:locStart$1,locEnd:locEnd$1},jsTokens=createCommonjsModule(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=/((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g,t.matchToToken=function(e){var t={type:"invalid",value:e[0]};return e[1]?(t.type="string",t.closed=!(!e[3]&&!e[4])):e[5]?t.type="comment":e[6]?(t.type="comment",t.closed=!!e[7]):e[8]?t.type="regex":e[9]?t.type="number":e[10]?t.type="name":e[11]?t.type="punctuator":e[12]&&(t.type="whitespace"),t}});unwrapExports(jsTokens);var ast=createCommonjsModule(function(e){!function(){function t(e){if(null==e)return!1;switch(e.type){case"ArrayExpression":case"AssignmentExpression":case"BinaryExpression":case"CallExpression":case"ConditionalExpression":case"FunctionExpression":case"Identifier":case"Literal":case"LogicalExpression":case"MemberExpression":case"NewExpression":case"ObjectExpression":case"SequenceExpression":case"ThisExpression":case"UnaryExpression":case"UpdateExpression":return!0}return!1}function n(e){if(null==e)return!1;switch(e.type){case"DoWhileStatement":case"ForInStatement":case"ForStatement":case"WhileStatement":return!0}return!1}function r(e){if(null==e)return!1;switch(e.type){case"BlockStatement":case"BreakStatement":case"ContinueStatement":case"DebuggerStatement":case"DoWhileStatement":case"EmptyStatement":case"ExpressionStatement":case"ForInStatement":case"ForStatement":case"IfStatement":case"LabeledStatement":case"ReturnStatement":case"SwitchStatement":case"ThrowStatement":case"TryStatement":case"VariableDeclaration":case"WhileStatement":case"WithStatement":return!0}return!1}function i(e){return r(e)||null!=e&&"FunctionDeclaration"===e.type}function o(e){switch(e.type){case"IfStatement":return null!=e.alternate?e.alternate:e.consequent;case"LabeledStatement":case"ForStatement":case"ForInStatement":case"WhileStatement":case"WithStatement":return e.body}return null}function a(e){var t;if("IfStatement"!==e.type)return!1;if(null==e.alternate)return!1;t=e.consequent;do{if("IfStatement"===t.type&&null==t.alternate)return!0;t=o(t)}while(t);return!1}e.exports={isExpression:t,isStatement:r,isIterationStatement:n,isSourceElement:i,isProblematicIfStatement:a,trailingStatement:o}}()}),code=createCommonjsModule(function(e){!function(){function t(e){return 48<=e&&e<=57}function n(e){return 48<=e&&e<=57||97<=e&&e<=102||65<=e&&e<=70}function r(e){return e>=48&&e<=55}function i(e){return 32===e||9===e||11===e||12===e||160===e||e>=5760&&d.indexOf(e)>=0}function o(e){return 10===e||13===e||8232===e||8233===e}function a(e){return e<=65535?String.fromCharCode(e):String.fromCharCode(Math.floor((e-65536)/1024)+55296)+String.fromCharCode((e-65536)%1024+56320)}function s(e){return e<128?h[e]:f.NonAsciiIdentifierStart.test(a(e))}function u(e){return e<128?m[e]:f.NonAsciiIdentifierPart.test(a(e))}function c(e){return e<128?h[e]:p.NonAsciiIdentifierStart.test(a(e))}function l(e){return e<128?m[e]:p.NonAsciiIdentifierPart.test(a(e))}var p,f,d,h,m,g;for(f={NonAsciiIdentifierStart:/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/,NonAsciiIdentifierPart:/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19D9\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u2E2F\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099\u309A\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/},p={NonAsciiIdentifierStart:/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B2\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDE00-\uDE11\uDE13-\uDE2B\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDE00-\uDE2F\uDE44\uDE80-\uDEAA]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]/,NonAsciiIdentifierPart:/[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B2\u08E4-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58\u0C59\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D60-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA69D\uA69F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA7AD\uA7B0\uA7B1\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB5F\uAB64\uAB65\uABC0-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2D\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDD0-\uDDDA\uDE00-\uDE11\uDE13-\uDE37\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF01-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF98]|\uD809[\uDC00-\uDC6E]|[\uD80C\uD840-\uD868\uD86A-\uD86C][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/},d=[5760,6158,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279],h=new Array(128),g=0;g<128;++g)h[g]=g>=97&&g<=122||g>=65&&g<=90||36===g||95===g;for(m=new Array(128),g=0;g<128;++g)m[g]=g>=97&&g<=122||g>=65&&g<=90||g>=48&&g<=57||36===g||95===g;e.exports={isDecimalDigit:t,isHexDigit:n,isOctalDigit:r,isWhiteSpace:i,isLineTerminator:o,isIdentifierStartES5:s,isIdentifierPartES5:u,isIdentifierStartES6:c,isIdentifierPartES6:l}}()}),keyword=createCommonjsModule(function(e){!function(){function t(e){switch(e){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"let":return!0;default:return!1}}function n(e,t){return!(!t&&"yield"===e)&&r(e,t)}function r(e,n){if(n&&t(e))return!0;switch(e.length){case 2:return"if"===e||"in"===e||"do"===e;case 3:return"var"===e||"for"===e||"new"===e||"try"===e;case 4:return"this"===e||"else"===e||"case"===e||"void"===e||"with"===e||"enum"===e;case 5:return"while"===e||"break"===e||"catch"===e||"throw"===e||"const"===e||"yield"===e||"class"===e||"super"===e;case 6:return"return"===e||"typeof"===e||"delete"===e||"switch"===e||"export"===e||"import"===e;case 7:return"default"===e||"finally"===e||"extends"===e;case 8:return"function"===e||"continue"===e||"debugger"===e;case 10:return"instanceof"===e;default:return!1}}function i(e,t){return"null"===e||"true"===e||"false"===e||n(e,t)}function o(e,t){return"null"===e||"true"===e||"false"===e||r(e,t)}function a(e){return"eval"===e||"arguments"===e}function s(e){var t,n,r;if(0===e.length)return!1;if(r=e.charCodeAt(0),!f.isIdentifierStartES5(r))return!1;for(t=1,n=e.length;t=n)return!1;if(!(56320<=(i=e.charCodeAt(t))&&i<=57343))return!1;r=u(r,i)}if(!o(r))return!1;o=f.isIdentifierPartES6}return!0}function l(e,t){return s(e)&&!i(e,t)}function p(e,t){return c(e)&&!o(e,t)}var f=code;e.exports={isKeywordES5:n,isKeywordES6:r,isReservedWordES5:i,isReservedWordES6:o,isRestrictedWord:a,isIdentifierNameES5:s,isIdentifierNameES6:c,isIdentifierES5:l,isIdentifierES6:p}}()}),utils=createCommonjsModule(function(e,t){!function(){t.ast=ast,t.code=code,t.keyword=keyword}()}),matchOperatorsRe=/[|\\{}()[\]^$+*?.]/g,escapeStringRegexp=function(e){if("string"!==typeof e)throw new TypeError("Expected a string");return e.replace(matchOperatorsRe,"\\$&")},colorName={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},conversions=createCommonjsModule(function(e){function t(e,t){return Math.pow(e[0]-t[0],2)+Math.pow(e[1]-t[1],2)+Math.pow(e[2]-t[2],2)}var n={};for(var r in colorName)colorName.hasOwnProperty(r)&&(n[colorName[r]]=r);var i=e.exports={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};for(var o in i)if(i.hasOwnProperty(o)){if(!("channels"in i[o]))throw new Error("missing channels property: "+o);if(!("labels"in i[o]))throw new Error("missing channel labels property: "+o);if(i[o].labels.length!==i[o].channels)throw new Error("channel and label counts mismatch: "+o);var a=i[o].channels,s=i[o].labels;delete i[o].channels,delete i[o].labels,Object.defineProperty(i[o],"channels",{value:a}),Object.defineProperty(i[o],"labels",{value:s})}i.rgb.hsl=function(e){var t,n,r,i=e[0]/255,o=e[1]/255,a=e[2]/255,s=Math.min(i,o,a),u=Math.max(i,o,a),c=u-s;return u===s?t=0:i===u?t=(o-a)/c:o===u?t=2+(a-i)/c:a===u&&(t=4+(i-o)/c),t=Math.min(60*t,360),t<0&&(t+=360),r=(s+u)/2,n=u===s?0:r<=.5?c/(u+s):c/(2-u-s),[t,100*n,100*r]},i.rgb.hsv=function(e){var t,n,r,i=e[0],o=e[1],a=e[2],s=Math.min(i,o,a),u=Math.max(i,o,a),c=u-s;return n=0===u?0:c/u*1e3/10,u===s?t=0:i===u?t=(o-a)/c:o===u?t=2+(a-i)/c:a===u&&(t=4+(i-o)/c),t=Math.min(60*t,360),t<0&&(t+=360),r=u/255*1e3/10,[t,n,r]},i.rgb.hwb=function(e){var t=e[0],n=e[1],r=e[2],o=i.rgb.hsl(e)[0],a=1/255*Math.min(t,Math.min(n,r));return r=1-1/255*Math.max(t,Math.max(n,r)),[o,100*a,100*r]},i.rgb.cmyk=function(e){var t,n,r,i,o=e[0]/255,a=e[1]/255,s=e[2]/255;return i=Math.min(1-o,1-a,1-s),t=(1-o-i)/(1-i)||0,n=(1-a-i)/(1-i)||0,r=(1-s-i)/(1-i)||0,[100*t,100*n,100*r,100*i]},i.rgb.keyword=function(e){var r=n[e];if(r)return r;var i,o=1/0;for(var a in colorName)if(colorName.hasOwnProperty(a)){var s=colorName[a],u=t(e,s);u.04045?Math.pow((t+.055)/1.055,2.4):t/12.92,n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92,r=r>.04045?Math.pow((r+.055)/1.055,2.4):r/12.92,[100*(.4124*t+.3576*n+.1805*r),100*(.2126*t+.7152*n+.0722*r),100*(.0193*t+.1192*n+.9505*r)]},i.rgb.lab=function(e){var t,n,r,o=i.rgb.xyz(e),a=o[0],s=o[1],u=o[2];return a/=95.047,s/=100,u/=108.883,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,s=s>.008856?Math.pow(s,1/3):7.787*s+16/116,u=u>.008856?Math.pow(u,1/3):7.787*u+16/116,t=116*s-16,n=500*(a-s),r=200*(s-u),[t,n,r]},i.hsl.rgb=function(e){var t,n,r,i,o,a=e[0]/360,s=e[1]/100,u=e[2]/100;if(0===s)return o=255*u,[o,o,o];n=u<.5?u*(1+s):u+s-u*s,t=2*u-n,i=[0,0,0];for(var c=0;c<3;c++)r=a+1/3*-(c-1),r<0&&r++,r>1&&r--,o=6*r<1?t+6*(n-t)*r:2*r<1?n:3*r<2?t+(n-t)*(2/3-r)*6:t,i[c]=255*o;return i},i.hsl.hsv=function(e){var t,n,r=e[0],i=e[1]/100,o=e[2]/100,a=i,s=Math.max(o,.01);return o*=2,i*=o<=1?o:2-o,a*=s<=1?s:2-s,n=(o+i)/2,t=0===o?2*a/(s+a):2*i/(o+i),[r,100*t,100*n]},i.hsv.rgb=function(e){var t=e[0]/60,n=e[1]/100,r=e[2]/100,i=Math.floor(t)%6,o=t-Math.floor(t),a=255*r*(1-n),s=255*r*(1-n*o),u=255*r*(1-n*(1-o));switch(r*=255,i){case 0:return[r,u,a];case 1:return[s,r,a];case 2:return[a,r,u];case 3:return[a,s,r];case 4:return[u,a,r];case 5:return[r,a,s]}},i.hsv.hsl=function(e){var t,n,r,i=e[0],o=e[1]/100,a=e[2]/100,s=Math.max(a,.01);return r=(2-o)*a,t=(2-o)*s,n=o*s,n/=t<=1?t:2-t,n=n||0,r/=2,[i,100*n,100*r]},i.hwb.rgb=function(e){var t,n,r,i,o=e[0]/360,a=e[1]/100,s=e[2]/100,u=a+s;u>1&&(a/=u,s/=u),t=Math.floor(6*o),n=1-s,r=6*o-t,0!==(1&t)&&(r=1-r),i=a+r*(n-a);var c,l,p;switch(t){default:case 6:case 0:c=n,l=i,p=a;break;case 1:c=i,l=n,p=a;break;case 2:c=a,l=n,p=i;break;case 3:c=a,l=i,p=n;break;case 4:c=i,l=a,p=n;break;case 5:c=n,l=a,p=i}return[255*c,255*l,255*p]},i.cmyk.rgb=function(e){var t,n,r,i=e[0]/100,o=e[1]/100,a=e[2]/100,s=e[3]/100;return t=1-Math.min(1,i*(1-s)+s),n=1-Math.min(1,o*(1-s)+s),r=1-Math.min(1,a*(1-s)+s),[255*t,255*n,255*r]},i.xyz.rgb=function(e){var t,n,r,i=e[0]/100,o=e[1]/100,a=e[2]/100;return t=3.2406*i+-1.5372*o+-.4986*a,n=-.9689*i+1.8758*o+.0415*a,r=.0557*i+-.204*o+1.057*a,t=t>.0031308?1.055*Math.pow(t,1/2.4)-.055:12.92*t,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:12.92*n,r=r>.0031308?1.055*Math.pow(r,1/2.4)-.055:12.92*r,t=Math.min(Math.max(0,t),1),n=Math.min(Math.max(0,n),1),r=Math.min(Math.max(0,r),1),[255*t,255*n,255*r]},i.xyz.lab=function(e){var t,n,r,i=e[0],o=e[1],a=e[2];return i/=95.047,o/=100,a/=108.883,i=i>.008856?Math.pow(i,1/3):7.787*i+16/116,o=o>.008856?Math.pow(o,1/3):7.787*o+16/116,a=a>.008856?Math.pow(a,1/3):7.787*a+16/116,t=116*o-16,n=500*(i-o),r=200*(o-a),[t,n,r]},i.lab.xyz=function(e){var t,n,r,i=e[0],o=e[1],a=e[2];n=(i+16)/116,t=o/500+n,r=n-a/200;var s=Math.pow(n,3),u=Math.pow(t,3),c=Math.pow(r,3);return n=s>.008856?s:(n-16/116)/7.787,t=u>.008856?u:(t-16/116)/7.787,r=c>.008856?c:(r-16/116)/7.787,t*=95.047,n*=100,r*=108.883,[t,n,r]},i.lab.lch=function(e){var t,n,r,i=e[0],o=e[1],a=e[2];return t=Math.atan2(a,o),n=360*t/2/Math.PI,n<0&&(n+=360),r=Math.sqrt(o*o+a*a),[i,r,n]},i.lch.lab=function(e){var t,n,r,i=e[0],o=e[1],a=e[2];return r=a/360*2*Math.PI,t=o*Math.cos(r),n=o*Math.sin(r),[i,t,n]},i.rgb.ansi16=function(e){var t=e[0],n=e[1],r=e[2],o=1 in arguments?arguments[1]:i.rgb.hsv(e)[2];if(0===(o=Math.round(o/50)))return 30;var a=30+(Math.round(r/255)<<2|Math.round(n/255)<<1|Math.round(t/255));return 2===o&&(a+=60),a},i.hsv.ansi16=function(e){return i.rgb.ansi16(i.hsv.rgb(e),e[2])},i.rgb.ansi256=function(e){var t=e[0],n=e[1],r=e[2];return t===n&&n===r?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(n/255*5)+Math.round(r/255*5)},i.ansi16.rgb=function(e){var t=e%10;if(0===t||7===t)return e>50&&(t+=3.5),t=t/10.5*255,[t,t,t];var n=.5*(1+~~(e>50));return[(1&t)*n*255,(t>>1&1)*n*255,(t>>2&1)*n*255]},i.ansi256.rgb=function(e){if(e>=232){var t=10*(e-232)+8;return[t,t,t]}e-=16;var n;return[Math.floor(e/36)/5*255,Math.floor((n=e%36)/6)/5*255,n%6/5*255]},i.rgb.hex=function(e){var t=((255&Math.round(e[0]))<<16)+((255&Math.round(e[1]))<<8)+(255&Math.round(e[2])),n=t.toString(16).toUpperCase();return"000000".substring(n.length)+n},i.hex.rgb=function(e){var t=e.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!t)return[0,0,0];var n=t[0];3===t[0].length&&(n=n.split("").map(function(e){return e+e}).join(""));var r=parseInt(n,16);return[r>>16&255,r>>8&255,255&r]},i.rgb.hcg=function(e){var t,n,r=e[0]/255,i=e[1]/255,o=e[2]/255,a=Math.max(Math.max(r,i),o),s=Math.min(Math.min(r,i),o),u=a-s;return t=u<1?s/(1-u):0,n=u<=0?0:a===r?(i-o)/u%6:a===i?2+(o-r)/u:4+(r-i)/u+4,n/=6,n%=1,[360*n,100*u,100*t]},i.hsl.hcg=function(e){var t=e[1]/100,n=e[2]/100,r=1,i=0;return r=n<.5?2*t*n:2*t*(1-n),r<1&&(i=(n-.5*r)/(1-r)),[e[0],100*r,100*i]},i.hsv.hcg=function(e){var t=e[1]/100,n=e[2]/100,r=t*n,i=0;return r<1&&(i=(n-r)/(1-r)),[e[0],100*r,100*i]},i.hcg.rgb=function(e){var t=e[0]/360,n=e[1]/100,r=e[2]/100;if(0===n)return[255*r,255*r,255*r];var i=[0,0,0],o=t%1*6,a=o%1,s=1-a,u=0;switch(Math.floor(o)){case 0:i[0]=1,i[1]=a,i[2]=0;break;case 1:i[0]=s,i[1]=1,i[2]=0;break;case 2:i[0]=0,i[1]=1,i[2]=a;break;case 3:i[0]=0,i[1]=s,i[2]=1;break;case 4:i[0]=a,i[1]=0,i[2]=1;break;default:i[0]=1,i[1]=0,i[2]=s}return u=(1-n)*r,[255*(n*i[0]+u),255*(n*i[1]+u),255*(n*i[2]+u)]},i.hcg.hsv=function(e){var t=e[1]/100,n=e[2]/100,r=t+n*(1-t),i=0;return r>0&&(i=t/r),[e[0],100*i,100*r]},i.hcg.hsl=function(e){var t=e[1]/100,n=e[2]/100,r=n*(1-t)+.5*t,i=0;return r>0&&r<.5?i=t/(2*r):r>=.5&&r<1&&(i=t/(2*(1-r))),[e[0],100*i,100*r]},i.hcg.hwb=function(e){var t=e[1]/100,n=e[2]/100,r=t+n*(1-t);return[e[0],100*(r-t),100*(1-r)]},i.hwb.hcg=function(e){var t=e[1]/100,n=e[2]/100,r=1-n,i=r-t,o=0;return i<1&&(o=(r-i)/(1-i)),[e[0],100*i,100*o]},i.apple.rgb=function(e){return[e[0]/65535*255,e[1]/65535*255,e[2]/65535*255]},i.rgb.apple=function(e){return[e[0]/255*65535,e[1]/255*65535,e[2]/255*65535]},i.gray.rgb=function(e){return[e[0]/100*255,e[0]/100*255,e[0]/100*255]},i.gray.hsl=i.gray.hsv=function(e){return[0,0,e[0]]},i.gray.hwb=function(e){return[0,100,e[0]]},i.gray.cmyk=function(e){return[0,0,0,e[0]]},i.gray.lab=function(e){return[e[0],0,0]},i.gray.hex=function(e){var t=255&Math.round(e[0]/100*255),n=(t<<16)+(t<<8)+t,r=n.toString(16).toUpperCase();return"000000".substring(r.length)+r},i.rgb.gray=function(e){return[(e[0]+e[1]+e[2])/3/255*100]}}),models$1=Object.keys(conversions),route=function(e){for(var t=deriveBFS(e),n={},r=Object.keys(t),i=r.length,o=0;o=8&&Number(e[0])>=10&&Number(e[2])>=10586?2:1}if("CI"in t)return"TRAVIS"in t||"Travis"===t.CI||"CIRCLECI"in t?1:0;if("TEAMCITY_VERSION"in t)return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(t.TEAMCITY_VERSION)?1:0;if("TERM_PROGRAM"in t){var n=parseInt((t.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(t.TERM_PROGRAM){case"iTerm.app":return n>=3?3:2;case"Hyper":return 3;case"Apple_Terminal":return 2}}return/^(screen|xterm)-256(?:color)?/.test(t.TERM)?2:/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(t.TERM)?1:"COLORTERM"in t?1:(t.TERM,0)}();"FORCE_COLOR"in t&&(n=0===parseInt(t.FORCE_COLOR,10)?0:n||1),e.exports=process&&function(e){return 0!==e&&{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}(n)}),templates=createCommonjsModule(function(e){function t(e){return"u"===e[0]&&5===e.length||"x"===e[0]&&3===e.length?String.fromCharCode(parseInt(e.slice(1),16)):c.get(e)||e}function n(e,n){var r,i=[],o=n.trim().split(/\s*,\s*/g),a=!0,c=!1,l=void 0;try{for(var p,f=o[Symbol.iterator]();!(a=(p=f.next()).done);a=!0){var d=p.value;if(isNaN(d)){if(!(r=d.match(s)))throw new Error("Invalid Chalk template style argument: ".concat(d," (in style '").concat(e,"')"));i.push(r[2].replace(u,function(e,n,r){return n?t(n):r}))}else i.push(Number(d))}}catch(e){c=!0,l=e}finally{try{a||null==f.return||f.return()}finally{if(c)throw l}}return i}function r(e){a.lastIndex=0;for(var t,r=[];null!==(t=a.exec(e));){var i=t[1];if(t[2]){var o=n(i,t[2]);r.push([i].concat(o))}else r.push([i])}return r}function i(e,t){var n={},r=!0,i=!1,o=void 0;try{for(var a,s=t[Symbol.iterator]();!(r=(a=s.next()).done);r=!0){var u=a.value,c=!0,l=!1,p=void 0;try{for(var f,d=u.styles[Symbol.iterator]();!(c=(f=d.next()).done);c=!0){var h=f.value;n[h[0]]=u.inverse?null:h.slice(1)}}catch(e){l=!0,p=e}finally{try{c||null==d.return||d.return()}finally{if(l)throw p}}}}catch(e){i=!0,o=e}finally{try{r||null==s.return||s.return()}finally{if(i)throw o}}for(var m=e,g=Object.keys(n),y=0;y0?m[v].apply(m,n[v]):m[v]}}return m}var o=/(?:\\(u[a-f\d]{4}|x[a-f\d]{2}|.))|(?:\{(~)?(\w+(?:\([^)]*\))?(?:\.\w+(?:\([^)]*\))?)*)(?:[ \t]|(?=\r?\n)))|(\})|((?:.|[\r\n\f])+?)/gi,a=/(?:^|\.)(\w+)(?:\(([^)]*)\))?/g,s=/^(['"])((?:\\.|(?!\1)[^\\])*)\1$/,u=/\\(u[a-f\d]{4}|x[a-f\d]{2}|.)|([^\\])/gi,c=new Map([["n","\n"],["r","\r"],["t","\t"],["b","\b"],["f","\f"],["v","\v"],["0","\0"],["\\","\\"],["e","\x1b"],["a","\x07"]]);e.exports=function(e,n){var a=[],s=[],u=[];if(n.replace(o,function(n,o,c,l,p,f){if(o)u.push(t(o));else if(l){var d=u.join("");u=[],s.push(0===a.length?d:i(e,a)(d)),a.push({inverse:c,styles:r(l)})}else if(p){if(0===a.length)throw new Error("Found extraneous } in Chalk template literal");s.push(i(e,a)(u.join(""))),u=[],a.pop()}else u.push(f)}),s.push(u.join("")),a.length>0){var c="Chalk template literal is missing ".concat(a.length," closing bracket").concat(1===a.length?"":"s"," (`}`)");throw new Error(c)}return s.join("")}}),chalk=createCommonjsModule(function(e){function t(e,t){t=t||{};var n=supportsColor?supportsColor.level:0;e.level=void 0===t.level?n:t.level,e.enabled="enabled"in t?t.enabled:e.level>0}function n(e){if(!this||!(this instanceof n)||this.template){var r={};return t(r,e),r.template=function(){var e=[].slice.call(arguments);return o.apply(null,[r.template].concat(e))},Object.setPrototypeOf(r,n.prototype),Object.setPrototypeOf(r.template,r),r.template.constructor=n,r.template}t(this,e)}function r(e,t,n){var r=function e(){return i.apply(e,arguments)};r._styles=e,r._empty=t;var o=this;return Object.defineProperty(r,"level",{enumerable:!0,get:function(){return o.level},set:function(e){o.level=e}}),Object.defineProperty(r,"enabled",{enumerable:!0,get:function(){return o.enabled},set:function(e){o.enabled=e}}),r.hasGrey=this.hasGrey||"gray"===n||"grey"===n,r.__proto__=g,r}function i(){var e=arguments,t=e.length,n=String(arguments[0]);if(0===t)return"";if(t>1)for(var r=1;r1&&void 0!==arguments[1]?arguments[1]:{};if(l(t)){return c(s(p(t)),e)}return e}Object.defineProperty(t,"__esModule",{value:!0}),t.shouldHighlight=l,t.getChalk=p,t.default=f;var d=/\r\n|[\n\r\u2028\u2029]/,h=/^[a-z][\w-]*$/i,m=/^[()[\]{}]$/});unwrapExports(lib$2);var lib$1=createCommonjsModule(function(e,t){function n(){var e=r(lib$2);return n=function(){return e},e}function r(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)if(Object.prototype.hasOwnProperty.call(e,n)){var r=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(e,n):{};r.get||r.set?Object.defineProperty(t,n,r):t[n]=e[n]}return t.default=e,t}function i(e){return{gutter:e.grey,marker:e.red.bold,message:e.red.bold}}function o(e,t,n){var r=Object.assign({column:0,line:-1},e.start),i=Object.assign({},r,e.end),o=n||{},a=o.linesAbove,s=void 0===a?2:a,u=o.linesBelow,c=void 0===u?3:u,l=r.line,p=r.column,f=i.line,d=i.column,h=Math.max(l-(s+1),0),m=Math.min(t.length,f+c);-1===l&&(h=0),-1===f&&(m=t.length);var g=f-l,y={};if(g)for(var v=0;v<=g;v++){var b=v+l;if(p)if(0===v){var x=t[b-1].length;y[b]=[p,x-p]}else if(v===g)y[b]=[0,d];else{var C=t[b-v].length;y[b]=[0,C]}else y[b]=!0}else y[l]=p===d?!p||[p,0]:[p,d-p];return{start:h,end:m,markerLines:y}}function a(e,t){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},a=(r.highlightCode||r.forceColor)&&(0,n().shouldHighlight)(r),s=(0,n().getChalk)(r),u=i(s),l=function(e,t){return a?e(t):t};a&&(e=(0,n().default)(e,r));var p=e.split(c),f=o(t,p,r),d=f.start,h=f.end,m=f.markerLines,g=t.start&&"number"===typeof t.start.column,y=String(h).length,v=p.slice(d,h).map(function(e,t){var n=d+1+t,i=" ".concat(n).slice(-y),o=" ".concat(i," | "),a=m[n],s=!m[n+1];if(a){var c="";if(Array.isArray(a)){var p=e.slice(0,Math.max(a[0]-1,0)).replace(/[^\t]/g," "),f=a[1]||1;c=["\n ",l(u.gutter,o.replace(/\d/g," ")),p,l(u.marker,"^").repeat(f)].join(""),s&&r.message&&(c+=" "+l(u.message,r.message))}return[l(u.marker,">"),l(u.gutter,o),e,c].join("")}return" ".concat(l(u.gutter,o)).concat(e)}).join("\n");return r.message&&!g&&(v="".concat(" ".repeat(y+1)).concat(r.message,"\n").concat(v)),a?s.reset(v):v}function s(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};if(!u){u=!0;var i="Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";if(process.emitWarning)process.emitWarning(i,"DeprecationWarning");else{new Error(i).name="DeprecationWarning",console.warn(new Error(i))}}return n=Math.max(n,0),a(e,{start:{column:n,line:t}},r)}Object.defineProperty(t,"__esModule",{value:!0}),t.codeFrameColumns=a,t.default=s;var u=!1,c=/\r\n|[\n\r\u2028\u2029]/});unwrapExports(lib$1);var path$5={},path$7=Object.freeze({default:path$5,__moduleExports:path$5}),path$4=path$7&&path$5||path$7,ConfigError$1=errors.ConfigError,locStart=loc.locStart,locEnd=loc.locEnd,ownNames=Object.getOwnPropertyNames,ownDescriptor=Object.getOwnPropertyDescriptor,parser={parse:parse$2,resolveParser:resolveParser$1},path$9={},path$11=Object.freeze({default:path$9,__moduleExports:path$9}),path$8=path$11&&path$9||path$11,UndefinedParserError=errors.UndefinedParserError,getSupportInfo$1=support.getSupportInfo,resolveParser=parser.resolveParser,hiddenDefaults={astFormat:"estree",printer:{},locStart:null,locEnd:null},options={normalize:normalize,hiddenDefaults:hiddenDefaults,inferParser:inferParser},massageAst=massageAST,assert={ok:function(){},strictEqual:function(){}},lineSuffixBoundary={type:"line-suffix-boundary"},breakParent$1={type:"break-parent"},line$2={type:"line"},softline={type:"line",soft:!0},hardline$1=concat$1([{type:"line",hard:!0},breakParent$1]),literalline=concat$1([{type:"line",hard:!0,literal:!0},breakParent$1]),cursor$1={type:"cursor",placeholder:Symbol("cursor")},docBuilders={concat:concat$1,join:join$1,line:line$2,softline:softline,hardline:hardline$1,literalline:literalline,group:group,conditionalGroup:conditionalGroup,fill:fill,lineSuffix:lineSuffix$1,lineSuffixBoundary:lineSuffixBoundary,cursor:cursor$1,breakParent:breakParent$1,ifBreak:ifBreak,indent:indent$1,align:align,addAlignmentToDoc:addAlignmentToDoc,markAsRoot:markAsRoot,dedentToRoot:dedentToRoot,dedent:dedent$1},ansiRegex=createCommonjsModule(function(e){e.exports=function(){var e=["[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)","(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))"].join("|");return new RegExp(e,"g")}}),stripAnsi=function(e){return"string"===typeof e?e.replace(ansiRegex(),""):e},isFullwidthCodePoint=createCommonjsModule(function(e){e.exports=function(e){return!Number.isNaN(e)&&(e>=4352&&(e<=4447||9001===e||9002===e||11904<=e&&e<=12871&&12351!==e||12880<=e&&e<=19903||19968<=e&&e<=42182||43360<=e&&e<=43388||44032<=e&&e<=55203||63744<=e&&e<=64255||65040<=e&&e<=65049||65072<=e&&e<=65131||65281<=e&&e<=65376||65504<=e&&e<=65510||110592<=e&&e<=110593||127488<=e&&e<=127569||131072<=e&&e<=262141))}}),stringWidth=createCommonjsModule(function(e){e.exports=function(e){if("string"!==typeof e||0===e.length)return 0;e=stripAnsi(e);for(var t=0,n=0;n=127&&r<=159||(r>=768&&r<=879||(r>65535&&n++,t+=isFullwidthCodePoint(r)?2:1))}return t}}),emojiRegex$1=function(){return/\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74)\uDB40\uDC7F|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC68(?:\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]\uFE0F|(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]))|\uD83D\uDC69\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2695\u2696\u2708]|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83D\uDC69\u200D[\u2695\u2696\u2708])\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D\uDC68(?:\u200D(?:(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|\uD83D[\uDC66\uDC67])|\uD83C[\uDFFB-\uDFFF])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92])|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF6\uD83C\uDDE6|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDD1-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC69\uDC6E\uDC70-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD18-\uDD1C\uDD1E\uDD1F\uDD26\uDD30-\uDD39\uDD3D\uDD3E\uDDD1-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])?|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDEEB\uDEEC\uDEF4-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267B\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEF8]|\uD83E[\uDD10-\uDD3A\uDD3C-\uDD3E\uDD40-\uDD45\uDD47-\uDD4C\uDD50-\uDD6B\uDD80-\uDD97\uDDC0\uDDD0-\uDDE6])\uFE0F/g},punctuation_ranges=[[12288,12351],[44032,55215],[65040,65055],[65072,65135],[65280,65376],[65504,65519]],character_ranges=[[4352,4607],[11904,12255],[12352,12687],[12800,19903],[19968,40959],[43360,43391],[63744,64255]];!function(e){function t(){return create_regex(punctuation_ranges)}function n(){return create_regex(character_ranges)}e.punctuations=t,e.characters=n}(get_regex||(get_regex={}));var lib$3=get_regex,data_generated=createCommonjsModule(function(e,t){t.__esModule=!0,t.get_data=function(){return{Pc:[[95,95],[8255,8256],[8276,8276],[65075,65076],[65101,65103],[65343,65343]],Pe:[[41,41],[93,93],[125,125],[3899,3899],[3901,3901],[5788,5788],[8262,8262],[8318,8318],[8334,8334],[8969,8969],[8971,8971],[9002,9002],[10089,10089],[10091,10091],[10093,10093],[10095,10095],[10097,10097],[10099,10099],[10101,10101],[10182,10182],[10215,10215],[10217,10217],[10219,10219],[10221,10221],[10223,10223],[10628,10628],[10630,10630],[10632,10632],[10634,10634],[10636,10636],[10638,10638],[10640,10640],[10642,10642],[10644,10644],[10646,10646],[10648,10648],[10713,10713],[10715,10715],[10749,10749],[11811,11811],[11813,11813],[11815,11815],[11817,11817],[12297,12297],[12299,12299],[12301,12301],[12303,12303],[12305,12305],[12309,12309],[12311,12311],[12313,12313],[12315,12315],[12318,12319],[64830,64830],[65048,65048],[65078,65078],[65080,65080],[65082,65082],[65084,65084],[65086,65086],[65088,65088],[65090,65090],[65092,65092],[65096,65096],[65114,65114],[65116,65116],[65118,65118],[65289,65289],[65341,65341],[65373,65373],[65376,65376],[65379,65379]],Ps:[[40,40],[91,91],[123,123],[3898,3898],[3900,3900],[5787,5787],[8218,8218],[8222,8222],[8261,8261],[8317,8317],[8333,8333],[8968,8968],[8970,8970],[9001,9001],[10088,10088],[10090,10090],[10092,10092],[10094,10094],[10096,10096],[10098,10098],[10100,10100],[10181,10181],[10214,10214],[10216,10216],[10218,10218],[10220,10220],[10222,10222],[10627,10627],[10629,10629],[10631,10631],[10633,10633],[10635,10635],[10637,10637],[10639,10639],[10641,10641],[10643,10643],[10645,10645],[10647,10647],[10712,10712],[10714,10714],[10748,10748],[11810,11810],[11812,11812],[11814,11814],[11816,11816],[11842,11842],[12296,12296],[12298,12298],[12300,12300],[12302,12302],[12304,12304],[12308,12308],[12310,12310],[12312,12312],[12314,12314],[12317,12317],[64831,64831],[65047,65047],[65077,65077],[65079,65079],[65081,65081],[65083,65083],[65085,65085],[65087,65087],[65089,65089],[65091,65091],[65095,65095],[65113,65113],[65115,65115],[65117,65117],[65288,65288],[65339,65339],[65371,65371],[65375,65375],[65378,65378]],Lm:[[688,705],[710,721],[736,740],[748,748],[750,750],[884,884],[890,890],[1369,1369],[1600,1600],[1765,1766],[2036,2037],[2042,2042],[2074,2074],[2084,2084],[2088,2088],[2417,2417],[3654,3654],[3782,3782],[4348,4348],[6103,6103],[6211,6211],[6823,6823],[7288,7293],[7468,7530],[7544,7544],[7579,7615],[8305,8305],[8319,8319],[8336,8348],[11388,11389],[11631,11631],[11823,11823],[12293,12293],[12337,12341],[12347,12347],[12445,12446],[12540,12542],[40981,40981],[42232,42237],[42508,42508],[42623,42623],[42652,42653],[42775,42783],[42864,42864],[42888,42888],[43e3,43001],[43471,43471],[43494,43494],[43632,43632],[43741,43741],[43763,43764],[43868,43871],[65392,65392],[65438,65439]],Mc:[[2307,2307],[2363,2363],[2366,2368],[2377,2380],[2382,2383],[2434,2435],[2494,2496],[2503,2504],[2507,2508],[2519,2519],[2563,2563],[2622,2624],[2691,2691],[2750,2752],[2761,2761],[2763,2764],[2818,2819],[2878,2878],[2880,2880],[2887,2888],[2891,2892],[2903,2903],[3006,3007],[3009,3010],[3014,3016],[3018,3020],[3031,3031],[3073,3075],[3137,3140],[3202,3203],[3262,3262],[3264,3268],[3271,3272],[3274,3275],[3285,3286],[3330,3331],[3390,3392],[3398,3400],[3402,3404],[3415,3415],[3458,3459],[3535,3537],[3544,3551],[3570,3571],[3902,3903],[3967,3967],[4139,4140],[4145,4145],[4152,4152],[4155,4156],[4182,4183],[4194,4196],[4199,4205],[4227,4228],[4231,4236],[4239,4239],[4250,4252],[6070,6070],[6078,6085],[6087,6088],[6435,6438],[6441,6443],[6448,6449],[6451,6456],[6681,6682],[6741,6741],[6743,6743],[6753,6753],[6755,6756],[6765,6770],[6916,6916],[6965,6965],[6971,6971],[6973,6977],[6979,6980],[7042,7042],[7073,7073],[7078,7079],[7082,7082],[7143,7143],[7146,7148],[7150,7150],[7154,7155],[7204,7211],[7220,7221],[7393,7393],[7410,7411],[7415,7415],[12334,12335],[43043,43044],[43047,43047],[43136,43137],[43188,43203],[43346,43347],[43395,43395],[43444,43445],[43450,43451],[43453,43456],[43567,43568],[43571,43572],[43597,43597],[43643,43643],[43645,43645],[43755,43755],[43758,43759],[43765,43765],[44003,44004],[44006,44007],[44009,44010],[44012,44012]],Zp:[[8233,8233]],Sc:[[36,36],[162,165],[1423,1423],[1547,1547],[2546,2547],[2555,2555],[2801,2801],[3065,3065],[3647,3647],[6107,6107],[8352,8383],[43064,43064],[65020,65020],[65129,65129],[65284,65284],[65504,65505],[65509,65510]],Me:[[1160,1161],[6846,6846],[8413,8416],[8418,8420],[42608,42610]],Sk:[[94,94],[96,96],[168,168],[175,175],[180,180],[184,184],[706,709],[722,735],[741,747],[749,749],[751,767],[885,885],[900,901],[8125,8125],[8127,8129],[8141,8143],[8157,8159],[8173,8175],[8189,8190],[12443,12444],[42752,42774],[42784,42785],[42889,42890],[43867,43867],[64434,64449],[65342,65342],[65344,65344],[65507,65507]],Cs:[[55296,55296],[56191,56192],[56319,56320],[57343,57343]],Nl:[[5870,5872],[8544,8578],[8581,8584],[12295,12295],[12321,12329],[12344,12346],[42726,42735]],So:[[166,166],[169,169],[174,174],[176,176],[1154,1154],[1421,1422],[1550,1551],[1758,1758],[1769,1769],[1789,1790],[2038,2038],[2554,2554],[2928,2928],[3059,3064],[3066,3066],[3199,3199],[3407,3407],[3449,3449],[3841,3843],[3859,3859],[3861,3863],[3866,3871],[3892,3892],[3894,3894],[3896,3896],[4030,4037],[4039,4044],[4046,4047],[4053,4056],[4254,4255],[5008,5017],[6464,6464],[6622,6655],[7009,7018],[7028,7036],[8448,8449],[8451,8454],[8456,8457],[8468,8468],[8470,8471],[8478,8483],[8485,8485],[8487,8487],[8489,8489],[8494,8494],[8506,8507],[8522,8522],[8524,8525],[8527,8527],[8586,8587],[8597,8601],[8604,8607],[8609,8610],[8612,8613],[8615,8621],[8623,8653],[8656,8657],[8659,8659],[8661,8691],[8960,8967],[8972,8991],[8994,9e3],[9003,9083],[9085,9114],[9140,9179],[9186,9254],[9280,9290],[9372,9449],[9472,9654],[9656,9664],[9666,9719],[9728,9838],[9840,10087],[10132,10175],[10240,10495],[11008,11055],[11077,11078],[11085,11123],[11126,11157],[11160,11193],[11197,11208],[11210,11218],[11244,11247],[11493,11498],[11904,11929],[11931,12019],[12032,12245],[12272,12283],[12292,12292],[12306,12307],[12320,12320],[12342,12343],[12350,12351],[12688,12689],[12694,12703],[12736,12771],[12800,12830],[12842,12871],[12880,12880],[12896,12927],[12938,12976],[12992,13054],[13056,13311],[19904,19967],[42128,42182],[43048,43051],[43062,43063],[43065,43065],[43639,43641],[65021,65021],[65508,65508],[65512,65512],[65517,65518],[65532,65533]],Lt:[[453,453],[456,456],[459,459],[498,498],[8072,8079],[8088,8095],[8104,8111],[8124,8124],[8140,8140],[8188,8188]],Zl:[[8232,8232]],Lo:[[170,170],[186,186],[443,443],[448,451],[660,660],[1488,1514],[1520,1522],[1568,1599],[1601,1610],[1646,1647],[1649,1747],[1749,1749],[1774,1775],[1786,1788],[1791,1791],[1808,1808],[1810,1839],[1869,1957],[1969,1969],[1994,2026],[2048,2069],[2112,2136],[2144,2154],[2208,2228],[2230,2237],[2308,2361],[2365,2365],[2384,2384],[2392,2401],[2418,2432],[2437,2444],[2447,2448],[2451,2472],[2474,2480],[2482,2482],[2486,2489],[2493,2493],[2510,2510],[2524,2525],[2527,2529],[2544,2545],[2556,2556],[2565,2570],[2575,2576],[2579,2600],[2602,2608],[2610,2611],[2613,2614],[2616,2617],[2649,2652],[2654,2654],[2674,2676],[2693,2701],[2703,2705],[2707,2728],[2730,2736],[2738,2739],[2741,2745],[2749,2749],[2768,2768],[2784,2785],[2809,2809],[2821,2828],[2831,2832],[2835,2856],[2858,2864],[2866,2867],[2869,2873],[2877,2877],[2908,2909],[2911,2913],[2929,2929],[2947,2947],[2949,2954],[2958,2960],[2962,2965],[2969,2970],[2972,2972],[2974,2975],[2979,2980],[2984,2986],[2990,3001],[3024,3024],[3077,3084],[3086,3088],[3090,3112],[3114,3129],[3133,3133],[3160,3162],[3168,3169],[3200,3200],[3205,3212],[3214,3216],[3218,3240],[3242,3251],[3253,3257],[3261,3261],[3294,3294],[3296,3297],[3313,3314],[3333,3340],[3342,3344],[3346,3386],[3389,3389],[3406,3406],[3412,3414],[3423,3425],[3450,3455],[3461,3478],[3482,3505],[3507,3515],[3517,3517],[3520,3526],[3585,3632],[3634,3635],[3648,3653],[3713,3714],[3716,3716],[3719,3720],[3722,3722],[3725,3725],[3732,3735],[3737,3743],[3745,3747],[3749,3749],[3751,3751],[3754,3755],[3757,3760],[3762,3763],[3773,3773],[3776,3780],[3804,3807],[3840,3840],[3904,3911],[3913,3948],[3976,3980],[4096,4138],[4159,4159],[4176,4181],[4186,4189],[4193,4193],[4197,4198],[4206,4208],[4213,4225],[4238,4238],[4304,4346],[4349,4680],[4682,4685],[4688,4694],[4696,4696],[4698,4701],[4704,4744],[4746,4749],[4752,4784],[4786,4789],[4792,4798],[4800,4800],[4802,4805],[4808,4822],[4824,4880],[4882,4885],[4888,4954],[4992,5007],[5121,5740],[5743,5759],[5761,5786],[5792,5866],[5873,5880],[5888,5900],[5902,5905],[5920,5937],[5952,5969],[5984,5996],[5998,6e3],[6016,6067],[6108,6108],[6176,6210],[6212,6263],[6272,6276],[6279,6312],[6314,6314],[6320,6389],[6400,6430],[6480,6509],[6512,6516],[6528,6571],[6576,6601],[6656,6678],[6688,6740],[6917,6963],[6981,6987],[7043,7072],[7086,7087],[7098,7141],[7168,7203],[7245,7247],[7258,7287],[7401,7404],[7406,7409],[7413,7414],[8501,8504],[11568,11623],[11648,11670],[11680,11686],[11688,11694],[11696,11702],[11704,11710],[11712,11718],[11720,11726],[11728,11734],[11736,11742],[12294,12294],[12348,12348],[12353,12438],[12447,12447],[12449,12538],[12543,12543],[12549,12590],[12593,12686],[12704,12730],[12784,12799],[13312,13312],[19893,19893],[19968,19968],[40938,40938],[40960,40980],[40982,42124],[42192,42231],[42240,42507],[42512,42527],[42538,42539],[42606,42606],[42656,42725],[42895,42895],[42999,42999],[43003,43009],[43011,43013],[43015,43018],[43020,43042],[43072,43123],[43138,43187],[43250,43255],[43259,43259],[43261,43261],[43274,43301],[43312,43334],[43360,43388],[43396,43442],[43488,43492],[43495,43503],[43514,43518],[43520,43560],[43584,43586],[43588,43595],[43616,43631],[43633,43638],[43642,43642],[43646,43695],[43697,43697],[43701,43702],[43705,43709],[43712,43712],[43714,43714],[43739,43740],[43744,43754],[43762,43762],[43777,43782],[43785,43790],[43793,43798],[43808,43814],[43816,43822],[43968,44002],[44032,44032],[55203,55203],[55216,55238],[55243,55291],[63744,64109],[64112,64217],[64285,64285],[64287,64296],[64298,64310],[64312,64316],[64318,64318],[64320,64321],[64323,64324],[64326,64433],[64467,64829],[64848,64911],[64914,64967],[65008,65019],[65136,65140],[65142,65276],[65382,65391],[65393,65437],[65440,65470],[65474,65479],[65482,65487],[65490,65495],[65498,65500]],Mn:[[768,879],[1155,1159],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1552,1562],[1611,1631],[1648,1648],[1750,1756],[1759,1764],[1767,1768],[1770,1773],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2070,2073],[2075,2083],[2085,2087],[2089,2093],[2137,2139],[2260,2273],[2275,2306],[2362,2362],[2364,2364],[2369,2376],[2381,2381],[2385,2391],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2641,2641],[2672,2673],[2677,2677],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2810,2815],[2817,2817],[2876,2876],[2879,2879],[2881,2884],[2893,2893],[2902,2902],[2914,2915],[2946,2946],[3008,3008],[3021,3021],[3072,3072],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3170,3171],[3201,3201],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3328,3329],[3387,3388],[3393,3396],[3405,3405],[3426,3427],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3981,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4151],[4153,4154],[4157,4158],[4184,4185],[4190,4192],[4209,4212],[4226,4226],[4229,4230],[4237,4237],[4253,4253],[4957,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6277,6278],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6683,6683],[6742,6742],[6744,6750],[6752,6752],[6754,6754],[6757,6764],[6771,6780],[6783,6783],[6832,6845],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7040,7041],[7074,7077],[7080,7081],[7083,7085],[7142,7142],[7144,7145],[7149,7149],[7151,7153],[7212,7219],[7222,7223],[7376,7378],[7380,7392],[7394,7400],[7405,7405],[7412,7412],[7416,7417],[7616,7673],[7675,7679],[8400,8412],[8417,8417],[8421,8432],[11503,11505],[11647,11647],[11744,11775],[12330,12333],[12441,12442],[42607,42607],[42612,42621],[42654,42655],[42736,42737],[43010,43010],[43014,43014],[43019,43019],[43045,43046],[43204,43205],[43232,43249],[43302,43309],[43335,43345],[43392,43394],[43443,43443],[43446,43449],[43452,43452],[43493,43493],[43561,43566],[43569,43570],[43573,43574],[43587,43587],[43596,43596],[43644,43644],[43696,43696],[43698,43700],[43703,43704],[43710,43711],[43713,43713],[43756,43757],[43766,43766],[44005,44005],[44008,44008],[44013,44013],[64286,64286],[65024,65039],[65056,65071]],Po:[[33,35],[37,39],[42,42],[44,44],[46,47],[58,59],[63,64],[92,92],[161,161],[167,167],[182,183],[191,191],[894,894],[903,903],[1370,1375],[1417,1417],[1472,1472],[1475,1475],[1478,1478],[1523,1524],[1545,1546],[1548,1549],[1563,1563],[1566,1567],[1642,1645],[1748,1748],[1792,1805],[2039,2041],[2096,2110],[2142,2142],[2404,2405],[2416,2416],[2557,2557],[2800,2800],[3572,3572],[3663,3663],[3674,3675],[3844,3858],[3860,3860],[3973,3973],[4048,4052],[4057,4058],[4170,4175],[4347,4347],[4960,4968],[5741,5742],[5867,5869],[5941,5942],[6100,6102],[6104,6106],[6144,6149],[6151,6154],[6468,6469],[6686,6687],[6816,6822],[6824,6829],[7002,7008],[7164,7167],[7227,7231],[7294,7295],[7360,7367],[7379,7379],[8214,8215],[8224,8231],[8240,8248],[8251,8254],[8257,8259],[8263,8273],[8275,8275],[8277,8286],[11513,11516],[11518,11519],[11632,11632],[11776,11777],[11782,11784],[11787,11787],[11790,11798],[11800,11801],[11803,11803],[11806,11807],[11818,11822],[11824,11833],[11836,11839],[11841,11841],[11843,11849],[12289,12291],[12349,12349],[12539,12539],[42238,42239],[42509,42511],[42611,42611],[42622,42622],[42738,42743],[43124,43127],[43214,43215],[43256,43258],[43260,43260],[43310,43311],[43359,43359],[43457,43469],[43486,43487],[43612,43615],[43742,43743],[43760,43761],[44011,44011],[65040,65046],[65049,65049],[65072,65072],[65093,65094],[65097,65100],[65104,65106],[65108,65111],[65119,65121],[65128,65128],[65130,65131],[65281,65283],[65285,65287],[65290,65290],[65292,65292],[65294,65295],[65306,65307],[65311,65312],[65340,65340],[65377,65377],[65380,65381]],Co:[[57344,57344],[63743,63743]],Sm:[[43,43],[60,62],[124,124],[126,126],[172,172],[177,177],[215,215],[247,247],[1014,1014],[1542,1544],[8260,8260],[8274,8274],[8314,8316],[8330,8332],[8472,8472],[8512,8516],[8523,8523],[8592,8596],[8602,8603],[8608,8608],[8611,8611],[8614,8614],[8622,8622],[8654,8655],[8658,8658],[8660,8660],[8692,8959],[8992,8993],[9084,9084],[9115,9139],[9180,9185],[9655,9655],[9665,9665],[9720,9727],[9839,9839],[10176,10180],[10183,10213],[10224,10239],[10496,10626],[10649,10711],[10716,10747],[10750,11007],[11056,11076],[11079,11084],[64297,64297],[65122,65122],[65124,65126],[65291,65291],[65308,65310],[65372,65372],[65374,65374],[65506,65506],[65513,65516]],Pf:[[187,187],[8217,8217],[8221,8221],[8250,8250],[11779,11779],[11781,11781],[11786,11786],[11789,11789],[11805,11805],[11809,11809]],Cc:[[0,31],[127,159]],Pi:[[171,171],[8216,8216],[8219,8220],[8223,8223],[8249,8249],[11778,11778],[11780,11780],[11785,11785],[11788,11788],[11804,11804],[11808,11808]],Lu:[[65,90],[192,214],[216,222],[256,256],[258,258],[260,260],[262,262],[264,264],[266,266],[268,268],[270,270],[272,272],[274,274],[276,276],[278,278],[280,280],[282,282],[284,284],[286,286],[288,288],[290,290],[292,292],[294,294],[296,296],[298,298],[300,300],[302,302],[304,304],[306,306],[308,308],[310,310],[313,313],[315,315],[317,317],[319,319],[321,321],[323,323],[325,325],[327,327],[330,330],[332,332],[334,334],[336,336],[338,338],[340,340],[342,342],[344,344],[346,346],[348,348],[350,350],[352,352],[354,354],[356,356],[358,358],[360,360],[362,362],[364,364],[366,366],[368,368],[370,370],[372,372],[374,374],[376,377],[379,379],[381,381],[385,386],[388,388],[390,391],[393,395],[398,401],[403,404],[406,408],[412,413],[415,416],[418,418],[420,420],[422,423],[425,425],[428,428],[430,431],[433,435],[437,437],[439,440],[444,444],[452,452],[455,455],[458,458],[461,461],[463,463],[465,465],[467,467],[469,469],[471,471],[473,473],[475,475],[478,478],[480,480],[482,482],[484,484],[486,486],[488,488],[490,490],[492,492],[494,494],[497,497],[500,500],[502,504],[506,506],[508,508],[510,510],[512,512],[514,514],[516,516],[518,518],[520,520],[522,522],[524,524],[526,526],[528,528],[530,530],[532,532],[534,534],[536,536],[538,538],[540,540],[542,542],[544,544],[546,546],[548,548],[550,550],[552,552],[554,554],[556,556],[558,558],[560,560],[562,562],[570,571],[573,574],[577,577],[579,582],[584,584],[586,586],[588,588],[590,590],[880,880],[882,882],[886,886],[895,895],[902,902],[904,906],[908,908],[910,911],[913,929],[931,939],[975,975],[978,980],[984,984],[986,986],[988,988],[990,990],[992,992],[994,994],[996,996],[998,998],[1e3,1e3],[1002,1002],[1004,1004],[1006,1006],[1012,1012],[1015,1015],[1017,1018],[1021,1071],[1120,1120],[1122,1122],[1124,1124],[1126,1126],[1128,1128],[1130,1130],[1132,1132],[1134,1134],[1136,1136],[1138,1138],[1140,1140],[1142,1142],[1144,1144],[1146,1146],[1148,1148],[1150,1150],[1152,1152],[1162,1162],[1164,1164],[1166,1166],[1168,1168],[1170,1170],[1172,1172],[1174,1174],[1176,1176],[1178,1178],[1180,1180],[1182,1182],[1184,1184],[1186,1186],[1188,1188],[1190,1190],[1192,1192],[1194,1194],[1196,1196],[1198,1198],[1200,1200],[1202,1202],[1204,1204],[1206,1206],[1208,1208],[1210,1210],[1212,1212],[1214,1214],[1216,1217],[1219,1219],[1221,1221],[1223,1223],[1225,1225],[1227,1227],[1229,1229],[1232,1232],[1234,1234],[1236,1236],[1238,1238],[1240,1240],[1242,1242],[1244,1244],[1246,1246],[1248,1248],[1250,1250],[1252,1252],[1254,1254],[1256,1256],[1258,1258],[1260,1260],[1262,1262],[1264,1264],[1266,1266],[1268,1268],[1270,1270],[1272,1272],[1274,1274],[1276,1276],[1278,1278],[1280,1280],[1282,1282],[1284,1284],[1286,1286],[1288,1288],[1290,1290],[1292,1292],[1294,1294],[1296,1296],[1298,1298],[1300,1300],[1302,1302],[1304,1304],[1306,1306],[1308,1308],[1310,1310],[1312,1312],[1314,1314],[1316,1316],[1318,1318],[1320,1320],[1322,1322],[1324,1324],[1326,1326],[1329,1366],[4256,4293],[4295,4295],[4301,4301],[5024,5109],[7680,7680],[7682,7682],[7684,7684],[7686,7686],[7688,7688],[7690,7690],[7692,7692],[7694,7694],[7696,7696],[7698,7698],[7700,7700],[7702,7702],[7704,7704],[7706,7706],[7708,7708],[7710,7710],[7712,7712],[7714,7714],[7716,7716],[7718,7718],[7720,7720],[7722,7722],[7724,7724],[7726,7726],[7728,7728],[7730,7730],[7732,7732],[7734,7734],[7736,7736],[7738,7738],[7740,7740],[7742,7742],[7744,7744],[7746,7746],[7748,7748],[7750,7750],[7752,7752],[7754,7754],[7756,7756],[7758,7758],[7760,7760],[7762,7762],[7764,7764],[7766,7766],[7768,7768],[7770,7770],[7772,7772],[7774,7774],[7776,7776],[7778,7778],[7780,7780],[7782,7782],[7784,7784],[7786,7786],[7788,7788],[7790,7790],[7792,7792],[7794,7794],[7796,7796],[7798,7798],[7800,7800],[7802,7802],[7804,7804],[7806,7806],[7808,7808],[7810,7810],[7812,7812],[7814,7814],[7816,7816],[7818,7818],[7820,7820],[7822,7822],[7824,7824],[7826,7826],[7828,7828],[7838,7838],[7840,7840],[7842,7842],[7844,7844],[7846,7846],[7848,7848],[7850,7850],[7852,7852],[7854,7854],[7856,7856],[7858,7858],[7860,7860],[7862,7862],[7864,7864],[7866,7866],[7868,7868],[7870,7870],[7872,7872],[7874,7874],[7876,7876],[7878,7878],[7880,7880],[7882,7882],[7884,7884],[7886,7886],[7888,7888],[7890,7890],[7892,7892],[7894,7894],[7896,7896],[7898,7898],[7900,7900],[7902,7902],[7904,7904],[7906,7906],[7908,7908],[7910,7910],[7912,7912],[7914,7914],[7916,7916],[7918,7918],[7920,7920],[7922,7922],[7924,7924],[7926,7926],[7928,7928],[7930,7930],[7932,7932],[7934,7934],[7944,7951],[7960,7965],[7976,7983],[7992,7999],[8008,8013],[8025,8025],[8027,8027],[8029,8029],[8031,8031],[8040,8047],[8120,8123],[8136,8139],[8152,8155],[8168,8172],[8184,8187],[8450,8450],[8455,8455],[8459,8461],[8464,8466],[8469,8469],[8473,8477],[8484,8484],[8486,8486],[8488,8488],[8490,8493],[8496,8499],[8510,8511],[8517,8517],[8579,8579],[11264,11310],[11360,11360],[11362,11364],[11367,11367],[11369,11369],[11371,11371],[11373,11376],[11378,11378],[11381,11381],[11390,11392],[11394,11394],[11396,11396],[11398,11398],[11400,11400],[11402,11402],[11404,11404],[11406,11406],[11408,11408],[11410,11410],[11412,11412],[11414,11414],[11416,11416],[11418,11418],[11420,11420],[11422,11422],[11424,11424],[11426,11426],[11428,11428],[11430,11430],[11432,11432],[11434,11434],[11436,11436],[11438,11438],[11440,11440],[11442,11442],[11444,11444],[11446,11446],[11448,11448],[11450,11450],[11452,11452],[11454,11454],[11456,11456],[11458,11458],[11460,11460],[11462,11462],[11464,11464],[11466,11466],[11468,11468],[11470,11470],[11472,11472],[11474,11474],[11476,11476],[11478,11478],[11480,11480],[11482,11482],[11484,11484],[11486,11486],[11488,11488],[11490,11490],[11499,11499],[11501,11501],[11506,11506],[42560,42560],[42562,42562],[42564,42564],[42566,42566],[42568,42568],[42570,42570],[42572,42572],[42574,42574],[42576,42576],[42578,42578],[42580,42580],[42582,42582],[42584,42584],[42586,42586],[42588,42588],[42590,42590],[42592,42592],[42594,42594],[42596,42596],[42598,42598],[42600,42600],[42602,42602],[42604,42604],[42624,42624],[42626,42626],[42628,42628],[42630,42630],[42632,42632],[42634,42634],[42636,42636],[42638,42638],[42640,42640],[42642,42642],[42644,42644],[42646,42646],[42648,42648],[42650,42650],[42786,42786],[42788,42788],[42790,42790],[42792,42792],[42794,42794],[42796,42796],[42798,42798],[42802,42802],[42804,42804],[42806,42806],[42808,42808],[42810,42810],[42812,42812],[42814,42814],[42816,42816],[42818,42818],[42820,42820],[42822,42822],[42824,42824],[42826,42826],[42828,42828],[42830,42830],[42832,42832],[42834,42834],[42836,42836],[42838,42838],[42840,42840],[42842,42842],[42844,42844],[42846,42846],[42848,42848],[42850,42850],[42852,42852],[42854,42854],[42856,42856],[42858,42858],[42860,42860],[42862,42862],[42873,42873],[42875,42875],[42877,42878],[42880,42880],[42882,42882],[42884,42884],[42886,42886],[42891,42891],[42893,42893],[42896,42896],[42898,42898],[42902,42902],[42904,42904],[42906,42906],[42908,42908],[42910,42910],[42912,42912],[42914,42914],[42916,42916],[42918,42918],[42920,42920],[42922,42926],[42928,42932],[42934,42934],[65313,65338]],Pd:[[45,45],[1418,1418],[1470,1470],[5120,5120],[6150,6150],[8208,8213],[11799,11799],[11802,11802],[11834,11835],[11840,11840],[12316,12316],[12336,12336],[12448,12448],[65073,65074],[65112,65112],[65123,65123],[65293,65293]],Cf:[[173,173],[1536,1541],[1564,1564],[1757,1757],[1807,1807],[2274,2274],[6158,6158],[8203,8207],[8234,8238],[8288,8292],[8294,8303],[65279,65279],[65529,65531]],Nd:[[48,57],[1632,1641],[1776,1785],[1984,1993],[2406,2415],[2534,2543],[2662,2671],[2790,2799],[2918,2927],[3046,3055],[3174,3183],[3302,3311],[3430,3439],[3558,3567],[3664,3673],[3792,3801],[3872,3881],[4160,4169],[4240,4249],[6112,6121],[6160,6169],[6470,6479],[6608,6617],[6784,6793],[6800,6809],[6992,7001],[7088,7097],[7232,7241],[7248,7257],[42528,42537],[43216,43225],[43264,43273],[43472,43481],[43504,43513],[43600,43609],[44016,44025],[65296,65305]],Ll:[[97,122],[181,181],[223,246],[248,255],[257,257],[259,259],[261,261],[263,263],[265,265],[267,267],[269,269],[271,271],[273,273],[275,275],[277,277],[279,279],[281,281],[283,283],[285,285],[287,287],[289,289],[291,291],[293,293],[295,295],[297,297],[299,299],[301,301],[303,303],[305,305],[307,307],[309,309],[311,312],[314,314],[316,316],[318,318],[320,320],[322,322],[324,324],[326,326],[328,329],[331,331],[333,333],[335,335],[337,337],[339,339],[341,341],[343,343],[345,345],[347,347],[349,349],[351,351],[353,353],[355,355],[357,357],[359,359],[361,361],[363,363],[365,365],[367,367],[369,369],[371,371],[373,373],[375,375],[378,378],[380,380],[382,384],[387,387],[389,389],[392,392],[396,397],[402,402],[405,405],[409,411],[414,414],[417,417],[419,419],[421,421],[424,424],[426,427],[429,429],[432,432],[436,436],[438,438],[441,442],[445,447],[454,454],[457,457],[460,460],[462,462],[464,464],[466,466],[468,468],[470,470],[472,472],[474,474],[476,477],[479,479],[481,481],[483,483],[485,485],[487,487],[489,489],[491,491],[493,493],[495,496],[499,499],[501,501],[505,505],[507,507],[509,509],[511,511],[513,513],[515,515],[517,517],[519,519],[521,521],[523,523],[525,525],[527,527],[529,529],[531,531],[533,533],[535,535],[537,537],[539,539],[541,541],[543,543],[545,545],[547,547],[549,549],[551,551],[553,553],[555,555],[557,557],[559,559],[561,561],[563,569],[572,572],[575,576],[578,578],[583,583],[585,585],[587,587],[589,589],[591,659],[661,687],[881,881],[883,883],[887,887],[891,893],[912,912],[940,974],[976,977],[981,983],[985,985],[987,987],[989,989],[991,991],[993,993],[995,995],[997,997],[999,999],[1001,1001],[1003,1003],[1005,1005],[1007,1011],[1013,1013],[1016,1016],[1019,1020],[1072,1119],[1121,1121],[1123,1123],[1125,1125],[1127,1127],[1129,1129],[1131,1131],[1133,1133],[1135,1135],[1137,1137],[1139,1139],[1141,1141],[1143,1143],[1145,1145],[1147,1147],[1149,1149],[1151,1151],[1153,1153],[1163,1163],[1165,1165],[1167,1167],[1169,1169],[1171,1171],[1173,1173],[1175,1175],[1177,1177],[1179,1179],[1181,1181],[1183,1183],[1185,1185],[1187,1187],[1189,1189],[1191,1191],[1193,1193],[1195,1195],[1197,1197],[1199,1199],[1201,1201],[1203,1203],[1205,1205],[1207,1207],[1209,1209],[1211,1211],[1213,1213],[1215,1215],[1218,1218],[1220,1220],[1222,1222],[1224,1224],[1226,1226],[1228,1228],[1230,1231],[1233,1233],[1235,1235],[1237,1237],[1239,1239],[1241,1241],[1243,1243],[1245,1245],[1247,1247],[1249,1249],[1251,1251],[1253,1253],[1255,1255],[1257,1257],[1259,1259],[1261,1261],[1263,1263],[1265,1265],[1267,1267],[1269,1269],[1271,1271],[1273,1273],[1275,1275],[1277,1277],[1279,1279],[1281,1281],[1283,1283],[1285,1285],[1287,1287],[1289,1289],[1291,1291],[1293,1293],[1295,1295],[1297,1297],[1299,1299],[1301,1301],[1303,1303],[1305,1305],[1307,1307],[1309,1309],[1311,1311],[1313,1313],[1315,1315],[1317,1317],[1319,1319],[1321,1321],[1323,1323],[1325,1325],[1327,1327],[1377,1415],[5112,5117],[7296,7304],[7424,7467],[7531,7543],[7545,7578],[7681,7681],[7683,7683],[7685,7685],[7687,7687],[7689,7689],[7691,7691],[7693,7693],[7695,7695],[7697,7697],[7699,7699],[7701,7701],[7703,7703],[7705,7705],[7707,7707],[7709,7709],[7711,7711],[7713,7713],[7715,7715],[7717,7717],[7719,7719],[7721,7721],[7723,7723],[7725,7725],[7727,7727],[7729,7729],[7731,7731],[7733,7733],[7735,7735],[7737,7737],[7739,7739],[7741,7741],[7743,7743],[7745,7745],[7747,7747],[7749,7749],[7751,7751],[7753,7753],[7755,7755],[7757,7757],[7759,7759],[7761,7761],[7763,7763],[7765,7765],[7767,7767],[7769,7769],[7771,7771],[7773,7773],[7775,7775],[7777,7777],[7779,7779],[7781,7781],[7783,7783],[7785,7785],[7787,7787],[7789,7789],[7791,7791],[7793,7793],[7795,7795],[7797,7797],[7799,7799],[7801,7801],[7803,7803],[7805,7805],[7807,7807],[7809,7809],[7811,7811],[7813,7813],[7815,7815],[7817,7817],[7819,7819],[7821,7821],[7823,7823],[7825,7825],[7827,7827],[7829,7837],[7839,7839],[7841,7841],[7843,7843],[7845,7845],[7847,7847],[7849,7849],[7851,7851],[7853,7853],[7855,7855],[7857,7857],[7859,7859],[7861,7861],[7863,7863],[7865,7865],[7867,7867],[7869,7869],[7871,7871],[7873,7873],[7875,7875],[7877,7877],[7879,7879],[7881,7881],[7883,7883],[7885,7885],[7887,7887],[7889,7889],[7891,7891],[7893,7893],[7895,7895],[7897,7897],[7899,7899],[7901,7901],[7903,7903],[7905,7905],[7907,7907],[7909,7909],[7911,7911],[7913,7913],[7915,7915],[7917,7917],[7919,7919],[7921,7921],[7923,7923],[7925,7925],[7927,7927],[7929,7929],[7931,7931],[7933,7933],[7935,7943],[7952,7957],[7968,7975],[7984,7991],[8e3,8005],[8016,8023],[8032,8039],[8048,8061],[8064,8071],[8080,8087],[8096,8103],[8112,8116],[8118,8119],[8126,8126],[8130,8132],[8134,8135],[8144,8147],[8150,8151],[8160,8167],[8178,8180],[8182,8183],[8458,8458],[8462,8463],[8467,8467],[8495,8495],[8500,8500],[8505,8505],[8508,8509],[8518,8521],[8526,8526],[8580,8580],[11312,11358],[11361,11361],[11365,11366],[11368,11368],[11370,11370],[11372,11372],[11377,11377],[11379,11380],[11382,11387],[11393,11393],[11395,11395],[11397,11397],[11399,11399],[11401,11401],[11403,11403],[11405,11405],[11407,11407],[11409,11409],[11411,11411],[11413,11413],[11415,11415],[11417,11417],[11419,11419],[11421,11421],[11423,11423],[11425,11425],[11427,11427],[11429,11429],[11431,11431],[11433,11433],[11435,11435],[11437,11437],[11439,11439],[11441,11441],[11443,11443],[11445,11445],[11447,11447],[11449,11449],[11451,11451],[11453,11453],[11455,11455],[11457,11457],[11459,11459],[11461,11461],[11463,11463],[11465,11465],[11467,11467],[11469,11469],[11471,11471],[11473,11473],[11475,11475],[11477,11477],[11479,11479],[11481,11481],[11483,11483],[11485,11485],[11487,11487],[11489,11489],[11491,11492],[11500,11500],[11502,11502],[11507,11507],[11520,11557],[11559,11559],[11565,11565],[42561,42561],[42563,42563],[42565,42565],[42567,42567],[42569,42569],[42571,42571],[42573,42573],[42575,42575],[42577,42577],[42579,42579],[42581,42581],[42583,42583],[42585,42585],[42587,42587],[42589,42589],[42591,42591],[42593,42593],[42595,42595],[42597,42597],[42599,42599],[42601,42601],[42603,42603],[42605,42605],[42625,42625],[42627,42627],[42629,42629],[42631,42631],[42633,42633],[42635,42635],[42637,42637],[42639,42639],[42641,42641],[42643,42643],[42645,42645],[42647,42647],[42649,42649],[42651,42651],[42787,42787],[42789,42789],[42791,42791],[42793,42793],[42795,42795],[42797,42797],[42799,42801],[42803,42803],[42805,42805],[42807,42807],[42809,42809],[42811,42811],[42813,42813],[42815,42815],[42817,42817],[42819,42819],[42821,42821],[42823,42823],[42825,42825],[42827,42827],[42829,42829],[42831,42831],[42833,42833],[42835,42835],[42837,42837],[42839,42839],[42841,42841],[42843,42843],[42845,42845],[42847,42847],[42849,42849],[42851,42851],[42853,42853],[42855,42855],[42857,42857],[42859,42859],[42861,42861],[42863,42863],[42865,42872],[42874,42874],[42876,42876],[42879,42879],[42881,42881],[42883,42883],[42885,42885],[42887,42887],[42892,42892],[42894,42894],[42897,42897],[42899,42901],[42903,42903],[42905,42905],[42907,42907],[42909,42909],[42911,42911],[42913,42913],[42915,42915],[42917,42917],[42919,42919],[42921,42921],[42933,42933],[42935,42935],[43002,43002],[43824,43866],[43872,43877],[43888,43967],[64256,64262],[64275,64279],[65345,65370]],No:[[178,179],[185,185],[188,190],[2548,2553],[2930,2935],[3056,3058],[3192,3198],[3416,3422],[3440,3448],[3882,3891],[4969,4988],[6128,6137],[6618,6618],[8304,8304],[8308,8313],[8320,8329],[8528,8543],[8585,8585],[9312,9371],[9450,9471],[10102,10131],[11517,11517],[12690,12693],[12832,12841],[12872,12879],[12881,12895],[12928,12937],[12977,12991],[43056,43061]],Zs:[[32,32],[160,160],[5760,5760],[8192,8202],[8239,8239],[8287,8287],[12288,12288]]}}});unwrapExports(data_generated);var utils$2=createCommonjsModule(function(e,t){function n(e){return e.sort(function(e,t){return e[0]-t[0]}).reduce(function(e,t,n){if(0===n)return[t];var r=e[e.length-1],i=r[0],o=r[1],a=t[0],s=t[1];return o+1===a?e.slice(0,-1).concat([[i,s]]):e.concat([t])},[])}function r(e,t){var n=e.map(function(e){var t=e[0],n=e[1];return t===n?"\\u"+i(t):"\\u"+i(t)+"-\\u"+i(n)}).join("");return new RegExp("["+n+"]",t)}function i(e){for(var t=e.toString(16);t.length<4;)t="0"+t;return t}t.__esModule=!0,t.normalize_ranges=n,t.build_regex=r});unwrapExports(utils$2);var lib$5=function(e,t){var n=data_generated.get_data(),r=e.reduce(function(e,t){return e.concat(n[t])},[]);return utils$2.build_regex(utils$2.normalize_ranges(r),t)},emojiRegex=emojiRegex$1(),cjkPattern=lib$3().source,asciiPunctuationCharRange=escapeStringRegexp("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"),punctuationCharRange="".concat(asciiPunctuationCharRange).concat(lib$5(["Pc","Pd","Pe","Pf","Pi","Po","Ps"]).source.slice(1,-1)),punctuationRegex=new RegExp("[".concat(punctuationCharRange,"]")),skipWhitespace=skip(/\s/),skipSpaces=skip(" \t"),skipToLineEnd=skip(",; \t"),skipEverythingButNewLine=skip(/[^\r\n]/),PRECEDENCE={};[["|>"],["||","??"],["&&"],["|"],["^"],["&"],["==","===","!=","!=="],["<",">","<=",">=","in","instanceof"],[">>","<<",">>>"],["+","-"],["*","/","%"],["**"]].forEach(function(e,t){e.forEach(function(e){PRECEDENCE[e]=t})});var equalityOperators={"==":!0,"!=":!0,"===":!0,"!==":!0},additiveOperators={"+":!0,"-":!0},multiplicativeOperators={"*":!0,"/":!0,"%":!0},bitshiftOperators={">>":!0,">>>":!0,"<<":!0},util={punctuationRegex:punctuationRegex,punctuationCharRange:punctuationCharRange,getStringWidth:getStringWidth,splitText:splitText,getMaxContinuousCount:getMaxContinuousCount,getPrecedence:getPrecedence,shouldFlatten:shouldFlatten,isBitwiseOperator:isBitwiseOperator,isExportDeclaration:isExportDeclaration,getParentExportDeclaration:getParentExportDeclaration,getPenultimate:getPenultimate,getLast:getLast$3,getNextNonSpaceNonCommentCharacterIndex:getNextNonSpaceNonCommentCharacterIndex,getNextNonSpaceNonCommentCharacter:getNextNonSpaceNonCommentCharacter,skipWhitespace:skipWhitespace,skipSpaces:skipSpaces,skipNewline:skipNewline$1,isNextLineEmptyAfterIndex:isNextLineEmptyAfterIndex,isNextLineEmpty:isNextLineEmpty,isPreviousLineEmpty:isPreviousLineEmpty$1,hasNewline:hasNewline$1,hasNewlineInRange:hasNewlineInRange,hasSpaces:hasSpaces,setLocStart:setLocStart,setLocEnd:setLocEnd,startsWithNoLookaheadToken:startsWithNoLookaheadToken,getAlignmentSize:getAlignmentSize,getIndentSize:getIndentSize,printString:printString,printNumber:printNumber,hasIgnoreComment:hasIgnoreComment,hasNodeIgnoreComment:hasNodeIgnoreComment,makeString:makeString,addLeadingComment:addLeadingComment$1,addDanglingComment:addDanglingComment$1,addTrailingComment:addTrailingComment$1},concat$2=docBuilders.concat,fill$1=docBuilders.fill,cursor$2=docBuilders.cursor,MODE_BREAK=1,MODE_FLAT=2,docPrinter={printDocToString:printDocToString},docUtils={isEmpty:isEmpty,willBreak:willBreak,isLineNext:isLineNext,traverseDoc:traverseDoc,mapDoc:mapDoc,propagateBreaks:propagateBreaks,removeLines:removeLines,stripTrailingHardline:stripTrailingHardline},docDebug={printDocToDebug:function(e){return printDoc(flattenDoc(e))}},doc={builders:docBuilders,printer:docPrinter,utils:docUtils,debug:docDebug},mapDoc$1=doc.utils.mapDoc,utilShared={isNextLineEmpty:isNextLineEmpty$1,isNextLineEmptyAfterIndex:util.isNextLineEmptyAfterIndex,getNextNonSpaceNonCommentCharacterIndex:getNextNonSpaceNonCommentCharacterIndex$1,mapDoc:mapDoc$1,makeString:util.makeString,addLeadingComment:util.addLeadingComment,addDanglingComment:util.addDanglingComment,addTrailingComment:util.addTrailingComment},_require$$0$builders=doc.builders,concat=_require$$0$builders.concat,hardline=_require$$0$builders.hardline,breakParent=_require$$0$builders.breakParent,indent=_require$$0$builders.indent,lineSuffix=_require$$0$builders.lineSuffix,join=_require$$0$builders.join,cursor=_require$$0$builders.cursor,hasNewline=util.hasNewline,skipNewline=util.skipNewline,isPreviousLineEmpty=util.isPreviousLineEmpty,addLeadingComment=utilShared.addLeadingComment,addDanglingComment=utilShared.addDanglingComment,addTrailingComment=utilShared.addTrailingComment,childNodesCacheKey=Symbol("child-nodes"),comments={attach:attach,printComments:printComments,printDanglingComments:printDanglingComments,getSortedChildNodes:getSortedChildNodes};FastPath.prototype.getName=function(){var e=this.stack,t=e.length;return t>1?e[t-2]:null},FastPath.prototype.getValue=function(){var e=this.stack;return e[e.length-1]},FastPath.prototype.getNode=function(e){return getNodeHelper(this,~~e)},FastPath.prototype.getParentNode=function(e){return getNodeHelper(this,1+~~e)},FastPath.prototype.call=function(e){for(var t=this.stack,n=t.length,r=t[n-1],i=arguments.length,o=1;ot.length-n?"\r\n":"\n"},e.exports.graceful=function(t){return e.exports(t)||"\n"}}),os$8={},os$10=Object.freeze({default:os$8,__moduleExports:os$8}),require$$1$4=os$10&&os$8||os$10,build=createCommonjsModule(function(e,t){function n(){return p=i(detectNewline)}function r(){return f=require$$1$4}function i(e){return e&&e.__esModule?e:{default:e}}function o(e){var t=e.match(m);return t?t[0].replace(y,"")||"":""}function a(e){var t=e.match(m);return t&&t[0]?e.substring(t[0].length):e}function s(e){return u(e).pragmas}function u(e){var t=(0,(p||n()).default)(e)||(f||r()).EOL;e=e.replace(h,"").replace(d,"").replace(E,"$1");for(var i="";i!==e;)i=e,e=e.replace(x,"".concat(t,"$1 $2").concat(t));e=e.replace(b,"").replace(v,"");for(var o,a=Object.create(null),s=e.replace(C,"").replace(b,"").replace(v,"");o=C.exec(e);){var u=o[2].replace(g,"");"string"===typeof a[o[1]]||Array.isArray(a[o[1]])?a[o[1]]=[].concat(a[o[1]],u):a[o[1]]=u}return{comments:s,pragmas:a}}function c(e){var t=e.comments,i=void 0===t?"":t,o=e.pragmas,a=void 0===o?{}:o,s=(0,(p||n()).default)(i)||(f||r()).EOL,u=Object.keys(a),c=u.map(function(e){return l(e,a[e])}).reduce(function(e,t){return e.concat(t)},[]).map(function(e){return" * "+e+s}).join("");if(!i){if(0===u.length)return"";if(1===u.length&&!Array.isArray(a[u[0]])){var d=a[u[0]];return"".concat("/**"," ").concat(l(u[0],d)[0]).concat(" */")}}var h=i.split(s).map(function(e){return"".concat(" *"," ").concat(e)}).join(s)+s;return"/**"+s+(i?h:"")+(i&&u.length?" *"+s:"")+c+" */"}function l(e,t){return[].concat(t).map(function(t){return"@".concat(e," ").concat(t).trim()})}Object.defineProperty(t,"__esModule",{value:!0}),t.extract=o,t.strip=a,t.parse=s,t.parseWithComments=u,t.print=c;var p,f,d=/\*\/$/,h=/^\/\*\*/,m=/^\s*(\/\*\*?(.|\r?\n)*?\*\/)/,g=/(^|\s+)\/\/([^\r\n]*)/g,y=/^\s*/,v=/\s*$/,b=/^(\r?\n)+/,x=/(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *(?![^@\r\n]*\/\/[^]*)([^@\r\n\s][^@\r\n]+?) *\r?\n/g,C=/(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g,E=/(\r?\n|^) *\* ?/g});unwrapExports(build);var pragma={hasPragma:hasPragma,insertPragma:insertPragma$1},addLeadingComment$2=utilShared.addLeadingComment,addTrailingComment$2=utilShared.addTrailingComment,addDanglingComment$2=utilShared.addDanglingComment,comments$3={handleOwnLineComment:handleOwnLineComment,handleEndOfLineComment:handleEndOfLineComment,handleRemainingComment:handleRemainingComment,isBlockComment:isBlockComment},needsParens_1=needsParens,getParentExportDeclaration$1=util.getParentExportDeclaration,isExportDeclaration$1=util.isExportDeclaration,shouldFlatten$1=util.shouldFlatten,getNextNonSpaceNonCommentCharacter$1=util.getNextNonSpaceNonCommentCharacter,hasNewline$2=util.hasNewline,hasNewlineInRange$1=util.hasNewlineInRange,getLast$4=util.getLast,getStringWidth$1=util.getStringWidth,printString$1=util.printString,printNumber$1=util.printNumber,hasIgnoreComment$1=util.hasIgnoreComment,skipWhitespace$1=util.skipWhitespace,hasNodeIgnoreComment$1=util.hasNodeIgnoreComment,getPenultimate$1=util.getPenultimate,startsWithNoLookaheadToken$1=util.startsWithNoLookaheadToken,getIndentSize$1=util.getIndentSize,isNextLineEmpty$2=utilShared.isNextLineEmpty,isNextLineEmptyAfterIndex$1=utilShared.isNextLineEmptyAfterIndex,getNextNonSpaceNonCommentCharacterIndex$2=utilShared.getNextNonSpaceNonCommentCharacterIndex,isIdentifierName=utils.keyword.isIdentifierNameES6,insertPragma=pragma.insertPragma,_require$$4$builders=doc.builders,concat$4=_require$$4$builders.concat,join$2=_require$$4$builders.join,line$3=_require$$4$builders.line,hardline$3=_require$$4$builders.hardline,softline$1=_require$$4$builders.softline,literalline$1=_require$$4$builders.literalline,group$1=_require$$4$builders.group,indent$2=_require$$4$builders.indent,align$1=_require$$4$builders.align,conditionalGroup$1=_require$$4$builders.conditionalGroup,fill$2=_require$$4$builders.fill,ifBreak$1=_require$$4$builders.ifBreak,breakParent$2=_require$$4$builders.breakParent,lineSuffixBoundary$1=_require$$4$builders.lineSuffixBoundary,addAlignmentToDoc$2=_require$$4$builders.addAlignmentToDoc,dedent$2=_require$$4$builders.dedent,_require$$4$utils=doc.utils,willBreak$1=_require$$4$utils.willBreak,isLineNext$1=_require$$4$utils.isLineNext,isEmpty$1=_require$$4$utils.isEmpty,removeLines$1=_require$$4$utils.removeLines,printDocToString$1=doc.printer.printDocToString,functionCompositionFunctionNames={pipe:!0,pipeP:!0,pipeK:!0,compose:!0,composeFlipped:!0,composeP:!0,composeK:!0,flow:!0,flowRight:!0,connect:!0},jsxWhitespaceChars=" \n\r\t",containsNonJsxWhitespaceRegex=new RegExp("[^"+jsxWhitespaceChars+"]"),matchJsxWhitespaceRegex=new RegExp("(["+jsxWhitespaceChars+"]+)"),unitTestRe=/^(skip|[fx]?(it|describe|test))$/,printerEstree={print:genericPrint$1,embed:embed_1,insertPragma:insertPragma,massageAstNode:clean_1,hasPrettierIgnore:hasPrettierIgnore,willPrintOwnComments:willPrintOwnComments,canAttachComment:canAttachComment,printComment:printComment$1,isBlockComment:comments$3.isBlockComment,handleComments:{ownLine:comments$3.handleOwnLineComment,endOfLine:comments$3.handleEndOfLineComment,remaining:comments$3.handleRemainingComment}},_require$$0$builders$2=doc.builders,concat$6=_require$$0$builders$2.concat,hardline$5=_require$$0$builders$2.hardline,indent$4=_require$$0$builders$2.indent,join$4=_require$$0$builders$2.join,printerEstreeJson={print:genericPrint$2,massageAstNode:clean$2},CATEGORY_COMMON="Common",commonOptions={bracketSpacing:{since:"0.0.0",category:CATEGORY_COMMON,type:"boolean",default:!0,description:"Print spaces between brackets.",oppositeDescription:"Do not print spaces between brackets."},singleQuote:{since:"0.0.0",category:CATEGORY_COMMON,type:"boolean",default:!1,description:"Use single quotes instead of double quotes."}},CATEGORY_JAVASCRIPT="JavaScript",options$3={arrowParens:{since:"1.9.0",category:CATEGORY_JAVASCRIPT,type:"choice",default:"avoid",description:"Include parentheses around a sole arrow function parameter.",choices:[{value:"avoid",description:"Omit parens when possible. Example: `x => x`"},{value:"always",description:"Always include parens. Example: `(x) => x`"}]},bracketSpacing:commonOptions.bracketSpacing,jsxBracketSameLine:{since:"0.17.0",category:CATEGORY_JAVASCRIPT,type:"boolean",default:!1,description:"Put > on the last line instead of at a new line."},semi:{since:"1.0.0",category:CATEGORY_JAVASCRIPT,type:"boolean",default:!0,description:"Print semicolons.",oppositeDescription:"Do not print semicolons, except at the beginning of lines which may need them."},singleQuote:commonOptions.singleQuote,trailingComma:{since:"0.0.0",category:CATEGORY_JAVASCRIPT,type:"choice",default:[{since:"0.0.0",value:!1},{since:"0.19.0",value:"none"}],description:"Print trailing commas wherever possible when multi-line.",choices:[{value:"none",description:"No trailing commas."},{value:"es5",description:"Trailing commas where valid in ES5 (objects, arrays, etc.)"},{value:"all",description:"Trailing commas wherever possible (including function arguments)."},{value:!0,deprecated:"0.19.0",redirect:"es5"},{value:!1,deprecated:"0.19.0",redirect:"none"}]}},languages=[{name:"JavaScript",since:"0.0.0",parsers:["babylon","flow"],group:"JavaScript",tmScope:"source.js",aceMode:"javascript",codemirrorMode:"javascript",codemirrorMimeType:"text/javascript",aliases:["js","node"],extensions:[".js","._js",".bones",".es",".es6",".frag",".gs",".jake",".jsb",".jscad",".jsfl",".jsm",".jss",".mjs",".njs",".pac",".sjs",".ssjs",".xsjs",".xsjslib"],filenames:["Jakefile"],linguistLanguageId:183,vscodeLanguageIds:["javascript"]},{name:"JSX",since:"0.0.0",parsers:["babylon","flow"],group:"JavaScript",extensions:[".jsx"],tmScope:"source.js.jsx",aceMode:"javascript",codemirrorMode:"jsx",codemirrorMimeType:"text/jsx",liguistLanguageId:178,vscodeLanguageIds:["javascriptreact"]},{name:"TypeScript",since:"1.4.0",parsers:["typescript-eslint"],group:"JavaScript",aliases:["ts"],extensions:[".ts",".tsx"],tmScope:"source.ts",aceMode:"typescript",codemirrorMode:"javascript",codemirrorMimeType:"application/typescript",liguistLanguageId:378,vscodeLanguageIds:["typescript","typescriptreact"]},{name:"JSON.stringify",since:"1.13.0",parsers:["json-stringify"],group:"JavaScript",tmScope:"source.json",aceMode:"json",codemirrorMode:"javascript",codemirrorMimeType:"application/json",extensions:[],filenames:["package.json","package-lock.json","composer.json"],linguistLanguageId:174,vscodeLanguageIds:["json"]},{name:"JSON",since:"1.5.0",parsers:["json"],group:"JavaScript",tmScope:"source.json",aceMode:"json",codemirrorMode:"javascript",codemirrorMimeType:"application/json",extensions:[".json",".geojson",".JSON-tmLanguage",".topojson"],filenames:[".arcconfig",".jshintrc",".eslintrc",".prettierrc","composer.lock","mcmod.info"],linguistLanguageId:174,vscodeLanguageIds:["json","jsonc"]},{name:"JSON5",since:"1.13.0",parsers:["json5"],group:"JavaScript",tmScope:"source.json",aceMode:"json",codemirrorMode:"javascript",codemirrorMimeType:"application/json",extensions:[".json5"],filenames:[".babelrc"],linguistLanguageId:175,vscodeLanguageIds:["json5"]}],printers={estree:printerEstree,"estree-json":printerEstreeJson},languageJs={languages:languages,options:options$3,printers:printers},index$5=["a","abbr","acronym","address","applet","area","article","aside","audio","b","base","basefont","bdi","bdo","bgsound","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","command","content","data","datalist","dd","del","details","dfn","dialog","dir","div","dl","dt","element","em","embed","fieldset","figcaption","figure","font","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","image","img","input","ins","isindex","kbd","keygen","label","legend","li","link","listing","main","map","mark","marquee","math","menu","menuitem","meta","meter","multicol","nav","nextid","nobr","noembed","noframes","noscript","object","ol","optgroup","option","output","p","param","picture","plaintext","pre","progress","q","rb","rbc","rp","rt","rtc","ruby","s","samp","script","section","select","shadow","slot","small","source","spacer","span","strike","strong","style","sub","summary","sup","svg","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr","xmp"],htmlTagNames=Object.freeze({default:index$5}),htmlTagNames$1=htmlTagNames&&index$5||htmlTagNames,clean_1$2=clean$3,utils$4={getAncestorCounter:getAncestorCounter,getAncestorNode:getAncestorNode$1,getPropOfDeclNode:getPropOfDeclNode$1,maybeToLowerCase:maybeToLowerCase$1,insideValueFunctionNode:insideValueFunctionNode$1,insideICSSRuleNode:insideICSSRuleNode$1,insideAtRuleNode:insideAtRuleNode$1,insideURLFunctionInImportAtRuleNode:insideURLFunctionInImportAtRuleNode$1,isKeyframeAtRuleKeywords:isKeyframeAtRuleKeywords$1,isHTMLTag:isHTMLTag$1,isWideKeywords:isWideKeywords$1,isSCSS:isSCSS$1,isLastNode:isLastNode$1,isSCSSControlDirectiveNode:isSCSSControlDirectiveNode$1,isDetachedRulesetDeclarationNode:isDetachedRulesetDeclarationNode$1,isRelationalOperatorNode:isRelationalOperatorNode$1,isEqualityOperatorNode:isEqualityOperatorNode$1,isMultiplicationNode:isMultiplicationNode$1,isDivisionNode:isDivisionNode$1,isAdditionNode:isAdditionNode$1,isSubtractionNode:isSubtractionNode$1,isModuloNode:isModuloNode,isMathOperatorNode:isMathOperatorNode$1,isEachKeywordNode:isEachKeywordNode$1,isForKeywordNode:isForKeywordNode$1,isURLFunctionNode:isURLFunctionNode$1,isIfElseKeywordNode:isIfElseKeywordNode$1,hasComposesNode:hasComposesNode$1,hasParensAroundNode:hasParensAroundNode$1,hasEmptyRawBefore:hasEmptyRawBefore$1,isSCSSNestedPropertyNode:isSCSSNestedPropertyNode,isDetachedRulesetCallNode:isDetachedRulesetCallNode$1,isPostcssSimpleVarNode:isPostcssSimpleVarNode$1,isKeyValuePairNode:isKeyValuePairNode$1,isKeyValuePairInParenGroupNode:isKeyValuePairInParenGroupNode,isSCSSMapItemNode:isSCSSMapItemNode$1,isInlineValueCommentNode:isInlineValueCommentNode$1,isHashNode:isHashNode$1,isLeftCurlyBraceNode:isLeftCurlyBraceNode$1,isRightCurlyBraceNode:isRightCurlyBraceNode$1,isWordNode:isWordNode$1,isColonNode:isColonNode$1,isMediaAndSupportsKeywords:isMediaAndSupportsKeywords$1},printNumber$2=util.printNumber,printString$2=util.printString,hasIgnoreComment$2=util.hasIgnoreComment,hasNewline$3=util.hasNewline,isNextLineEmpty$3=utilShared.isNextLineEmpty,_require$$2$builders=doc.builders,concat$7=_require$$2$builders.concat,join$5=_require$$2$builders.join,line$4=_require$$2$builders.line,hardline$6=_require$$2$builders.hardline,softline$3=_require$$2$builders.softline,group$2=_require$$2$builders.group,fill$3=_require$$2$builders.fill,indent$5=_require$$2$builders.indent,dedent$3=_require$$2$builders.dedent,ifBreak$2=_require$$2$builders.ifBreak,removeLines$2=doc.utils.removeLines,getAncestorNode=utils$4.getAncestorNode,getPropOfDeclNode=utils$4.getPropOfDeclNode,maybeToLowerCase=utils$4.maybeToLowerCase,insideValueFunctionNode=utils$4.insideValueFunctionNode,insideICSSRuleNode=utils$4.insideICSSRuleNode,insideAtRuleNode=utils$4.insideAtRuleNode,insideURLFunctionInImportAtRuleNode=utils$4.insideURLFunctionInImportAtRuleNode,isKeyframeAtRuleKeywords=utils$4.isKeyframeAtRuleKeywords,isHTMLTag=utils$4.isHTMLTag,isWideKeywords=utils$4.isWideKeywords,isSCSS=utils$4.isSCSS,isLastNode=utils$4.isLastNode,isSCSSControlDirectiveNode=utils$4.isSCSSControlDirectiveNode,isDetachedRulesetDeclarationNode=utils$4.isDetachedRulesetDeclarationNode,isRelationalOperatorNode=utils$4.isRelationalOperatorNode,isEqualityOperatorNode=utils$4.isEqualityOperatorNode,isMultiplicationNode=utils$4.isMultiplicationNode,isDivisionNode=utils$4.isDivisionNode,isAdditionNode=utils$4.isAdditionNode,isSubtractionNode=utils$4.isSubtractionNode,isMathOperatorNode=utils$4.isMathOperatorNode,isEachKeywordNode=utils$4.isEachKeywordNode,isForKeywordNode=utils$4.isForKeywordNode,isURLFunctionNode=utils$4.isURLFunctionNode,isIfElseKeywordNode=utils$4.isIfElseKeywordNode,hasComposesNode=utils$4.hasComposesNode,hasParensAroundNode=utils$4.hasParensAroundNode,hasEmptyRawBefore=utils$4.hasEmptyRawBefore,isKeyValuePairNode=utils$4.isKeyValuePairNode,isDetachedRulesetCallNode=utils$4.isDetachedRulesetCallNode,isPostcssSimpleVarNode=utils$4.isPostcssSimpleVarNode,isSCSSMapItemNode=utils$4.isSCSSMapItemNode,isInlineValueCommentNode=utils$4.isInlineValueCommentNode,isHashNode=utils$4.isHashNode,isLeftCurlyBraceNode=utils$4.isLeftCurlyBraceNode,isRightCurlyBraceNode=utils$4.isRightCurlyBraceNode,isWordNode=utils$4.isWordNode,isColonNode=utils$4.isColonNode,isMediaAndSupportsKeywords=utils$4.isMediaAndSupportsKeywords,STRING_REGEX=/(['"])(?:(?!\1)[^\\]|\\[\s\S])*\1/g,NUMBER_REGEX=/(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g,STANDARD_UNIT_REGEX=/[a-zA-Z]+/g,WORD_PART_REGEX=/[$@]?[a-zA-Z_\u0080-\uFFFF][\w\-\u0080-\uFFFF]*/g,ADJUST_NUMBERS_REGEX=RegExp(STRING_REGEX.source+"|"+"(".concat(WORD_PART_REGEX.source,")?")+"(".concat(NUMBER_REGEX.source,")")+"(".concat(STANDARD_UNIT_REGEX.source,")?"),"g"),printerPostcss={print:genericPrint$3,hasPrettierIgnore:hasIgnoreComment$2,massageAstNode:clean_1$2},options$6={singleQuote:commonOptions.singleQuote},languages$1=[{name:"CSS",since:"1.4.0",parsers:["css"],group:"CSS",tmScope:"source.css",aceMode:"css",codemirrorMode:"css",codemirrorMimeType:"text/css",extensions:[".css",".pcss",".postcss"],liguistLanguageId:50,vscodeLanguageIds:["css","postcss"]},{name:"Less",since:"1.4.0",parsers:["less"],group:"CSS",extensions:[".less"],tmScope:"source.css.less",aceMode:"less",codemirrorMode:"css",codemirrorMimeType:"text/css",liguistLanguageId:198,vscodeLanguageIds:["less"]},{name:"SCSS",since:"1.4.0",parsers:["scss"],group:"CSS",tmScope:"source.scss",aceMode:"scss",codemirrorMode:"css",codemirrorMimeType:"text/x-scss",extensions:[".scss"],liguistLanguageId:329,vscodeLanguageIds:["scss"]}],printers$1={postcss:printerPostcss},languageCss={languages:languages$1,options:options$6,printers:printers$1},_require$$0$builders$3=doc.builders,concat$8=_require$$0$builders$3.concat,join$6=_require$$0$builders$3.join,hardline$7=_require$$0$builders$3.hardline,line$5=_require$$0$builders$3.line,softline$4=_require$$0$builders$3.softline,group$3=_require$$0$builders$3.group,indent$6=_require$$0$builders$3.indent,ifBreak$3=_require$$0$builders$3.ifBreak,hasIgnoreComment$3=util.hasIgnoreComment,isNextLineEmpty$4=utilShared.isNextLineEmpty,printerGraphql={print:genericPrint$4,massageAstNode:clean$5,hasPrettierIgnore:hasIgnoreComment$3,printComment:printComment$2,canAttachComment:canAttachComment$1},options$9={bracketSpacing:commonOptions.bracketSpacing},languages$2=[{name:"GraphQL",since:"1.5.0",parsers:["graphql"],extensions:[".graphql",".gql"],tmScope:"source.graphql",aceMode:"text",liguistLanguageId:139,vscodeLanguageIds:["graphql"]}],printers$2={graphql:printerGraphql},languageGraphql={languages:languages$2,options:options$9,printers:printers$2},_require$$0$builders$5=doc.builders,hardline$9=_require$$0$builders$5.hardline,literalline$3=_require$$0$builders$5.literalline,concat$10=_require$$0$builders$5.concat,markAsRoot$1=_require$$0$builders$5.markAsRoot,mapDoc$4=doc.utils.mapDoc,embed_1$2=embed$2,frontMatter=parse$3,pragma$2=createCommonjsModule(function(e){function t(e){var t="@(".concat(n.join("|"),")"),r=new RegExp(["\x3c!--\\s*".concat(t,"\\s*--\x3e"),"\x3c!--.*\n[\\s\\S]*(^|\n)[^\\S\n]*".concat(t,"[^\\S\n]*($|\n)[\\s\\S]*\n.*--\x3e")].join("|"),"m"),i=e.match(r);return i&&0===i.index}var n=["format","prettier"];e.exports={startWithPragma:t,hasPragma:function(e){return t(frontMatter(e).content.trimLeft())},insertPragma:function(e){var t=frontMatter(e),r="\x3c!-- @".concat(n[0]," --\x3e");return t.frontMatter?"".concat(t.frontMatter,"\n\n").concat(r,"\n\n").concat(t.content):"".concat(r,"\n\n").concat(t.content)}}}),_require$$0$builders$4=doc.builders,concat$9=_require$$0$builders$4.concat,join$7=_require$$0$builders$4.join,line$6=_require$$0$builders$4.line,hardline$8=_require$$0$builders$4.hardline,softline$5=_require$$0$builders$4.softline,fill$4=_require$$0$builders$4.fill,align$2=_require$$0$builders$4.align,indent$7=_require$$0$builders$4.indent,group$4=_require$$0$builders$4.group,mapDoc$3=doc.utils.mapDoc,printDocToString$2=doc.printer.printDocToString,SINGLE_LINE_NODE_TYPES=["heading","tableCell","link"],SIBLING_NODE_TYPES=["listItem","definition","footnoteDefinition"],INLINE_NODE_TYPES=["liquidNode","inlineCode","emphasis","strong","delete","link","linkReference","image","imageReference","footnote","footnoteReference","sentence","whitespace","word","break"],INLINE_NODE_WRAPPER_TYPES=INLINE_NODE_TYPES.concat(["tableCell","paragraph","heading"]),printerMarkdown={print:genericPrint$5,embed:embed_1$2,massageAstNode:clean$6,hasPrettierIgnore:hasPrettierIgnore$1,insertPragma:pragma$2.insertPragma},CATEGORY_MARKDOWN="Markdown",options$12={proseWrap:{since:"1.8.2",category:CATEGORY_MARKDOWN,type:"choice",default:[{since:"1.8.2",value:!0},{since:"1.9.0",value:"preserve"}],description:"How to wrap prose. (markdown)",choices:[{since:"1.9.0",value:"always",description:"Wrap prose if it exceeds the print width."},{since:"1.9.0",value:"never",description:"Do not wrap prose."},{since:"1.9.0",value:"preserve",description:"Wrap prose as-is."},{value:!1,deprecated:"1.9.0",redirect:"never"},{value:!0,deprecated:"1.9.0",redirect:"always"}]},singleQuote:commonOptions.singleQuote},languages$3=[{name:"Markdown",since:"1.8.0",parsers:["remark"],aliases:["pandoc"],aceMode:"markdown",codemirrorMode:"gfm",codemirrorMimeType:"text/x-gfm",wrap:!0,extensions:[".md",".markdown",".mdown",".mdwn",".mkd",".mkdn",".mkdown",".ron",".workbook"],filenames:["README"],tmScope:"source.gfm",linguistLanguageId:222,vscodeLanguageIds:["markdown"]}],printers$3={mdast:printerMarkdown},languageMarkdown={languages:languages$3,options:options$12,printers:printers$3},_require$$0$builders$7=doc.builders,concat$12=_require$$0$builders$7.concat,hardline$11=_require$$0$builders$7.hardline,embed_1$4=embed$4,_require$$0$builders$6=doc.builders,concat$11=_require$$0$builders$6.concat,hardline$10=_require$$0$builders$6.hardline,clean$7=function(e,t){delete t.start,delete t.end,delete t.contentStart,delete t.contentEnd},printerVue={print:genericPrint$6,embed:embed_1$4,massageAstNode:clean$7},languages$4=[{name:"Vue",since:"1.10.0",parsers:["vue"],group:"HTML",tmScope:"text.html.vue",aceMode:"html",codemirrorMode:"htmlmixed",codemirrorMimeType:"text/html",extensions:[".vue"],linguistLanguageId:146,vscodeLanguageIds:["vue"]}],printers$4={vue:printerVue},languageVue={languages:languages$4,printers:printers$4},version=require$$0.version,getSupportInfo=support.getSupportInfo,internalPlugins=[languageJs,languageCss,languageGraphql,languageMarkdown,languageVue],isArray=Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)},formatWithCursor=withPlugins(core.formatWithCursor),standalone={formatWithCursor:formatWithCursor,format:function(e,t){return formatWithCursor(e,t).formatted},check:function(e,t){return formatWithCursor(e,t).formatted===e},doc:doc,getSupportInfo:withPlugins(getSupportInfo),version:version,util:utilShared,__debug:{parse:withPlugins(core.parse),formatAST:withPlugins(core.formatAST),formatDoc:withPlugins(core.formatDoc),printToDoc:withPlugins(core.printToDoc),printDocToString:withPlugins(core.printDocToString)}};return standalone})}).call(exports,__webpack_require__(11))},function(e,t,n){!function(t,n){e.exports=n()}(0,function(){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function n(e,t){return e(t={exports:{}},t.exports),t.exports}var r=function(e,t){var n=new SyntaxError(e+" ("+t.start.line+":"+t.start.column+")");return n.loc=t,n},i=n(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.getLocation=function(e,t){for(var n=/\r\n|[\n\r]/g,r=1,i=t+1,o=void 0;(o=n.exec(e.body))&&o.index=2&&o(f,c)+": "+d[n-2],o(f,l)+": "+d[n-1],r(2+f+u-1)+"^",n0&&r(t[0]);)t.shift();for(;t.length>0&&r(t[t.length-1]);)t.pop();return t.join("\n")}});t(d);var h=n(function(e,t){function n(){return this.lastToken=this.token,this.token=this.lookahead()}function r(){var e=this.token;if(e.kind!==p.EOF)do{e=e.next||(e.next=a(this,e))}while(e.kind===p.COMMENT);return e}function i(e,t,n,r,i,o,a){this.kind=e,this.start=t,this.end=n,this.line=r,this.column=i,this.value=a,this.prev=o,this.next=null}function o(e){return isNaN(e)?p.EOF:e<127?JSON.stringify(String.fromCharCode(e)):'"\\u'+("00"+e.toString(16).toUpperCase()).slice(-4)+'"'}function a(e,t){var n=e.source,r=n.body,a=r.length,c=function(e,t,n){for(var r=e.length,i=t;i=a)return new i(p.EOF,a,a,d,g,t);var y=h.call(r,c);if(y<32&&9!==y&&10!==y&&13!==y)throw(0,f.syntaxError)(n,c,"Cannot contain the invalid character "+o(y)+".");switch(y){case 33:return new i(p.BANG,c,c+1,d,g,t);case 35:return function(e,t,n,r,o){var a=e.body,s=void 0,u=t;do{s=h.call(a,++u)}while(null!==s&&(s>31||9===s));return new i(p.COMMENT,t,u,n,r,o,m.call(a,t+1,u))}(n,c,d,g,t);case 36:return new i(p.DOLLAR,c,c+1,d,g,t);case 38:return new i(p.AMP,c,c+1,d,g,t);case 40:return new i(p.PAREN_L,c,c+1,d,g,t);case 41:return new i(p.PAREN_R,c,c+1,d,g,t);case 46:if(46===h.call(r,c+1)&&46===h.call(r,c+2))return new i(p.SPREAD,c,c+3,d,g,t);break;case 58:return new i(p.COLON,c,c+1,d,g,t);case 61:return new i(p.EQUALS,c,c+1,d,g,t);case 64:return new i(p.AT,c,c+1,d,g,t);case 91:return new i(p.BRACKET_L,c,c+1,d,g,t);case 93:return new i(p.BRACKET_R,c,c+1,d,g,t);case 123:return new i(p.BRACE_L,c,c+1,d,g,t);case 124:return new i(p.PIPE,c,c+1,d,g,t);case 125:return new i(p.BRACE_R,c,c+1,d,g,t);case 65:case 66:case 67:case 68:case 69:case 70:case 71:case 72:case 73:case 74:case 75:case 76:case 77:case 78:case 79:case 80:case 81:case 82:case 83:case 84:case 85:case 86:case 87:case 88:case 89:case 90:case 95:case 97:case 98:case 99:case 100:case 101:case 102:case 103:case 104:case 105:case 106:case 107:case 108:case 109:case 110:case 111:case 112:case 113:case 114:case 115:case 116:case 117:case 118:case 119:case 120:case 121:case 122:return function(e,t,n,r,o){for(var a=e.body,s=a.length,u=t+1,c=0;u!==s&&null!==(c=h.call(a,u))&&(95===c||c>=48&&c<=57||c>=65&&c<=90||c>=97&&c<=122);)++u;return new i(p.NAME,t,u,n,r,o,m.call(a,t,u))}(n,c,d,g,t);case 45:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return function(e,t,n,r,a,u){var c=e.body,l=n,d=t,g=!1;if(45===l&&(l=h.call(c,++d)),48===l){if((l=h.call(c,++d))>=48&&l<=57)throw(0,f.syntaxError)(e,d,"Invalid number, unexpected digit after 0: "+o(l)+".")}else d=s(e,d,l),l=h.call(c,d);return 46===l&&(g=!0,l=h.call(c,++d),d=s(e,d,l),l=h.call(c,d)),69!==l&&101!==l||(g=!0,43!==(l=h.call(c,++d))&&45!==l||(l=h.call(c,++d)),d=s(e,d,l)),new i(g?p.FLOAT:p.INT,t,d,r,a,u,m.call(c,t,d))}(n,c,y,d,g,t);case 34:return 34===h.call(r,c+1)&&34===h.call(r,c+2)?function(e,t,n,r,a){for(var s=e.body,u=t+3,c=u,d=0,g="";u=48&&a<=57){do{a=h.call(r,++i)}while(a>=48&&a<=57);return i}throw(0,f.syntaxError)(e,i,"Invalid number, expected digit but got: "+o(a)+".")}function u(e){return e>=48&&e<=57?e-48:e>=65&&e<=70?e-55:e>=97&&e<=102?e-87:-1}Object.defineProperty(t,"__esModule",{value:!0}),t.TokenKind=void 0,t.createLexer=function(e,t){var o=new i(p.SOF,0,0,0,0,null);return{source:e,options:t,lastToken:o,token:o,line:1,lineStart:0,advance:n,lookahead:r}},t.getTokenDesc=function(e){var t=e.value;return t?e.kind+' "'+t+'"':e.kind};var c,l=(c=d)&&c.__esModule?c:{default:c},p=t.TokenKind=Object.freeze({SOF:"",EOF:"",BANG:"!",DOLLAR:"$",AMP:"&",PAREN_L:"(",PAREN_R:")",SPREAD:"...",COLON:":",EQUALS:"=",AT:"@",BRACKET_L:"[",BRACKET_R:"]",BRACE_L:"{",PIPE:"|",BRACE_R:"}",NAME:"Name",INT:"Int",FLOAT:"Float",STRING:"String",BLOCK_STRING:"BlockString",COMMENT:"Comment"}),h=String.prototype.charCodeAt,m=String.prototype.slice;i.prototype.toJSON=i.prototype.inspect=function(){return{kind:this.kind,value:this.value,line:this.line,column:this.column}}});t(h);var m=n(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.Source=void 0;var n,r=(n=l)&&n.__esModule?n:{default:n};t.Source=function e(t,n,i){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.body=t,this.name=n||"GraphQL request",this.locationOffset=i||{line:1,column:1},this.locationOffset.line>0||(0,r.default)(0,"line in locationOffset is 1-indexed and must be positive"),this.locationOffset.column>0||(0,r.default)(0,"column in locationOffset is 1-indexed and must be positive")}});t(m);var g=n(function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.DirectiveLocation=Object.freeze({QUERY:"QUERY",MUTATION:"MUTATION",SUBSCRIPTION:"SUBSCRIPTION",FIELD:"FIELD",FRAGMENT_DEFINITION:"FRAGMENT_DEFINITION",FRAGMENT_SPREAD:"FRAGMENT_SPREAD",INLINE_FRAGMENT:"INLINE_FRAGMENT",SCHEMA:"SCHEMA",SCALAR:"SCALAR",OBJECT:"OBJECT",FIELD_DEFINITION:"FIELD_DEFINITION",ARGUMENT_DEFINITION:"ARGUMENT_DEFINITION",INTERFACE:"INTERFACE",UNION:"UNION",ENUM:"ENUM",ENUM_VALUE:"ENUM_VALUE",INPUT_OBJECT:"INPUT_OBJECT",INPUT_FIELD_DEFINITION:"INPUT_FIELD_DEFINITION"})});t(g);var y=n(function(e,t){function n(e){var t=Q(e,h.TokenKind.NAME);return{kind:o.Kind.NAME,value:t.value,loc:V(e,t)}}function r(e){if(H(e,h.TokenKind.NAME))switch(e.token.value){case"query":case"mutation":case"subscription":case"fragment":return i(e);case"schema":case"scalar":case"type":case"interface":case"union":case"enum":case"input":case"extend":case"directive":return O(e)}else{if(H(e,h.TokenKind.BRACE_L))return i(e);if(F(e))return O(e)}throw J(e)}function i(e){if(H(e,h.TokenKind.NAME))switch(e.token.value){case"query":case"mutation":case"subscription":return a(e);case"fragment":return function(e){var t=e.token;return K(e,"fragment"),e.options.experimentalFragmentVariables?{kind:o.Kind.FRAGMENT_DEFINITION,name:x(e),variableDefinitions:u(e),typeCondition:(K(e,"on"),T(e)),directives:k(e,!1),selectionSet:p(e),loc:V(e,t)}:{kind:o.Kind.FRAGMENT_DEFINITION,name:x(e),typeCondition:(K(e,"on"),T(e)),directives:k(e,!1),selectionSet:p(e),loc:V(e,t)}}(e)}else if(H(e,h.TokenKind.BRACE_L))return a(e);throw J(e)}function a(e){var t=e.token;if(H(e,h.TokenKind.BRACE_L))return{kind:o.Kind.OPERATION_DEFINITION,operation:"query",name:void 0,variableDefinitions:[],directives:[],selectionSet:p(e),loc:V(e,t)};var r=s(e),i=void 0;return H(e,h.TokenKind.NAME)&&(i=n(e)),{kind:o.Kind.OPERATION_DEFINITION,operation:r,name:i,variableDefinitions:u(e),directives:k(e,!1),selectionSet:p(e),loc:V(e,t)}}function s(e){var t=Q(e,h.TokenKind.NAME);switch(t.value){case"query":return"query";case"mutation":return"mutation";case"subscription":return"subscription"}throw J(e,t)}function u(e){return H(e,h.TokenKind.PAREN_L)?Y(e,h.TokenKind.PAREN_L,c,h.TokenKind.PAREN_R):[]}function c(e){var t=e.token;return{kind:o.Kind.VARIABLE_DEFINITION,variable:l(e),type:(Q(e,h.TokenKind.COLON),_(e)),defaultValue:W(e,h.TokenKind.EQUALS)?C(e,!0):void 0,loc:V(e,t)}}function l(e){var t=e.token;return Q(e,h.TokenKind.DOLLAR),{kind:o.Kind.VARIABLE,name:n(e),loc:V(e,t)}}function p(e){var t=e.token;return{kind:o.Kind.SELECTION_SET,selections:Y(e,h.TokenKind.BRACE_L,d,h.TokenKind.BRACE_R),loc:V(e,t)}}function d(e){return H(e,h.TokenKind.SPREAD)?function(e){var t=e.token;if(Q(e,h.TokenKind.SPREAD),H(e,h.TokenKind.NAME)&&"on"!==e.token.value)return{kind:o.Kind.FRAGMENT_SPREAD,name:x(e),directives:k(e,!1),loc:V(e,t)};var n=void 0;return"on"===e.token.value&&(e.advance(),n=T(e)),{kind:o.Kind.INLINE_FRAGMENT,typeCondition:n,directives:k(e,!1),selectionSet:p(e),loc:V(e,t)}}(e):function(e){var t=e.token,r=n(e),i=void 0,a=void 0;return W(e,h.TokenKind.COLON)?(i=r,a=n(e)):a=r,{kind:o.Kind.FIELD,alias:i,name:a,arguments:y(e,!1),directives:k(e,!1),selectionSet:H(e,h.TokenKind.BRACE_L)?p(e):void 0,loc:V(e,t)}}(e)}function y(e,t){var n=t?b:v;return H(e,h.TokenKind.PAREN_L)?Y(e,h.TokenKind.PAREN_L,n,h.TokenKind.PAREN_R):[]}function v(e){var t=e.token;return{kind:o.Kind.ARGUMENT,name:n(e),value:(Q(e,h.TokenKind.COLON),C(e,!1)),loc:V(e,t)}}function b(e){var t=e.token;return{kind:o.Kind.ARGUMENT,name:n(e),value:(Q(e,h.TokenKind.COLON),D(e)),loc:V(e,t)}}function x(e){if("on"===e.token.value)throw J(e);return n(e)}function C(e,t){var n=e.token;switch(n.kind){case h.TokenKind.BRACKET_L:return function(e,t){var n=e.token,r=t?D:w;return{kind:o.Kind.LIST,values:function(e,t,n,r){Q(e,t);for(var i=[];!W(e,r);)i.push(n(e));return i}(e,h.TokenKind.BRACKET_L,r,h.TokenKind.BRACKET_R),loc:V(e,n)}}(e,t);case h.TokenKind.BRACE_L:return function(e,t){var n=e.token;Q(e,h.TokenKind.BRACE_L);for(var r=[];!W(e,h.TokenKind.BRACE_R);)r.push(S(e,t));return{kind:o.Kind.OBJECT,fields:r,loc:V(e,n)}}(e,t);case h.TokenKind.INT:return e.advance(),{kind:o.Kind.INT,value:n.value,loc:V(e,n)};case h.TokenKind.FLOAT:return e.advance(),{kind:o.Kind.FLOAT,value:n.value,loc:V(e,n)};case h.TokenKind.STRING:case h.TokenKind.BLOCK_STRING:return E(e);case h.TokenKind.NAME:return"true"===n.value||"false"===n.value?(e.advance(),{kind:o.Kind.BOOLEAN,value:"true"===n.value,loc:V(e,n)}):"null"===n.value?(e.advance(),{kind:o.Kind.NULL,loc:V(e,n)}):(e.advance(),{kind:o.Kind.ENUM,value:n.value,loc:V(e,n)});case h.TokenKind.DOLLAR:if(!t)return l(e)}throw J(e)}function E(e){var t=e.token;return e.advance(),{kind:o.Kind.STRING,value:t.value,block:t.kind===h.TokenKind.BLOCK_STRING,loc:V(e,t)}}function D(e){return C(e,!0)}function w(e){return C(e,!1)}function S(e,t){var r=e.token;return{kind:o.Kind.OBJECT_FIELD,name:n(e),value:(Q(e,h.TokenKind.COLON),C(e,t)),loc:V(e,r)}}function k(e,t){for(var n=[];H(e,h.TokenKind.AT);)n.push(A(e,t));return n}function A(e,t){var r=e.token;return Q(e,h.TokenKind.AT),{kind:o.Kind.DIRECTIVE,name:n(e),arguments:y(e,t),loc:V(e,r)}}function _(e){var t=e.token,n=void 0;return W(e,h.TokenKind.BRACKET_L)?(n=_(e),Q(e,h.TokenKind.BRACKET_R),n={kind:o.Kind.LIST_TYPE,type:n,loc:V(e,t)}):n=T(e),W(e,h.TokenKind.BANG)?{kind:o.Kind.NON_NULL_TYPE,type:n,loc:V(e,t)}:n}function T(e){var t=e.token;return{kind:o.Kind.NAMED_TYPE,name:n(e),loc:V(e,t)}}function O(e){var t=F(e)?e.lookahead():e.token;if(t.kind===h.TokenKind.NAME)switch(t.value){case"schema":return function(e){var t=e.token;K(e,"schema");var n=k(e,!0),r=Y(e,h.TokenKind.BRACE_L,I,h.TokenKind.BRACE_R);return{kind:o.Kind.SCHEMA_DEFINITION,directives:n,operationTypes:r,loc:V(e,t)}}(e);case"scalar":return function(e){var t=e.token,r=N(e);K(e,"scalar");var i=n(e),a=k(e,!0);return{kind:o.Kind.SCALAR_TYPE_DEFINITION,description:r,name:i,directives:a,loc:V(e,t)}}(e);case"type":return function(e){var t=e.token,r=N(e);K(e,"type");var i=n(e),a=L(e),s=k(e,!0),u=P(e);return{kind:o.Kind.OBJECT_TYPE_DEFINITION,description:r,name:i,interfaces:a,directives:s,fields:u,loc:V(e,t)}}(e);case"interface":return function(e){var t=e.token,r=N(e);K(e,"interface");var i=n(e),a=k(e,!0),s=P(e);return{kind:o.Kind.INTERFACE_TYPE_DEFINITION,description:r,name:i,directives:a,fields:s,loc:V(e,t)}}(e);case"union":return function(e){var t=e.token,r=N(e);K(e,"union");var i=n(e),a=k(e,!0),s=B(e);return{kind:o.Kind.UNION_TYPE_DEFINITION,description:r,name:i,directives:a,types:s,loc:V(e,t)}}(e);case"enum":return function(e){var t=e.token,r=N(e);K(e,"enum");var i=n(e),a=k(e,!0),s=$(e);return{kind:o.Kind.ENUM_TYPE_DEFINITION,description:r,name:i,directives:a,values:s,loc:V(e,t)}}(e);case"input":return function(e){var t=e.token,r=N(e);K(e,"input");var i=n(e),a=k(e,!0),s=z(e);return{kind:o.Kind.INPUT_OBJECT_TYPE_DEFINITION,description:r,name:i,directives:a,fields:s,loc:V(e,t)}}(e);case"extend":return function(e){var t=e.lookahead();if(t.kind===h.TokenKind.NAME)switch(t.value){case"scalar":return function(e){var t=e.token;K(e,"extend"),K(e,"scalar");var r=n(e),i=k(e,!0);if(0===i.length)throw J(e);return{kind:o.Kind.SCALAR_TYPE_EXTENSION,name:r,directives:i,loc:V(e,t)}}(e);case"type":return function(e){var t=e.token;K(e,"extend"),K(e,"type");var r=n(e),i=L(e),a=k(e,!0),s=P(e);if(0===i.length&&0===a.length&&0===s.length)throw J(e);return{kind:o.Kind.OBJECT_TYPE_EXTENSION,name:r,interfaces:i,directives:a,fields:s,loc:V(e,t)}}(e);case"interface":return function(e){var t=e.token;K(e,"extend"),K(e,"interface");var r=n(e),i=k(e,!0),a=P(e);if(0===i.length&&0===a.length)throw J(e);return{kind:o.Kind.INTERFACE_TYPE_EXTENSION,name:r,directives:i,fields:a,loc:V(e,t)}}(e);case"union":return function(e){var t=e.token;K(e,"extend"),K(e,"union");var r=n(e),i=k(e,!0),a=B(e);if(0===i.length&&0===a.length)throw J(e);return{kind:o.Kind.UNION_TYPE_EXTENSION,name:r,directives:i,types:a,loc:V(e,t)}}(e);case"enum":return function(e){var t=e.token;K(e,"extend"),K(e,"enum");var r=n(e),i=k(e,!0),a=$(e);if(0===i.length&&0===a.length)throw J(e);return{kind:o.Kind.ENUM_TYPE_EXTENSION,name:r,directives:i,values:a,loc:V(e,t)}}(e);case"input":return function(e){var t=e.token;K(e,"extend"),K(e,"input");var r=n(e),i=k(e,!0),a=z(e);if(0===i.length&&0===a.length)throw J(e);return{kind:o.Kind.INPUT_OBJECT_TYPE_EXTENSION,name:r,directives:i,fields:a,loc:V(e,t)}}(e)}throw J(e,t)}(e);case"directive":return function(e){var t=e.token,r=N(e);K(e,"directive"),Q(e,h.TokenKind.AT);var i=n(e),a=j(e);K(e,"on");var s=function(e){W(e,h.TokenKind.PIPE);var t=[];do{t.push(G(e))}while(W(e,h.TokenKind.PIPE));return t}(e);return{kind:o.Kind.DIRECTIVE_DEFINITION,description:r,name:i,arguments:a,locations:s,loc:V(e,t)}}(e)}throw J(e,t)}function F(e){return H(e,h.TokenKind.STRING)||H(e,h.TokenKind.BLOCK_STRING)}function N(e){if(F(e))return E(e)}function I(e){var t=e.token,n=s(e);Q(e,h.TokenKind.COLON);var r=T(e);return{kind:o.Kind.OPERATION_TYPE_DEFINITION,operation:n,type:r,loc:V(e,t)}}function L(e){var t=[];if("implements"===e.token.value){e.advance(),W(e,h.TokenKind.AMP);do{t.push(T(e))}while(W(e,h.TokenKind.AMP)||e.options.allowLegacySDLImplementsInterfaces&&H(e,h.TokenKind.NAME))}return t}function P(e){return e.options.allowLegacySDLEmptyFields&&H(e,h.TokenKind.BRACE_L)&&e.lookahead().kind===h.TokenKind.BRACE_R?(e.advance(),e.advance(),[]):H(e,h.TokenKind.BRACE_L)?Y(e,h.TokenKind.BRACE_L,M,h.TokenKind.BRACE_R):[]}function M(e){var t=e.token,r=N(e),i=n(e),a=j(e);Q(e,h.TokenKind.COLON);var s=_(e),u=k(e,!0);return{kind:o.Kind.FIELD_DEFINITION,description:r,name:i,arguments:a,type:s,directives:u,loc:V(e,t)}}function j(e){return H(e,h.TokenKind.PAREN_L)?Y(e,h.TokenKind.PAREN_L,R,h.TokenKind.PAREN_R):[]}function R(e){var t=e.token,r=N(e),i=n(e);Q(e,h.TokenKind.COLON);var a=_(e),s=void 0;W(e,h.TokenKind.EQUALS)&&(s=D(e));var u=k(e,!0);return{kind:o.Kind.INPUT_VALUE_DEFINITION,description:r,name:i,type:a,defaultValue:s,directives:u,loc:V(e,t)}}function B(e){var t=[];if(W(e,h.TokenKind.EQUALS)){W(e,h.TokenKind.PIPE);do{t.push(T(e))}while(W(e,h.TokenKind.PIPE))}return t}function $(e){return H(e,h.TokenKind.BRACE_L)?Y(e,h.TokenKind.BRACE_L,U,h.TokenKind.BRACE_R):[]}function U(e){var t=e.token,r=N(e),i=n(e),a=k(e,!0);return{kind:o.Kind.ENUM_VALUE_DEFINITION,description:r,name:i,directives:a,loc:V(e,t)}}function z(e){return H(e,h.TokenKind.BRACE_L)?Y(e,h.TokenKind.BRACE_L,R,h.TokenKind.BRACE_R):[]}function G(e){var t=e.token,r=n(e);if(g.DirectiveLocation.hasOwnProperty(r.value))return r;throw J(e,t)}function V(e,t){if(!e.options.noLocation)return new q(t,e.lastToken,e.source)}function q(e,t,n){this.start=e.start,this.end=t.end,this.startToken=e,this.endToken=t,this.source=n}function H(e,t){return e.token.kind===t}function W(e,t){var n=e.token.kind===t;return n&&e.advance(),n}function Q(e,t){var n=e.token;if(n.kind===t)return e.advance(),n;throw(0,f.syntaxError)(e.source,n.start,"Expected "+t+", found "+(0,h.getTokenDesc)(n))}function K(e,t){var n=e.token;if(n.kind===h.TokenKind.NAME&&n.value===t)return e.advance(),n;throw(0,f.syntaxError)(e.source,n.start,'Expected "'+t+'", found '+(0,h.getTokenDesc)(n))}function J(e,t){var n=t||e.token;return(0,f.syntaxError)(e.source,n.start,"Unexpected "+(0,h.getTokenDesc)(n))}function Y(e,t,n,r){Q(e,t);for(var i=[n(e)];!W(e,r);)i.push(n(e));return i}Object.defineProperty(t,"__esModule",{value:!0}),t.parse=function(e,t){var n="string"==typeof e?new m.Source(e):e;if(!(n instanceof m.Source))throw new TypeError("Must provide Source. Received: "+String(n));return function(e){var t=e.token;Q(e,h.TokenKind.SOF);var n=[];do{n.push(r(e))}while(!W(e,h.TokenKind.EOF));return{kind:o.Kind.DOCUMENT,definitions:n,loc:V(e,t)}}((0,h.createLexer)(n,t||{}))},t.parseValue=function(e,t){var n="string"==typeof e?new m.Source(e):e,r=(0,h.createLexer)(n,t||{});Q(r,h.TokenKind.SOF);var i=C(r,!1);return Q(r,h.TokenKind.EOF),i},t.parseType=function(e,t){var n="string"==typeof e?new m.Source(e):e,r=(0,h.createLexer)(n,t||{});Q(r,h.TokenKind.SOF);var i=_(r);return Q(r,h.TokenKind.EOF),i},t.parseConstValue=D,t.parseTypeReference=_,t.parseNamedType=T,q.prototype.toJSON=q.prototype.inspect=function(){return{start:this.start,end:this.end}}});t(y);var v=n(function(e,t){function n(e){return Boolean(e&&"string"==typeof e.kind)}function r(e,t,n){var r=e[t];if(r){if(!n&&"function"==typeof r)return r;var i=n?r.leave:r.enter;if("function"==typeof i)return i}else{var o=n?e.leave:e.enter;if(o){if("function"==typeof o)return o;var a=o[t];if("function"==typeof a)return a}}}Object.defineProperty(t,"__esModule",{value:!0}),t.visit=function(e,t){var a=arguments.length>2&&void 0!==arguments[2]?arguments[2]:i,s=void 0,u=Array.isArray(e),c=[e],l=-1,p=[],f=void 0,d=void 0,h=void 0,m=[],g=[],y=e;do{var v=++l===c.length,b=v&&0!==p.length;if(v){if(d=0===g.length?void 0:m[m.length-1],f=h,h=g.pop(),b){if(u)f=f.slice();else{var x={};for(var C in f)f.hasOwnProperty(C)&&(x[C]=f[C]);f=x}for(var E=0,D=0;D"!==n.kind;)"Comment"===n.kind&&(Object.assign(n,{column:n.column-1}),t.push(n)),n=n.next;return t}(i),function t(n){if(n&&"object"===e(n))for(var r in delete n.startToken,delete n.endToken,delete n.prev,delete n.next,n)t(n[r]);return n}(i),i}catch(e){throw e instanceof f.GraphQLError?r(e.message,{start:{line:e.locations[0].line,column:e.locations[0].column}}):e}},astFormat:"graphql",locStart:function(e){return"number"==typeof e.start?e.start:e.loc&&e.loc.start},locEnd:function(e){return"number"==typeof e.end?e.end:e.loc&&e.loc.end}}}}})},function(e,t,n){"use strict";function r(){var e,t,n,r,i,o,a,s,a;return d(this,function(u){switch(u.label){case 0:return[4,m.call(g.delay,100)];case 1:return u.sent(),[4,m.select(y.getSelectedSession)];case 2:return e=u.sent(),[4,S.schemaFetcher.fetch(e)];case 3:t=u.sent().schema,u.label=4;case 4:return u.trys.push([4,12,,14]),(n=T.parse(e.query),r=b.getQueryFacts(t,n))?(i=x.fromJS(r),o=v.default(e.operations,e.operationName,i.operations),x.is(i.get("variableToType"),e.variableToType)?[3,6]:[4,m.put(C.setVariableToType(i.get("variableToType")))]):[3,10];case 5:u.sent(),u.label=6;case 6:return x.is(i.get("operations"),e.operations)?[3,8]:[4,m.put(C.setOperations(i.get("operations")))];case 7:u.sent(),u.label=8;case 8:return o===e.operationName?[3,10]:[4,m.put(C.setOperationName(o))];case 9:u.sent(),u.label=10;case 10:return a=_.getQueryTypes(n),[4,m.put(C.setQueryTypes(a))];case 11:return u.sent(),[3,14];case 12:return s=u.sent(),a=_.getQueryTypes(null),[4,m.put(C.setQueryTypes(a))];case 13:return u.sent(),[3,14];case 14:return[2]}})}function i(e){var t,n,r,i=e.payload;return d(this,function(e){switch(e.label){case 0:return[4,m.call(g.delay,100)];case 1:return e.sent(),location.search.includes("query")?(t=F.parse(location.search),"undefined"!==typeof t.query&&(n=F.stringify(f({},t,{query:i.query})),r=""+location.origin+location.pathname+"?"+n,window.history.replaceState({},document.getElementsByTagName("title")[0].innerHTML,r)),[2]):[2]}})}function o(e){var t,n,r,i;return d(this,function(o){switch(o.label){case 0:return t=e.payload.position,[4,m.select(y.getSelectedSession)];case 1:return n=o.sent(),n.operations?(i=n.operations.toJS(),i.forEach(function(e){e.loc&&e.loc.start<=t&&e.loc.end>=t&&(r=e.name&&e.name.value)}),r?[4,m.put(C.runQuery(r))]:[3,3]):[3,6];case 2:return o.sent(),[3,5];case 3:return[4,m.put(C.runQuery())];case 4:o.sent(),o.label=5;case 5:return[3,8];case 6:return[4,m.put(C.runQuery())];case 7:o.sent(),o.label=8;case 8:return[2]}})}function a(){var e,t;return d(this,function(n){switch(n.label){case 0:return[4,m.select(y.getSelectedSession)];case 1:return e=n.sent(),[4,m.select(k.getSettings)];case 2:return t=n.sent(),[2,{endpoint:e.endpoint,headers:e.headers,credentials:t["request.credentials"]}]}})}function s(){var e,t,n,r,i;return d(this,function(o){switch(o.label){case 0:return[4,a()];case 1:e=o.sent(),o.label=2;case 2:return o.trys.push([2,6,,10]),[4,S.schemaFetcher.fetch(e)];case 3:return o.sent(),t=m.put,n=C.schemaFetchingSuccess,r=[e.endpoint,null],[4,m.select(y.getIsPollingSchema)];case 4:return[4,t.apply(void 0,[n.apply(void 0,r.concat([o.sent()]))])];case 5:return o.sent(),[3,10];case 6:return i=o.sent(),[4,m.put(C.schemaFetchingError(e.endpoint))];case 7:return o.sent(),[4,m.call(g.delay,5e3)];case 8:return o.sent(),[4,m.put(C.fetchSchema())];case 9:return o.sent(),[3,10];case 10:return[2]}})}function u(){var e,t,n,r,i;return d(this,function(o){switch(o.label){case 0:return[4,a()];case 1:e=o.sent(),o.label=2;case 2:return o.trys.push([2,6,,10]),[4,S.schemaFetcher.refetch(e)];case 3:return o.sent(),t=m.put,n=C.schemaFetchingSuccess,r=[e.endpoint,null],[4,m.select(y.getIsPollingSchema)];case 4:return[4,t.apply(void 0,[n.apply(void 0,r.concat([o.sent()]))])];case 5:return o.sent(),[3,10];case 6:return i=o.sent(),[4,m.put(C.schemaFetchingError(e.endpoint))];case 7:return o.sent(),[4,m.call(g.delay,5e3)];case 8:return o.sent(),[4,m.put(C.refetchSchema())];case 9:return o.sent(),[3,10];case 10:return[2]}})}function c(){var e,t,n,r,i,o,s,u;return d(this,function(c){switch(c.label){case 0:return[4,m.select(y.getSelectedSession)];case 1:return e=c.sent(),[4,a()];case 2:return t=c.sent(),[4,m.select(A.getSessionDocsState)];case 3:return n=c.sent(),[4,S.schemaFetcher.fetch(t)];case 4:return r=c.sent(),(i=r.schema,o=r.tracingSupported,!i||h&&h===i)?[3,7]:(s=E.getRootMap(i),u=n.navStack.map(function(e){return E.getNewStack(s,i,e)}).filter(function(e){return e}),[4,m.put(D.setStacks(e.id,u))]);case 5:return c.sent(),[4,m.put(C.setTracingSupported(o))];case 6:c.sent(),h=i,c.label=7;case 7:return[2]}})}function l(e){var t,n,r,i,o,a=e.payload;return d(this,function(e){switch(e.label){case 0:return t=a.sessionId,[4,m.select(k.getSelectedWorkspace)];case 1:return n=e.sent(),r=n.getIn(["sessions",t]),i=n.get("history"),o=i.toKeyedSeq().find(function(e){return x.is(e,r)}),o?[3,3]:[4,m.put(w.addHistoryItem(r))];case 2:e.sent(),e.label=3;case 3:return[2]}})}function p(){var e,t,n,r;return d(this,function(i){switch(i.label){case 0:return[4,m.select(y.getSelectedSession)];case 1:return e=i.sent().query,[4,m.select(k.getSettings)];case 2:t=i.sent(),i.label=3;case 3:return i.trys.push([3,5,,6]),n=O.prettify(e,{printWidth:t["prettier.printWidth"],tabWidth:t["prettier.tabWidth"],useTabs:t["prettier.useTabs"]}),[4,m.put(C.editQuery(n))];case 4:return i.sent(),[3,6];case 5:return r=i.sent(),console.log(r),[3,6];case 6:return[2]}})}var f=function(){return f=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]0&&0===(_-=1)&&x.show(t),n.props.shouldFocusAfterRender&&(n.props.shouldReturnFocusAfterClose?(g.returnFocus(),g.teardownScopedFocus()):g.popWithoutFocus())},n.open=function(){n.beforeOpen(),n.state.afterOpen&&n.state.beforeClose?(clearTimeout(n.closeTimer),n.setState({beforeClose:!1})):(n.props.shouldFocusAfterRender&&(g.setupScopedFocus(n.node),g.markForFocusLater()),n.setState({isOpen:!0},function(){n.setState({afterOpen:!0}),n.props.isOpen&&n.props.onAfterOpen&&n.props.onAfterOpen()}))},n.close=function(){n.props.closeTimeoutMS>0?n.closeWithTimeout():n.closeWithoutTimeout()},n.focusContent=function(){return n.content&&!n.contentHasFocus()&&n.content.focus()},n.closeWithTimeout=function(){var e=Date.now()+n.props.closeTimeoutMS;n.setState({beforeClose:!0,closesAt:e},function(){n.closeTimer=setTimeout(n.closeWithoutTimeout,n.state.closesAt-Date.now())})},n.closeWithoutTimeout=function(){n.setState({beforeClose:!1,isOpen:!1,afterOpen:!1,closesAt:null},n.afterClose)},n.handleKeyDown=function(e){e.keyCode===k&&(0,v.default)(n.content,e),n.props.shouldCloseOnEsc&&e.keyCode===A&&(e.stopPropagation(),n.requestClose(e))},n.handleOverlayOnClick=function(e){null===n.shouldClose&&(n.shouldClose=!0),n.shouldClose&&n.props.shouldCloseOnOverlayClick&&(n.ownerHandlesClose()?n.requestClose(e):n.focusContent()),n.shouldClose=null},n.handleContentOnMouseUp=function(){n.shouldClose=!1},n.handleOverlayOnMouseDown=function(e){n.props.shouldCloseOnOverlayClick||e.target!=n.overlay||e.preventDefault()},n.handleContentOnClick=function(){n.shouldClose=!1},n.handleContentOnMouseDown=function(){n.shouldClose=!1},n.requestClose=function(e){return n.ownerHandlesClose()&&n.props.onRequestClose(e)},n.ownerHandlesClose=function(){return n.props.onRequestClose},n.shouldBeClosed=function(){return!n.state.isOpen&&!n.state.beforeClose},n.contentHasFocus=function(){return document.activeElement===n.content||n.content.contains(document.activeElement)},n.buildClassName=function(e,t){var r="object"===("undefined"===typeof t?"undefined":c(t))?t:{base:S[e],afterOpen:S[e]+"--after-open",beforeClose:S[e]+"--before-close"},i=r.base;return n.state.afterOpen&&(i=i+" "+r.afterOpen),n.state.beforeClose&&(i=i+" "+r.beforeClose),"string"===typeof t&&t?i+" "+t:i},n.ariaAttributes=function(e){return Object.keys(e).reduce(function(t,n){return t["aria-"+n]=e[n],t},{})},n.state={afterOpen:!1,beforeClose:!1},n.shouldClose=null,n.moveFromContentToOverlay=null,n}return s(t,e),l(t,[{key:"componentDidMount",value:function(){this.props.isOpen&&this.open()}},{key:"componentDidUpdate",value:function(e,t){this.props.isOpen&&!e.isOpen?this.open():!this.props.isOpen&&e.isOpen&&this.close(),this.props.shouldFocusAfterRender&&this.state.isOpen&&!t.isOpen&&this.focusContent()}},{key:"componentWillUnmount",value:function(){this.afterClose(),clearTimeout(this.closeTimer)}},{key:"beforeOpen",value:function(){var e=this.props,t=e.appElement,n=e.ariaHideApp,r=e.htmlOpenClassName,i=e.bodyOpenClassName;E.add(document.body,i),r&&E.add(document.getElementsByTagName("html")[0],r),n&&(_+=1,x.hide(t))}},{key:"render",value:function(){var e=this.props,t=e.className,n=e.overlayClassName,r=e.defaultStyles,i=t?{}:r.content,o=n?{}:r.overlay;return this.shouldBeClosed()?null:f.default.createElement("div",{ref:this.setOverlayRef,className:this.buildClassName("overlay",n),style:u({},o,this.props.style.overlay),onClick:this.handleOverlayOnClick,onMouseDown:this.handleOverlayOnMouseDown,"aria-modal":"true"},f.default.createElement("div",u({ref:this.setContentRef,style:u({},i,this.props.style.content),className:this.buildClassName("content",t),tabIndex:"-1",onKeyDown:this.handleKeyDown,onMouseDown:this.handleContentOnMouseDown,onMouseUp:this.handleContentOnMouseUp,onClick:this.handleContentOnClick,role:this.props.role,"aria-label":this.props.contentLabel},this.ariaAttributes(this.props.aria||{}),{"data-testid":this.props.testId}),this.props.children))}}]),t}(p.Component);T.defaultProps={style:{overlay:{},content:{}},defaultStyles:{}},T.propTypes={isOpen:h.default.bool.isRequired,defaultStyles:h.default.shape({content:h.default.object,overlay:h.default.object}),style:h.default.shape({content:h.default.object,overlay:h.default.object}),className:h.default.oneOfType([h.default.string,h.default.object]),overlayClassName:h.default.oneOfType([h.default.string,h.default.object]),bodyOpenClassName:h.default.string,htmlOpenClassName:h.default.string,ariaHideApp:h.default.bool,appElement:h.default.instanceOf(w.default),onAfterOpen:h.default.func,onRequestClose:h.default.func,closeTimeoutMS:h.default.number,shouldFocusAfterRender:h.default.bool,shouldCloseOnOverlayClick:h.default.bool,shouldReturnFocusAfterClose:h.default.bool,role:h.default.string,contentLabel:h.default.string,aria:h.default.object,children:h.default.node,shouldCloseOnEsc:h.default.bool,overlayRef:h.default.func,contentRef:h.default.func,testId:h.default.string},t.default=T,e.exports=t.default},function(e,t,n){"use strict";function r(){h=!0}function i(){if(h){if(h=!1,!d)return;setTimeout(function(){if(!d.contains(document.activeElement)){((0,p.default)(d)[0]||d).focus()}},0)}}function o(){f.push(document.activeElement)}function a(){var e=null;try{return void(0!==f.length&&(e=f.pop(),e.focus()))}catch(t){console.warn(["You tried to return focus to",e,"but it is not in the DOM anymore"].join(" "))}}function s(){f.length>0&&f.pop()}function u(e){d=e,window.addEventListener?(window.addEventListener("blur",r,!1),document.addEventListener("focus",i,!0)):(window.attachEvent("onBlur",r),document.attachEvent("onFocus",i))}function c(){d=null,window.addEventListener?(window.removeEventListener("blur",r),document.removeEventListener("focus",i)):(window.detachEvent("onBlur",r),document.detachEvent("onFocus",i))}Object.defineProperty(t,"__esModule",{value:!0}),t.handleBlur=r,t.handleFocus=i,t.markForFocusLater=o,t.returnFocus=a,t.popWithoutFocus=s,t.setupScopedFocus=u,t.teardownScopedFocus=c;var l=n(255),p=function(e){return e&&e.__esModule?e:{default:e}}(l),f=[],d=null,h=!1},function(e,t,n){"use strict";function r(e,t){var n=(0,o.default)(e);if(!n.length)return void t.preventDefault();var r=t.shiftKey,i=n[0],a=n[n.length-1];if(e===document.activeElement){if(!r)return;s=a}var s;if(a!==document.activeElement||r||(s=i),i===document.activeElement&&r&&(s=a),s)return t.preventDefault(),void s.focus();var u=/(\bChrome\b|\bSafari\b)\//.exec(navigator.userAgent);if(null!=u&&"Chrome"!=u[1]&&null==/\biPod\b|\biPad\b/g.exec(navigator.userAgent)){var c=n.indexOf(document.activeElement);c>-1&&(c+=r?-1:1),t.preventDefault(),n[c].focus()}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var i=n(255),o=function(e){return e&&e.__esModule?e:{default:e}}(i);e.exports=t.default},function(e,t,n){"use strict";function r(){}Object.defineProperty(t,"__esModule",{value:!0}),t.dumpClassLists=r;var i={},o={},a=function(e,t){return e[t]||(e[t]=0),e[t]+=1,t},s=function(e,t){return e[t]&&(e[t]-=1),t},u=function(e,t,n){n.forEach(function(n){a(t,n),e.add(n)})},c=function(e,t,n){n.forEach(function(n){s(t,n),0===t[n]&&e.remove(n)})};t.add=function(e,t){return u(e.classList,"html"==e.nodeName.toLowerCase()?i:o,t.split(" "))},t.remove=function(e,t){return c(e.classList,"html"==e.nodeName.toLowerCase()?i:o,t.split(" "))}},function(e,t,n){"use strict";function r(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!==e&&void 0!==e&&this.setState(e)}function i(e){function t(t){var n=this.constructor.getDerivedStateFromProps(e,t);return null!==n&&void 0!==n?n:null}this.setState(t.bind(this))}function o(e,t){try{var n=this.props,r=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,r)}finally{this.props=n,this.state=r}}function a(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if("function"!==typeof e.getDerivedStateFromProps&&"function"!==typeof t.getSnapshotBeforeUpdate)return e;var n=null,a=null,s=null;if("function"===typeof t.componentWillMount?n="componentWillMount":"function"===typeof t.UNSAFE_componentWillMount&&(n="UNSAFE_componentWillMount"),"function"===typeof t.componentWillReceiveProps?a="componentWillReceiveProps":"function"===typeof t.UNSAFE_componentWillReceiveProps&&(a="UNSAFE_componentWillReceiveProps"),"function"===typeof t.componentWillUpdate?s="componentWillUpdate":"function"===typeof t.UNSAFE_componentWillUpdate&&(s="UNSAFE_componentWillUpdate"),null!==n||null!==a||null!==s){var u=e.displayName||e.name,c="function"===typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()";throw Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+u+" uses "+c+" but also contains the following legacy lifecycles:"+(null!==n?"\n "+n:"")+(null!==a?"\n "+a:"")+(null!==s?"\n "+s:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks")}if("function"===typeof e.getDerivedStateFromProps&&(t.componentWillMount=r,t.componentWillReceiveProps=i),"function"===typeof t.getSnapshotBeforeUpdate){if("function"!==typeof t.componentDidUpdate)throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=o;var l=t.componentDidUpdate;t.componentDidUpdate=function(e,t,n){var r=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;l.call(this,e,t,r)}}return e}Object.defineProperty(t,"__esModule",{value:!0}),n.d(t,"polyfill",function(){return a}),r.__suppressDeprecationWarning=!0,i.__suppressDeprecationWarning=!0,o.__suppressDeprecationWarning=!0},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e,r){function i(e){return"function"===typeof e}function o(e){return e.displayName||e.name||"Component"}function a(e){return e&&"string"===typeof e.styledComponentId}function s(e){return e.replace(Ie,"-$1").toLowerCase().replace(Le,"-ms-")}function u(e,t,n){if(Array.isArray(e)){for(var r,o=[],s=0,c=e.length;s1?t-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:V;if(!Object(T.isValidElementType)(t))throw new Q(1,String(t));var r=function(){return e(t,n,c.apply(void 0,arguments))};return r.withConfig=function(r){return l(e,t,R({},n,r))},r.attrs=function(r){return l(e,t,R({},n,{attrs:R({},n.attrs||V,r)}))},r}function p(e){for(var t,n=0|e.length,r=0|n,i=0;n>=4;)t=255&e.charCodeAt(i)|(255&e.charCodeAt(++i))<<8|(255&e.charCodeAt(++i))<<16|(255&e.charCodeAt(++i))<<24,t=1540483477*(65535&t)+((1540483477*(t>>>16)&65535)<<16),t^=t>>>24,t=1540483477*(65535&t)+((1540483477*(t>>>16)&65535)<<16),r=1540483477*(65535&r)+((1540483477*(r>>>16)&65535)<<16)^t,n-=4,++i;switch(n){case 3:r^=(255&e.charCodeAt(i+2))<<16;case 2:r^=(255&e.charCodeAt(i+1))<<8;case 1:r^=255&e.charCodeAt(i),r=1540483477*(65535&r)+((1540483477*(r>>>16)&65535)<<16)}return r^=r>>>13,((r=1540483477*(65535&r)+((1540483477*(r>>>16)&65535)<<16))^r>>>15)>>>0}function f(e){var t="",n=void 0;for(n=e;n>je;n=Math.floor(n/je))t=Re(n%je)+t;return Re(n%je)+t}function d(e,t){for(var n=0;n1?t-1:0),r=1;r1?t-1:0),r=1;r=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n},U=function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t},z=function(e){return"object"===("undefined"===typeof e?"undefined":P(e))&&e.constructor===Object},G=Object.freeze([]),V=Object.freeze({}),q="undefined"!==typeof e&&Object({NODE_ENV:"production",PUBLIC_URL:""}).SC_ATTR||"data-styled",H="undefined"!==typeof window&&"HTMLElement"in window,W={},Q=function(e){function t(n){M(this,t);for(var r=arguments.length,i=Array(r>1?r-1:0),o=1;o])([^&{][^{]+)[^+~>]*)?([+~>] *)&/g,Z=new w.a({global:!1,cascade:!0,keyframe:!1,prefix:!1,compress:!1,semicolon:!0}),ee=new w.a({global:!1,cascade:!0,keyframe:!1,prefix:!0,compress:!1,semicolon:!1}),te=[],ne=function(e){if(-2===e){var t=te;return te=[],t}},re=k()(function(e){te.push(e)});ee.use([re,ne]),Z.use([re,ne]);var ie=function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"&",i=e.join("").replace(Y,""),o=(t&&n?n+" "+t+" { "+i+" }":i).replace(X,"$1$3."+r+"$2");return ee(n||!t?"":t,o)},oe=function(e){return Z("",e)},ae=function(){return n.nc},se=function(e){var t=!1;return function(){t||(t=!0,e())}},ue=function(e,t,n){if(n){(e[t]||(e[t]=Object.create(null)))[n]=!0}},ce=function(e,t){e[t]=Object.create(null)},le=function(e){return function(t,n){return void 0!==e[t]&&e[t][n]}},pe=function(e){var t="";for(var n in e)t+=Object.keys(e[n]).join(" ")+" ";return t.trim()},fe=function(e){var t=Object.create(null);for(var n in e)t[n]=R({},e[n]);return t},de=function(e){if(e.sheet)return e.sheet;for(var t=document.styleSheets.length,n=0;nr;i-=1)e.deleteRule(i)},ge=function(e){return"\n/* sc-component-id: "+e+" */\n"},ye=function(e,t){for(var n=0,r=0;r<=t;r+=1)n+=e[r];return n},ve=function(e,t,n){var r=document.createElement("style");r.setAttribute(q,""),r.setAttribute("data-styled-version","4.0.0");var i=ae();if(i&&r.setAttribute("nonce",i),r.appendChild(document.createTextNode("")),e&&!t)e.appendChild(r);else{if(!t||!e||!t.parentNode)throw new Q(6);t.parentNode.insertBefore(r,n?t:t.nextSibling)}return r},be=function(e,t){return function(n){var r=ae();return""}},xe=function(e,t){return function(){var n,r=(n={},n[q]=pe(t),n["data-styled-version"]="4.0.0",n),i=ae();return i&&(r.nonce=i),_.a.createElement("style",R({},r,{dangerouslySetInnerHTML:{__html:e()}}))}},Ce=function(e){return function(){return Object.keys(e)}},Ee=function(e,t){var n=Object.create(null),r=Object.create(null),i=[],o=void 0!==t,a=!1,s=function(e){var t=r[e];return void 0!==t?t:(r[e]=i.length,i.push(0),ce(n,e),r[e])},u=function(r,u,c){for(var l=s(r),p=de(e),f=ye(i,l),d=0,h=[],m=u.length,g=0;g0&&(a=!0,t().insertRules(r+"-import",h)),i[l]+=d,ue(n,r,c)},c=function(s){var u=r[s];if(void 0!==u){var c=i[u],l=de(e),p=ye(i,u)-1;me(l,p,c),i[u]=0,ce(n,s),o&&a&&t().removeRules(s+"-import")}},l=function(){var t=de(e),n=t.cssRules,o="";for(var a in r){o+=ge(a);for(var s=r[a],u=ye(i,s),c=i[s],l=u-c;l0&&void 0!==arguments[0]?arguments[0]:H?document.head:null,r=arguments.length>1&&void 0!==arguments[1]&&arguments[1];M(this,e),this.getImportRuleTag=function(){var e=t.importRuleTag;if(void 0!==e)return e;var n=t.tags[0];return t.importRuleTag=we(t.target,n?n.styleTag:null,t.forceServer,!0)},Te+=1,this.id=Te,this.forceServer=r,this.target=r?null:n,this.tagMap={},this.deferred={},this.rehydratedNames={},this.ignoreRehydratedNames={},this.tags=[],this.capacity=1,this.clones=[]}return e.prototype.rehydrate=function(){if(!H||this.forceServer)return this;var e=[],t=[],n=!1,r=document.querySelectorAll("style["+q+'][data-styled-version="4.0.0"]'),i=r.length;if(0===i)return this;for(var o=0;o0&&void 0!==arguments[0]&&arguments[0];Oe=new e(void 0,t).rehydrate()},e.prototype.clone=function(){var t=new e(this.target,this.forceServer);return this.clones.push(t),t.tags=this.tags.map(function(e){for(var n=e.getIds(),r=e.clone(),i=0;i25?39:97))},Be=!1,$e=function(e){return f(p(e))},Ue=function(){function e(t,n,r){if(M(this,e),this.rules=t,this.isStatic=!Be&&d(t,n),this.componentId=r,!Fe.master.hasId(r)){var i=[];Fe.master.deferredInject(r,i)}}return e.prototype.generateAndInjectStyles=function(e,t){var n=this.isStatic,r=this.componentId,i=this.lastClassName;if(H&&n&&void 0!==i&&t.hasNameForId(r,i))return i;var o=u(this.rules,e,t),a=$e(this.componentId+o.join(""));return t.hasNameForId(r,a)||t.inject(this.componentId,ie(o,"."+a,void 0,r),a),this.lastClassName=a,a},e.generateName=function(e){return $e(e)},e}(),ze=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:V,r=!!n&&e.theme===n.theme;return e.theme&&!r?e.theme:t||n.theme},Ge=/[[\].#*$><+~=|^:(),"'`-]+/g,Ve=/(^-|-$)/g,qe={childContextTypes:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDerivedStateFromProps:!0,propTypes:!0,type:!0},He={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},We=(_e={},_e[T.ForwardRef]={$$typeof:!0,render:!0},_e),Qe=Object.defineProperty,Ke=Object.getOwnPropertyNames,Je=Object.getOwnPropertySymbols,Ye=void 0===Je?function(){return[]}:Je,Xe=Object.getOwnPropertyDescriptor,Ze=Object.getPrototypeOf,et=Object.prototype,tt=Array.prototype,nt=Object(A.createContext)(),rt=nt.Consumer,it=function(e){function t(n){M(this,t);var r=U(this,e.call(this,n));return r.getContext=Object(O.a)(r.getContext.bind(r)),r.renderInner=r.renderInner.bind(r),r}return B(t,e),t.prototype.render=function(){return this.props.children?_.a.createElement(nt.Consumer,null,this.renderInner):null},t.prototype.renderInner=function(e){var t=this.getContext(this.props.theme,e);return _.a.createElement(nt.Provider,{value:t},_.a.Children.only(this.props.children))},t.prototype.getTheme=function(e,t){if(i(e)){return e(t)}if(null===e||Array.isArray(e)||"object"!==("undefined"===typeof e?"undefined":P(e)))throw new Q(8);return R({},t,e)},t.prototype.getContext=function(e,t){return this.getTheme(e,t)},t}(A.Component),ot=function(){function e(){M(this,e),this.masterSheet=Fe.master,this.instance=this.masterSheet.clone(),this.sealed=!1}return e.prototype.seal=function(){if(!this.sealed){var e=this.masterSheet.clones.indexOf(this.instance);this.masterSheet.clones.splice(e,1),this.sealed=!0}},e.prototype.collectStyles=function(e){if(this.sealed)throw new Q(2);return _.a.createElement(ut,{sheet:this.instance},e)},e.prototype.getStyleTags=function(){return this.seal(),this.instance.toHTML()},e.prototype.getStyleElement=function(){return this.seal(),this.instance.toReactElements()},e.prototype.interleaveWithNodeStream=function(e){throw new Q(3)},e}(),at=Object(A.createContext)(),st=at.Consumer,ut=function(e){function t(n){M(this,t);var r=U(this,e.call(this,n));return r.getContext=Object(O.a)(r.getContext),r}return B(t,e),t.prototype.getContext=function(e,t){if(e)return e;if(t)return new Fe(t);throw new Q(4)},t.prototype.render=function(){var e=this.props,t=e.children,n=e.sheet,r=e.target,i=this.getContext(n,r);return _.a.createElement(at.Provider,{value:i},_.a.Children.only(t))},t}(A.Component),ct={},lt=(se(function(){return console.warn('The "innerRef" API has been removed in styled-components v4 in favor of React 16 ref forwarding, use "ref" instead like a typical component.')}),function(e){function t(){M(this,t);var n=U(this,e.call(this));return n.attrs={},n.renderOuter=n.renderOuter.bind(n),n.renderInner=n.renderInner.bind(n),n}return B(t,e),t.prototype.render=function(){return _.a.createElement(st,null,this.renderOuter)},t.prototype.renderOuter=function(e){return this.styleSheet=e,_.a.createElement(rt,null,this.renderInner)},t.prototype.renderInner=function(e){var t=this.props.forwardedClass,n=t.componentStyle,r=t.defaultProps,i=t.styledComponentId,o=t.target,a=void 0;a=n.isStatic?this.generateAndInjectStyles(V,this.props,this.styleSheet):void 0!==e?this.generateAndInjectStyles(ze(this.props,e,r),this.props,this.styleSheet):this.generateAndInjectStyles(this.props.theme||V,this.props,this.styleSheet);var s=this.props.as||this.attrs.as||o,u=m(s),c=R({},this.attrs),l=void 0;for(l in this.props)"forwardedClass"!==l&&"as"!==l&&("forwardedRef"===l?c.ref=this.props[l]:u&&!Object(I.a)(l)||(c[l]="style"===l&&l in this.attrs?R({},this.attrs[l],this.props[l]):this.props[l]));return c.className=[this.props.className,i,this.attrs.className,a].filter(Boolean).join(" "),Object(A.createElement)(s,c)},t.prototype.buildExecutionContext=function(e,t,n){var r=R({},t,{theme:e});if(void 0===n)return r;this.attrs={};var o=void 0,s=void 0;for(s in n)o=n[s],this.attrs[s]=!i(o)||v(o)||a(o)?o:o(r);return R({},r,this.attrs)},t.prototype.generateAndInjectStyles=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:Fe.master,r=t.forwardedClass,i=r.attrs,o=r.componentStyle,a=r.warnTooManyClasses;if(o.isStatic&&void 0===i)return o.generateAndInjectStyles(V,n);var s=o.generateAndInjectStyles(this.buildExecutionContext(e,t,t.forwardedClass.attrs),n);return a&&a(s),s},t}(A.Component)),pt=["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","marquee","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","clipPath","defs","ellipse","foreignObject","g","image","line","linearGradient","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","tspan"],ft=function(e){return l(x,e)};pt.forEach(function(e){ft[e]=ft(e)});var dt=function(){function e(t,n){M(this,e),this.rules=t,this.componentId=n,this.isStatic=d(t),Fe.master.hasId(n)||Fe.master.deferredInject(n,[])}return e.prototype.createStyles=function(e,t){var n=u(this.rules,e,t),r=ie(n,"");t.inject(this.componentId,r)},e.prototype.removeStyles=function(e){var t=this.componentId;e.hasId(t)&&e.remove(t)},e.prototype.renderStyles=function(e,t){this.removeStyles(t),this.createStyles(e,t)},e}();H&&(window.scCGSHMRCache={});var ht=function(e){return e.replace(/\s|\\n/g,"")},mt=function(e){var t=_.a.forwardRef(function(t,n){return _.a.createElement(rt,null,function(r){var i=e.defaultProps,o=ze(t,r,i);return _.a.createElement(e,R({},t,{theme:o,ref:n}))})});return y(t,e),t.displayName="WithTheme("+o(e)+")",t},gt={StyleSheet:Fe};t.default=ft}.call(t,n(56),n(79)(e))},function(e,t,n){!function(t){e.exports=t(null)}(function e(t){"use strict";function n(e,t,i,c,l){for(var d,h,m=0,g=0,y=0,b=0,x=0,C=0,E=0,k=0,A=0,_=0,T=0,F=0,I=0,L=0,P=0,M=0,ee=0,_e=0,Ne=0,Le=i.length,Pe=Le-1,Me="",He="",We="",Qe="",Ke="",Je="";P0&&(He=He.replace(f,"")),He.trim().length>0)){switch(E){case Y:case K:case $:case Q:case W:break;default:He+=i.charAt(P)}E=$}if(1===ee)switch(E){case z:case U:case $:case oe:case ie:case G:case V:case ne:ee=0;case K:case Q:case W:case Y:break;default:for(ee=0,Ne=P,x=E,P--,E=$;Ne0&&(++P,E=x);case z:Ne=Le}}switch(E){case z:for(x=(He=He.trim()).charCodeAt(0),T=1,Ne=++P;P0&&(He=He.replace(f,"")),C=He.charCodeAt(1)){case xe:case he:case me:case Z:d=t;break;default:d=Fe}if(Ne=(We=n(t,d,We,C,l+1)).length,Oe>0&&0===Ne&&(Ne=He.length),Ie>0&&(d=r(Fe,He,_e),h=u($e,We,d,t,De,Ee,Ne,C,l,c),He=d.join(""),void 0!==h&&0===(Ne=(We=h.trim()).length)&&(C=0,We="")),Ne>0)switch(C){case me:He=He.replace(N,s);case xe:case he:case Z:We=He+"{"+We+"}";break;case de:We=(He=He.replace(D,"$1 $2"+(ze>0?Ge:"")))+"{"+We+"}",We=1===ke||2===ke&&a("@"+We,3)?"@"+j+We+"@"+We:"@"+We;break;default:We=He+We,c===Ce&&(Qe+=We,We="")}else We="";break;default:We=n(t,r(t,He,_e),We,c,l+1)}Ke+=We,F=0,ee=0,L=0,M=0,_e=0,I=0,He="",We="",E=i.charCodeAt(++P);break;case U:case $:if((Ne=(He=(M>0?He.replace(f,""):He).trim()).length)>1)switch(0===L&&((x=He.charCodeAt(0))===Z||x>96&&x<123)&&(Ne=(He=He.replace(" ",":")).length),Ie>0&&void 0!==(h=u(Re,He,t,e,De,Ee,Qe.length,c,l,c))&&0===(Ne=(He=h.trim()).length)&&(He="\0\0"),(x=He.charCodeAt(0))+(C=He.charCodeAt(1))){case le:break;case ve:case be:Je+=He+i.charAt(P);break;default:if(He.charCodeAt(Ne-1)===re)break;Qe+=o(He,x,C,He.charCodeAt(2))}F=0,ee=0,L=0,M=0,_e=0,He="",E=i.charCodeAt(++P)}}switch(E){case Q:case W:if(g+b+y+m+Te===0)switch(_){case V:case ie:case oe:case J:case ce:case se:case te:case ue:case ae:case Z:case re:case ne:case $:case z:case U:break;default:L>0&&(ee=1)}g===ae?g=0:Se+F===0&&(M=1,He+="\0"),Ie*Ue>0&&u(je,He,t,e,De,Ee,Qe.length,c,l,c),Ee=1,De++;break;case $:case U:if(g+b+y+m===0){Ee++;break}default:switch(Ee++,Me=i.charAt(P),E){case K:case Y:if(b+m+g===0)switch(k){case ne:case re:case K:case Y:Me="";break;default:E!==Y&&(Me=" ")}break;case le:Me="\\0";break;case pe:Me="\\f";break;case fe:Me="\\v";break;case X:b+g+m===0&&Se>0&&(_e=1,M=1,Me="\f"+Me);break;case 108:if(b+g+m+we===0&&L>0)switch(P-L){case 2:k===ge&&i.charCodeAt(P-3)===re&&(we=k);case 8:A===ye&&(we=A)}break;case re:b+g+m===0&&(L=P);break;case ne:g+y+b+m===0&&(M=1,Me+="\r");break;case oe:case ie:0===g&&(b=b===E?0:0===b?E:b);break;case q:b+g+y===0&&m++;break;case H:b+g+y===0&&m--;break;case V:b+g+m===0&&y--;break;case G:if(b+g+m===0){if(0===F)switch(2*k+3*A){case 533:break;default:T=0,F=1}y++}break;case J:g+y+b+m+L+I===0&&(I=1);break;case te:case ae:if(b+m+y>0)break;switch(g){case 0:switch(2*E+3*i.charCodeAt(P+1)){case 235:g=ae;break;case 220:Ne=P,g=te}break;case te:E===ae&&k===te&&(33===i.charCodeAt(Ne+2)&&(Qe+=i.substring(Ne,P+1)),Me="",g=0)}}if(0===g){if(Se+b+m+I===0&&c!==de&&E!==$)switch(E){case ne:case ce:case se:case ue:case V:case G:if(0===F){switch(k){case K:case Y:case W:case Q:Me+="\0";break;default:Me="\0"+Me+(E===ne?"":"\0")}M=1}else switch(E){case G:F=++T;break;case V:0==(F=--T)&&(M=1,Me+="\0")}break;case K:case Y:switch(k){case le:case z:case U:case $:case ne:case pe:case K:case Y:case W:case Q:break;default:0===F&&(M=1,Me+="\0")}}He+=Me,E!==Y&&E!==K&&(_=E)}}A=k,k=E,P++}if(Ne=Qe.length,Oe>0&&0===Ne&&0===Ke.length&&0===t[0].length==0&&(c!==he||1===t.length&&(Se>0?Ve:qe)===t[0])&&(Ne=t.join(",").length+2),Ne>0){if(d=0===Se&&c!==de?function(e){for(var t,n,r=0,i=e.length,o=Array(i);r1)){if(l=s.charCodeAt(s.length-1),p=n.charCodeAt(0),t="",0!==u)switch(l){case te:case ce:case se:case ue:case Y:case G:break;default:t=" "}switch(p){case X:n=t+Ve;case ce:case se:case ue:case Y:case V:case G:break;case q:n=t+n+Ve;break;case re:switch(2*n.charCodeAt(1)+3*n.charCodeAt(2)){case 530:if(Ae>0){n=t+n.substring(8,c-1);break}default:(u<1||a[u-1].length<1)&&(n=t+Ve+n)}break;case ne:t="";default:n=c>1&&n.indexOf(":")>0?t+n.replace(O,"$1"+Ve+"$2"):t+n+Ve}s+=n}o[r]=s.replace(f,"").trim()}return o}(t):t,Ie>0&&void 0!==(h=u(Be,Qe,d,e,De,Ee,Ne,c,l,c))&&0===(Qe=h).length)return Je+Qe+Ke;if(Qe=d.join(",")+"{"+Qe+"}",ke*we!=0){switch(2!==ke||a(Qe,2)||(we=0),we){case ye:Qe=Qe.replace(S,":"+R+"$1")+Qe;break;case ge:Qe=Qe.replace(w,"::"+j+"input-$1")+Qe.replace(w,"::"+R+"$1")+Qe.replace(w,":"+B+"input-$1")+Qe}we=0}}return Je+Qe+Ke}function r(e,t,n){var r=t.trim().split(b),o=r,a=r.length,s=e.length;switch(s){case 0:case 1:for(var u=0,c=0===s?"":e[0]+" ";u0&&Se>0)return i.replace(C,"$1").replace(x,"$1"+qe);break;default:return e.trim()+i.replace(x,"$1"+e.trim())}default:if(n*Se>0&&i.indexOf("\f")>0)return i.replace(x,(e.charCodeAt(0)===re?"":"$1")+e.trim())}return e+i}function o(e,t,n,r){var i,s=0,u=e+";",c=2*t+3*n+4*r;if(944===c)return function(e){var t=e.length,n=e.indexOf(":",9)+1,r=e.substring(0,n).trim(),i=e.substring(n,t-1).trim();switch(e.charCodeAt(9)*ze){case 0:break;case Z:if(110!==e.charCodeAt(10))break;default:for(var o=i.split((i="",g)),s=0,n=0,t=o.length;sJ&&l<90||l>96&&l<123||l===ee||l===Z&&u.charCodeAt(1)!==Z))switch(isNaN(parseFloat(u))+(-1!==u.indexOf("("))){case 1:switch(u){case"infinite":case"alternate":case"backwards":case"running":case"normal":case"forwards":case"both":case"none":case"linear":case"ease":case"ease-in":case"ease-out":case"ease-in-out":case"paused":case"reverse":case"alternate-reverse":case"inherit":case"initial":case"unset":case"step-start":case"step-end":break;default:u+=Ge}}c[n++]=u}i+=(0===s?"":",")+c.join(" ")}}return i=r+i+";",1===ke||2===ke&&a(i,1)?j+i+i:i}(u);if(0===ke||2===ke&&!a(u,1))return u;switch(c){case 1015:return 97===u.charCodeAt(10)?j+u+u:u;case 951:return 116===u.charCodeAt(3)?j+u+u:u;case 963:return 110===u.charCodeAt(5)?j+u+u:u;case 1009:if(100!==u.charCodeAt(4))break;case 969:case 942:return j+u+u;case 978:return j+u+R+u+u;case 1019:case 983:return j+u+R+u+B+u+u;case 883:return u.charCodeAt(8)===Z?j+u+u:u;case 932:if(u.charCodeAt(4)===Z)switch(u.charCodeAt(5)){case 103:return j+"box-"+u.replace("-grow","")+j+u+B+u.replace("grow","positive")+u;case 115:return j+u+B+u.replace("shrink","negative")+u;case 98:return j+u+B+u.replace("basis","preferred-size")+u}return j+u+B+u+u;case 964:return j+u+B+"flex-"+u+u;case 1023:if(99!==u.charCodeAt(8))break;return i=u.substring(u.indexOf(":",15)).replace("flex-","").replace("space-between","justify"),j+"box-pack"+i+j+u+B+"flex-pack"+i+u;case 1005:return h.test(u)?u.replace(d,":"+j)+u.replace(d,":"+R)+u:u;case 1e3:switch(s=(i=u.substring(13).trim()).indexOf("-")+1,i.charCodeAt(0)+i.charCodeAt(s)){case 226:i=u.replace(F,"tb");break;case 232:i=u.replace(F,"tb-rl");break;case 220:i=u.replace(F,"lr");break;default:return u}return j+u+B+i+u;case 1017:if(-1===u.indexOf("sticky",9))return u;case 975:switch(s=(u=e).length-10,c=(i=(33===u.charCodeAt(s)?u.substring(0,s):u).substring(e.indexOf(":",7)+1).trim()).charCodeAt(0)+(0|i.charCodeAt(7))){case 203:if(i.charCodeAt(8)<111)break;case 115:u=u.replace(i,j+i)+";"+u;break;case 207:case 102:u=u.replace(i,j+(c>102?"inline-":"")+"box")+";"+u.replace(i,j+i)+";"+u.replace(i,B+i+"box")+";"+u}return u+";";case 938:if(u.charCodeAt(5)===Z)switch(u.charCodeAt(6)){case 105:return i=u.replace("-items",""),j+u+j+"box-"+i+B+"flex-"+i+u;case 115:return j+u+B+"flex-item-"+u.replace(L,"")+u;default:return j+u+B+"flex-line-pack"+u.replace("align-content","").replace(L,"")+u}break;case 973:case 989:if(u.charCodeAt(3)!==Z||122===u.charCodeAt(4))break;case 931:case 953:if(!0===M.test(e))return 115===(i=e.substring(e.indexOf(":")+1)).charCodeAt(0)?o(e.replace("stretch","fill-available"),t,n,r).replace(":fill-available",":stretch"):u.replace(i,j+i)+u.replace(i,R+i.replace("fill-",""))+u;break;case 962:if(u=j+u+(102===u.charCodeAt(5)?B+u:"")+u,n+r===211&&105===u.charCodeAt(13)&&u.indexOf("transform",10)>0)return u.substring(0,u.indexOf(";",27)+1).replace(m,"$1"+j+"$2")+u}return u}function a(e,t){var n=e.indexOf(1===t?":":"{"),r=e.substring(0,3!==t?n:10),i=e.substring(n+1,e.length-1);return Le(2!==t?r:r.replace(P,"$1"),i,t)}function s(e,t){var n=o(t,t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2));return n!==t+";"?n.replace(I," or ($1)").substring(4):"("+t+")"}function u(e,t,n,r,i,o,a,s,u,c){for(var p,f=0,d=t;f0&&(Ge=i.replace(E,o===q?"":"-")),o=1,1===Se?qe=i:Ve=i;var a,s=[qe];Ie>0&&void 0!==(a=u(Me,r,s,s,De,Ee,0,0,0,0))&&"string"==typeof a&&(r=a);var c=n(Fe,s,r,0,0);return Ie>0&&void 0!==(a=u(Pe,c,s,s,De,Ee,c.length,0,0,0))&&"string"!=typeof(c=a)&&(o=0),Ge="",qe="",Ve="",we=0,De=1,Ee=1,_e*o==0?c:c.replace(f,"").replace(k,"").replace(A,"$1").replace(_,"$1").replace(T," ")}var p=/^\0+/g,f=/[\0\r\f]/g,d=/: */g,h=/zoo|gra/,m=/([,: ])(transform)/g,g=/,+\s*(?![^(]*[)])/g,y=/ +\s*(?![^(]*[)])/g,v=/ *[\0] */g,b=/,\r+?/g,x=/([\t\r\n ])*\f?&/g,C=/:global\(((?:[^\(\)\[\]]*|\[.*\]|\([^\(\)]*\))*)\)/g,E=/\W+/g,D=/@(k\w+)\s*(\S*)\s*/,w=/::(place)/g,S=/:(read-only)/g,k=/\s+(?=[{\];=:>])/g,A=/([[}=:>])\s+/g,_=/(\{[^{]+?);(?=\})/g,T=/\s{2,}/g,O=/([^\(])(:+) */g,F=/[svh]\w+-[tblr]{2}/,N=/\(\s*(.*)\s*\)/g,I=/([\s\S]*?);/g,L=/-self|flex-/g,P=/[^]*?(:[rp][el]a[\w-]+)[^]*/,M=/stretch|:\s*\w+\-(?:conte|avail)/,j="-webkit-",R="-moz-",B="-ms-",$=59,U=125,z=123,G=40,V=41,q=91,H=93,W=10,Q=13,K=9,J=64,Y=32,X=38,Z=45,ee=95,te=42,ne=44,re=58,ie=39,oe=34,ae=47,se=62,ue=43,ce=126,le=0,pe=12,fe=11,de=107,he=109,me=115,ge=112,ye=111,ve=169,be=163,xe=100,Ce=112,Ee=1,De=1,we=0,Se=1,ke=1,Ae=1,_e=0,Te=0,Oe=0,Fe=[],Ne=[],Ie=0,Le=null,Pe=-2,Me=-1,je=0,Re=1,Be=2,$e=3,Ue=0,ze=1,Ge="",Ve="",qe="";return l.use=function e(t){switch(t){case void 0:case null:Ie=Ne.length=0;break;default:switch(t.constructor){case Array:for(var n=0,r=t.length;n0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]0&&(localStorage.setItem("platform-token",e),window.location.replace(window.location.origin+window.location.pathname))},n.prototype.componentDidMount=function(){var e=this;if(""===this.state.subscriptionEndpoint&&this.updateSubscriptionsUrl(),setTimeout(function(){e.removePlaygroundInClass()},5e3),this.setInitialWorkspace(),this.props.tabs)this.props.injectTabs(this.props.tabs);else{var t=r("query");if(t){var n=r("endpoint")||this.state.endpoint;this.props.injectTabs([{query:t,endpoint:n}])}else{var i=r("tabs");if(i)try{var o=JSON.parse(i);this.props.injectTabs(o)}catch(e){}}}this.props.schema&&("string"===typeof this.props.schema?this.setState({schema:C.buildSchema(this.props.schema)}):this.setState({schema:C.buildClientSchema(this.props.schema)}))},n.prototype.setInitialWorkspace=function(e){if(void 0===e&&(e=this.props),e.config){var t=this.getInitialActiveEnv(e.config),n=y.getActiveEndpoints(e.config,t.activeEnv,t.projectName),r=n.endpoint,i=n.subscriptionEndpoint||this.normalizeSubscriptionUrl(r,n.subscriptionEndpoint),o=n.headers;this.setState({endpoint:r,subscriptionEndpoint:i,headers:o,activeEnv:t.activeEnv,activeProjectName:t.projectName})}},n.prototype.removePlaygroundInClass=function(){var e=document.getElementById("root");e&&e.classList.remove("playgroundIn")},n.prototype.render=function(){var e=this.props.setTitle?l.createElement(f.Helmet,null,l.createElement("title",null,this.getTitle())):null,t=this.props.headers||{},n=this.state.headers||{},r=s({},t,n),i=this.props.theme;return l.createElement("div",null,e,l.createElement(m.ThemeProvider,{theme:s({},m.theme,{mode:i,colours:"dark"===i?g.darkColours:g.lightColours,editorColours:s({},"dark"===i?g.darkEditorColours:g.lightEditorColours,this.props.codeTheme),settings:this.props.settings})},l.createElement(A,null,this.props.config&&this.state.activeEnv&&l.createElement(h.default,{config:this.props.config,folderName:this.props.folderName||"GraphQL App",theme:i,activeEnv:this.state.activeEnv,onSelectEnv:this.handleSelectEnv,onNewWorkspace:this.props.onNewWorkspace,showNewWorkspace:Boolean(this.props.showNewWorkspace),isElectron:Boolean(this.props.isElectron),activeProjectName:this.state.activeProjectName,configPath:this.props.configPath}),l.createElement(p.default,{endpoint:this.state.endpoint,shareEnabled:this.props.shareEnabled,subscriptionEndpoint:this.state.subscriptionEndpoint,shareUrl:this.state.shareUrl,onChangeEndpoint:this.handleChangeEndpoint,onChangeSubscriptionsEndpoint:this.handleChangeSubscriptionsEndpoint,adminAuthToken:this.state.platformToken,getRef:this.getPlaygroundRef,config:this.props.config,configString:this.state.configString,configIsYaml:this.state.configIsYaml,canSaveConfig:Boolean(this.props.canSaveConfig),onChangeConfig:this.handleChangeConfig,onSaveConfig:this.handleSaveConfig,onUpdateSessionCount:this.handleUpdateSessionCount,fixedEndpoints:Boolean(this.state.configString),fixedEndpoint:this.props.fixedEndpoint,headers:r,configPath:this.props.configPath,workspaceName:this.props.workspaceName||this.state.activeProjectName,createApolloLink:this.props.createApolloLink,schema:this.state.schema}))))},n.prototype.getTitle=function(){if(this.state.platformToken||this.state.endpoint.includes("api.graph.cool")){var e=this.getProjectId(this.state.endpoint);return(this.state.endpoint.includes("api.graph.cool")?"shared":"local")+"/"+e+" - Playground"}return"Playground - "+this.state.endpoint},n.prototype.updateSubscriptionsUrl=function(){return u(this,void 0,void 0,function(){var e,t,n=this;return c(this,function(r){switch(r.label){case 0:return e=this.getSubscriptionsUrlCandidated(this.state.endpoint),[4,i(e,function(e){return n.wsEndpointValid(e)})];case 1:return t=r.sent(),t&&this.setState({subscriptionEndpoint:t}),[2]}})})},n.prototype.getSubscriptionsUrlCandidated=function(e){var t=[];if(t.push(e.replace("https","wss").replace("http","ws")),e.includes("graph.cool")&&t.push("wss://subscriptions.graph.cool/v1/"+this.getProjectId(e)),e.includes("/simple/v1/")){var n=e.match(/https?:\/\/(.*?)\//);t.push("ws://"+n[1]+"/subscriptions/v1/"+this.getProjectId(e))}return t},n.prototype.wsEndpointValid=function(e){return new Promise(function(t){var n=new WebSocket(e,"graphql-ws");n.addEventListener("open",function(e){n.send(JSON.stringify({type:"connection_init"}))}),n.addEventListener("message",function(e){"connection_ack"===JSON.parse(e.data).type&&t(!0)}),n.addEventListener("error",function(e){t(!1)}),setTimeout(function(){t(!1)},1e3)})},n.prototype.getProjectId=function(e){return e.split("/").slice(-1)[0]},n}(l.Component),D=function(e,t){return{theme:t.theme||b.getTheme(e,t.settings),settings:b.getSettings(e)}};t.default=v.connect(D,{injectTabs:x.injectTabs})(E);var w,S,k=m.keyframes(w||(w=a(["\n from { \n opacity: 0;\n transform: translateY(10px);\n }\n to { \n opacity: 1;\n transform: translateY(0);\n }\n"],["\n from { \n opacity: 0;\n transform: translateY(10px);\n }\n to { \n opacity: 1;\n transform: translateY(0);\n }\n"]))),A=m.styled.div(S||(S=a(["\n display: flex;\n width: 100%;\n opacity: 0;\n transform: translateY(10px);\n animation: "," 0.5s ease-out forwards 0.2s;\n"],["\n display: flex;\n width: 100%;\n opacity: 0;\n transform: translateY(10px);\n animation: "," 0.5s ease-out forwards 0.2s;\n"])),k)}).call(t,n(11))},function(e,t,n){"use strict";(function(e){var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e},o=function(e,t,n,r){return new(n||(n=Promise))(function(i,o){function a(e){try{u(r.next(e))}catch(e){o(e)}}function s(e){try{u(r.throw(e))}catch(e){o(e)}}function u(e){e.done?i(e.value):new n(function(t){t(e.value)}).then(a,s)}u((r=r.apply(e,t||[])).next())})},a=function(e,t){function n(e){return function(t){return r([e,t])}}function r(n){if(i)throw new TypeError("Generator is already executing.");for(;u;)try{if(i=1,o&&(a=2&n[0]?o.return:n[0]?o.throw||((a=o.return)&&a.call(o),0):o.next)&&!(a=a.call(o,n[1])).done)return a;switch(o=0,a&&(n=[2&n[0],a.value]),n[0]){case 0:case 1:a=n;break;case 4:return u.label++,{value:n[1],done:!1};case 5:u.label++,o=n[1],n=[0];continue;case 7:n=u.ops.pop(),u.trys.pop();continue;default:if(a=u.trys,!(a=a.length>0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]-1&&this.setState({selectedSessionIndex:this.initialIndex}),this.mounted=!0},n.prototype.componentWillReceiveProps=function(e){var t=this;this.props.createApolloLink!==e.createApolloLink&&D.setLinkCreator(e.createApolloLink),e.headers===this.props.headers&&e.endpoint===this.props.endpoint&&e.workspaceName===this.props.workspaceName&&e.sessionHeaders===this.props.sessionHeaders&&e.sessionEndpoint===this.props.sessionEndpoint||this.getSchema(e),this.props.isReloadingSchema&&!e.isReloadingSchema&&setTimeout(function(){t.getSchema(e)}),this.props.endpoint===e.endpoint&&this.props.configPath===e.configPath&&e.workspaceName===this.props.workspaceName||this.props.initState(w.getWorkspaceId(e),e.endpoint),this.props.subscriptionEndpoint!==e.subscriptionEndpoint&&D.setSubscriptionEndpoint(e.subscriptionEndpoint),e.headers!==this.props.headers&&this.props.injectHeaders(e.headers,e.endpoint),e.configString!==this.props.configString&&this.props.setConfigString(e.configString),e.schema!==this.props.schema&&this.setState({schema:e.schema})},n.prototype.schemaGetter=function(e){return o(this,void 0,void 0,function(){var t,n,r,i,o,s,u=this;return a(this,function(a){switch(a.label){case 0:t=this.props||e,n=t.sessionEndpoint||t.endpoint,r=this.state.schema,a.label=1;case 1:return a.trys.push([1,3,,4]),i={endpoint:n,headers:t.sessionHeaders&&t.sessionHeaders.length>0?t.sessionHeaders:JSON.stringify(t.headers),credentials:t.settings["request.credentials"]},[4,D.schemaFetcher.fetch(i)];case 2:return o=a.sent(),D.schemaFetcher.subscribe(i,function(e){i.endpoint!==u.props.endpoint&&i.endpoint!==u.props.sessionEndpoint||u.updateSchema(r,e,t)}),o&&(this.updateSchema(r,o.schema,t),this.initialSchemaFetch&&(this.props.schemaFetchingSuccess(i.endpoint,o.tracingSupported,t.isPollingSchema),this.initialSchemaFetch=!1),this.backoff.stop()),[3,4];case 3:return s=a.sent(),console.error(s),this.props.schemaFetchingError(n,s.message),[3,4];case 4:return[2]}})})},n.prototype.render=function(){var e=m.version;return window.version=e,s.createElement(L,{className:"playground"},s.createElement(c.default,{onNewSession:this.createSession,isApp:this.props.isApp}),s.createElement(P,null,s.createElement(M,{className:"graphiql-wrapper active"},this.props.isConfigTab?s.createElement(d.GraphQLConfigEditor,{onSave:this.handleSaveConfig,isYaml:this.props.configIsYaml,isConfig:!0,readOnly:!this.props.canSaveConfig}):this.props.isSettingsTab?s.createElement(d.PlaygroundSettingsEditor,{onSave:this.handleSaveSettings}):this.props.isFile&&this.props.file?s.createElement(h.default,null):s.createElement(u.default,{shareEnabled:this.props.shareEnabled,fixedEndpoint:this.props.fixedEndpoint,schema:this.state.schema}))),s.createElement(f.default,null),this.props.historyOpen&&this.renderHistoryPopup())},n.prototype.renderHistoryPopup=function(){return s.createElement(l.default,null)},n.prototype.updateSchema=function(e,t,n){if(e!==t){var r=e?_.cachedPrintSchema(e):null;_.cachedPrintSchema(t)===r&&n.isPollingSchema||this.setState({schema:t})}},Object.defineProperty(n.prototype,"httpApiPrefix",{get:function(){return this.props.endpoint.match(/(https?:\/\/.*?)\/?/)[1]},enumerable:!0,configurable:!0}),n.defaultProps={shareEnabled:!1},n}(s.PureComponent);t.Playground=T;var O=x.createStructuredSelector({isConfigTab:C.getIsConfigTab,isSettingsTab:C.getIsSettingsTab,isFile:C.getIsFile,historyOpen:E.getHistoryOpen,file:C.getFile,sessionHeaders:C.getHeaders,settings:S.getSettings,settingsString:S.getSettingsString,isReloadingSchema:C.getIsReloadingSchema,isPollingSchema:C.getIsPollingSchema,sessionEndpoint:C.getEndpoint});t.default=g.connect(O,{selectTabIndex:y.selectTabIndex,selectNextTab:y.selectNextTab,selectPrevTab:y.selectPrevTab,newSession:y.newSession,closeSelectedTab:y.closeSelectedTab,initState:b.initState,saveSettings:y.saveSettings,saveConfig:y.saveConfig,setTracingSupported:y.setTracingSupported,injectHeaders:y.injectHeaders,setConfigString:v.setConfigString,schemaFetchingError:y.schemaFetchingError,schemaFetchingSuccess:y.schemaFetchingSuccess})(T);var F,N,I,L=p.styled.div(F||(F=i(["\n flex: 1;\n display: flex;\n flex-direction: column;\n\n height: 100%;\n margin: 0;\n padding: 0;\n overflow: hidden;\n margin-right: -1px !important;\n\n line-height: 1.5;\n font-family: 'Open Sans', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n letter-spacing: 0.53px;\n color: rgba(0, 0, 0, 0.8);\n\n a:active,\n a:focus,\n button:focus,\n input:focus {\n outline: none;\n }\n"],["\n flex: 1;\n display: flex;\n flex-direction: column;\n\n height: 100%;\n margin: 0;\n padding: 0;\n overflow: hidden;\n margin-right: -1px !important;\n\n line-height: 1.5;\n font-family: 'Open Sans', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n letter-spacing: 0.53px;\n color: rgba(0, 0, 0, 0.8);\n\n a:active,\n a:focus,\n button:focus,\n input:focus {\n outline: none;\n }\n"]))),P=p.styled.div(N||(N=i(["\n height: calc(100vh - 57px);\n position: relative;\n overflow: hidden;\n"],["\n height: calc(100vh - 57px);\n position: relative;\n overflow: hidden;\n"]))),M=p.styled.div(I||(I=i(["\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n visibility: hidden;\n &.active {\n visibility: visible;\n }\n"],["\n width: 100%;\n height: 100%;\n position: relative;\n overflow: hidden;\n visibility: hidden;\n &.active {\n visibility: visible;\n }\n"])))}).call(t,n(11))},function(e,t,n){"use strict";(function(e){var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e},o=function(e,t){var n={};for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&t.indexOf(r)<0&&(n[r]=e[r]);if(null!=e&&"function"===typeof Object.getOwnPropertySymbols)for(var i=0,r=Object.getOwnPropertySymbols(e);i0?"("+this.props.headersCount+")":""))),this.props.queryVariablesActive?a.createElement(h.VariableEditorComponent,{getRef:this.setVariableEditorComponent,onHintInformationRender:this.props.queryVariablesActive?this.handleHintInformationRender:void 0,onRunQuery:this.runQueryAtCursor}):a.createElement(h.HeadersEditorComponent,{getRef:this.setVariableEditorComponent,onHintInformationRender:this.props.queryVariablesActive?this.handleHintInformationRender:void 0,onRunQuery:this.runQueryAtCursor})),a.createElement(K,{ref:this.setQueryResizer})),a.createElement(W,null,a.createElement(J,{ref:this.setResponseResizer}),a.createElement(c.default,null),this.props.queryRunning&&0===this.props.responses.size&&a.createElement(m.default,null),a.createElement(g.default,{setRef:this.setResultComponent}),!this.props.queryRunning&&(!this.props.responses||0===this.props.responses.size)&&a.createElement(oe,null,"Hit the Play Button to get a response here"),this.props.subscriptionActive&&a.createElement(ae,null,"Listening \u2026"),a.createElement(ne,{isOpen:this.props.responseTracingOpen,height:this.props.responseTracingHeight},a.createElement(re,{isOpen:this.props.responseTracingOpen,onMouseDown:this.handleTracingResizeStart},a.createElement(te,{isOpen:!1},"Tracing")),a.createElement(y.default,{open:this.props.responseTracingOpen}))))),this.containerComponent&&a.createElement(C.default,{maxWidth:this.containerComponent.offsetWidth-86},a.createElement(x.default,{label:"Docs",activeColor:"green",tabWidth:"49px"},a.createElement(D.default,{schema:this.props.schema,ref:this.setDocExplorerRef})),a.createElement(x.default,{label:"Schema",activeColor:"blue",tabWidth:"65px"},a.createElement(E.default,{schema:this.props.schema,ref:this.setSchemaExplorerRef,sessionId:this.props.sessionId}))))},n.prototype.autoCompleteLeafs=function(){var e=v.fillLeafs(this.props.schema,this.props.query),t=e.insertions,n=e.result;if(t&&t.length>0){var r=this.queryEditorComponent.getCodeMirror();r.operation(function(){var e=r.getCursor(),i=r.indexFromPos(e);r.setValue(n);var o=0;try{var a=t.map(function(e){var t=e.index,n=e.string;return r.markText(r.posFromIndex(t+o),r.posFromIndex(t+(o+=n.length)),{className:"autoInsertedLeaf",clearOnEnter:!0,title:"Automatically added leaf fields"})});setTimeout(function(){return a.forEach(function(e){return e.clear()})},7e3)}catch(e){}var s=i;t.forEach(function(e){var t=e.index,n=e.string;t1,i=null;if(r&&n){var s=this.state.highlight;i=o.createElement(E,null,o.createElement(D,null,t.map(function(t){return o.createElement(a.default,{operation:t,onMouseOver:e.handleMouseOver,onMouseOut:e.handleMouseOut,onMouseUp:e.handleMouseUp,highlight:s,key:t.name?t.name.value:"*"})})))}var u;!this.props.queryRunning&&r||(u=this.onClick);var c;this.props.queryRunning||!r||n||(c=this.onOptionsOpen);var l=this.props.queryRunning?o.createElement("rect",{fill:"#FFFFFF",x:"10",y:"10",width:"13",height:"13",rx:"1"}):o.createElement("path",{d:"M 11 9 L 24 16 L 11 23 z"});return o.createElement(x,null,o.createElement(C,{isRunning:this.props.queryRunning,onMouseDown:c,onClick:u,title:"Execute Query (Ctrl-Enter)"},o.createElement("svg",{width:"35",height:"35",viewBox:(this.props.queryRunning?4:3)+".5,4.5,24,24"},l)),i)},t}(o.Component),m=l.createStructuredSelector({queryRunning:p.getQueryRunning,operations:p.getOperations,sessionId:p.getSelectedSessionIdFromRoot});t.default=u.connect(m,{runQuery:c.runQuery,stopQuery:c.stopQuery})(f.toJS(h));var g,y,v,b,x=s.styled.div(g||(g=i(["\n position: absolute;\n left: -62px;\n z-index: 5;\n top: 15px;\n margin: 0 14px 0 28px;\n"],["\n position: absolute;\n left: -62px;\n z-index: 5;\n top: 15px;\n margin: 0 14px 0 28px;\n"]))),C=s.styled("div")(y||(y=i(["\n width: 60px;\n height: 60px;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border-radius: 100%;\n transition: background-color 100ms;\n background-color: ",";\n border: 6px solid ",";\n cursor: pointer;\n\n svg {\n fill: ",";\n }\n\n &:hover {\n background-color: ",";\n }\n"],["\n width: 60px;\n height: 60px;\n\n display: flex;\n align-items: center;\n justify-content: center;\n\n border-radius: 100%;\n transition: background-color 100ms;\n background-color: ",";\n border: 6px solid ",";\n cursor: pointer;\n\n svg {\n fill: ",";\n }\n\n &:hover {\n background-color: ",";\n }\n"])),function(e){return e.isRunning?e.theme.editorColours.executeButtonSubscription:e.theme.editorColours.executeButton},function(e){return e.theme.editorColours.executeButtonBorder},function(e){return"light"===e.theme.mode?"white":"inherit"},function(e){return e.isRunning?e.theme.editorColours.executeButtonSubscriptionHover:e.theme.editorColours.executeButtonHover}),E=s.styled.div(v||(v=i(["\n background: #fff;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.25);\n padding: 8px 0;\n left: -1px;\n margin: 0;\n position: absolute;\n top: 78px;\n z-index: 100;\n\n &:before {\n position: absolute;\n background: white;\n content: '';\n top: -4px;\n left: 34px;\n transform: rotate(45deg);\n width: 8px;\n height: 8px;\n }\n"],["\n background: #fff;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.25);\n padding: 8px 0;\n left: -1px;\n margin: 0;\n position: absolute;\n top: 78px;\n z-index: 100;\n\n &:before {\n position: absolute;\n background: white;\n content: '';\n top: -4px;\n left: 34px;\n transform: rotate(45deg);\n width: 8px;\n height: 8px;\n }\n"]))),D=s.styled.ul(b||(b=i(["\n max-height: 270px;\n overflow: scroll;\n\n li {\n cursor: pointer;\n list-style: none;\n min-width: 100px;\n padding: 2px 30px 4px 10px;\n }\n\n li.selected {\n background: rgb(39, 174, 96);\n color: white;\n }\n"],["\n max-height: 270px;\n overflow: scroll;\n\n li {\n cursor: pointer;\n list-style: none;\n min-width: 100px;\n padding: 2px 30px 4px 10px;\n }\n\n li.selected {\n background: rgb(39, 174, 96);\n color: white;\n }\n"])))},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.onMouseOver=function(){t.props.onMouseOver(t.props.operation)},t.onMouseUp=function(){t.props.onMouseUp(t.props.operation)},t}return r(t,e),t.prototype.render=function(){return i.createElement("li",{key:this.props.operation.name?this.props.operation.name.value:"*",className:this.props.operation===this.props.highlight?"selected":"",onMouseOver:this.onMouseOver,onMouseOut:this.props.onMouseOut,onMouseUp:this.onMouseUp},this.props.operation.name?this.props.operation.name.value:"")},t}(i.PureComponent);t.default=o},function(e,t,n){"use strict";e.exports=n(538)},function(e,t,n){"use strict";function r(e){var t=e.trim().toLowerCase();return!y.test(t)||!!v.test(t)}function i(e){var t=h.parse(e,!0);if(t.hostname&&(!t.protocol||b.indexOf(t.protocol)>=0))try{t.hostname=m.toASCII(t.hostname)}catch(e){}return h.encode(h.format(t))}function o(e){var t=h.parse(e,!0);if(t.hostname&&(!t.protocol||b.indexOf(t.protocol)>=0))try{t.hostname=m.toUnicode(t.hostname)}catch(e){}return h.decode(h.format(t))}function a(e,t){if(!(this instanceof a))return new a(e,t);t||s.isString(e)||(t=e||{},e="default"),this.inline=new f,this.block=new p,this.core=new l,this.renderer=new c,this.linkify=new d,this.validateLink=r,this.normalizeLink=i,this.normalizeLinkText=o,this.utils=s,this.helpers=s.assign({},u),this.options={},this.configure(e),t&&this.set(t)}var s=n(4),u=n(548),c=n(552),l=n(553),p=n(561),f=n(575),d=n(267),h=n(88),m=n(271),g={default:n(589),zero:n(590),commonmark:n(591)},y=/^(vbscript|javascript|file|data):/,v=/^data:image\/(gif|png|jpeg|webp);/,b=["http:","https:","mailto:"];a.prototype.set=function(e){return s.assign(this.options,e),this},a.prototype.configure=function(e){var t,n=this;if(s.isString(e)&&(t=e,!(e=g[t])))throw new Error('Wrong `markdown-it` preset "'+t+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&n.set(e.options),e.components&&Object.keys(e.components).forEach(function(t){e.components[t].rules&&n[t].ruler.enableOnly(e.components[t].rules),e.components[t].rules2&&n[t].ruler2.enableOnly(e.components[t].rules2)}),this},a.prototype.enable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach(function(t){n=n.concat(this[t].ruler.enable(e,!0))},this),n=n.concat(this.inline.ruler2.enable(e,!0));var r=e.filter(function(e){return n.indexOf(e)<0});if(r.length&&!t)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+r);return this},a.prototype.disable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach(function(t){n=n.concat(this[t].ruler.disable(e,!0))},this),n=n.concat(this.inline.ruler2.disable(e,!0));var r=e.filter(function(e){return n.indexOf(e)<0});if(r.length&&!t)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+r);return this},a.prototype.use=function(e){var t=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,t),this},a.prototype.parse=function(e,t){if("string"!==typeof e)throw new Error("Input data should be a String");var n=new this.core.State(e,this,t);return this.core.process(n),n.tokens},a.prototype.render=function(e,t){return t=t||{},this.renderer.render(this.parse(e,t),this.options,t)},a.prototype.parseInline=function(e,t){var n=new this.core.State(e,this,t);return n.inlineMode=!0,this.core.process(n),n.tokens},a.prototype.renderInline=function(e,t){return t=t||{},this.renderer.render(this.parseInline(e,t),this.options,t)},e.exports=a},function(e,t,n){"use strict";function r(e){var t,n,r=o[e];if(r)return r;for(r=o[e]=[],t=0;t<128;t++)n=String.fromCharCode(t),/^[0-9a-z]$/i.test(n)?r.push(n):r.push("%"+("0"+t.toString(16).toUpperCase()).slice(-2));for(t=0;t=55296&&s<=57343){if(s>=55296&&s<=56319&&o+1=56320&&u<=57343){l+=encodeURIComponent(e[o]+e[o+1]),o++;continue}l+="%EF%BF%BD"}else l+=encodeURIComponent(e[o]);return l}var o={};i.defaultChars=";/?:@&=+$,-_.!~*'()#",i.componentChars="-_.!~*'()",e.exports=i},function(e,t,n){"use strict";function r(e){var t,n,r=o[e];if(r)return r;for(r=o[e]=[],t=0;t<128;t++)n=String.fromCharCode(t),r.push(n);for(t=0;t=55296&&u<=57343?"\ufffd\ufffd\ufffd":String.fromCharCode(u),t+=6):240===(248&i)&&t+91114111?c+="\ufffd\ufffd\ufffd\ufffd":(u-=65536,c+=String.fromCharCode(55296+(u>>10),56320+(1023&u))),t+=9):c+="\ufffd";return c})}var o={};i.defaultChars=";/?:@&=+$,#",i.componentChars="",e.exports=i},function(e,t,n){"use strict";e.exports=function(e){var t="";return t+=e.protocol||"",t+=e.slashes?"//":"",t+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?t+="["+e.hostname+"]":t+=e.hostname||"",t+=e.port?":"+e.port:"",t+=e.pathname||"",t+=e.search||"",t+=e.hash||""}},function(e,t,n){"use strict";function r(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}function i(e,t){if(e&&e instanceof r)return e;var n=new r;return n.parse(e,t),n}var o=/^([a-z0-9.+-]+:)/i,a=/:[0-9]*$/,s=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,u=["<",">",'"',"`"," ","\r","\n","\t"],c=["{","}","|","\\","^","`"].concat(u),l=["'"].concat(c),p=["%","/","?",";","#"].concat(l),f=["/","?","#"],d=/^[+a-z0-9A-Z_-]{0,63}$/,h=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},g={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};r.prototype.parse=function(e,t){var n,r,i,a,u,c=e;if(c=c.trim(),!t&&1===e.split("#").length){var l=s.exec(c);if(l)return this.pathname=l[1],l[2]&&(this.search=l[2]),this}var y=o.exec(c);if(y&&(y=y[0],i=y.toLowerCase(),this.protocol=y,c=c.substr(y.length)),(t||y||c.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(u="//"===c.substr(0,2))||y&&m[y]||(c=c.substr(2),this.slashes=!0)),!m[y]&&(u||y&&!g[y])){var v=-1;for(n=0;n127?S+="x":S+=w[k];if(!S.match(d)){var _=D.slice(0,n),T=D.slice(n+1),O=w.match(h);O&&(_.push(O[1]),T.unshift(O[2])),T.length&&(c=T.join(".")+c),this.hostname=_.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),E&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var F=c.indexOf("#");-1!==F&&(this.hash=c.substr(F),c=c.slice(0,F));var N=c.indexOf("?");return-1!==N&&(this.search=c.substr(N),c=c.slice(0,N)),c&&(this.pathname=c),g[i]&&this.hostname&&!this.pathname&&(this.pathname=""),this},r.prototype.parseHost=function(e){var t=a.exec(e);t&&(t=t[0],":"!==t&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)},e.exports=i},function(e,t,n){"use strict";t.Any=n(544),t.Cc=n(545),t.Cf=n(546),t.P=n(263),t.Z=n(547)},function(e,t){e.exports=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/},function(e,t){e.exports=/[\0-\x1F\x7F-\x9F]/},function(e,t){e.exports=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804\uDCBD|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/},function(e,t){e.exports=/[ \xA0\u1680\u2000-\u200A\u202F\u205F\u3000]/},function(e,t,n){"use strict";t.parseLinkLabel=n(549),t.parseLinkDestination=n(550),t.parseLinkTitle=n(551)},function(e,t,n){"use strict";e.exports=function(e,t,n){var r,i,o,a,s=-1,u=e.posMax,c=e.pos;for(e.pos=t+1,r=1;e.pos=n)return u;if(34!==(o=e.charCodeAt(t))&&39!==o&&40!==o)return u;for(t++,40===o&&(o=41);t"+a(e[t].content)+""},s.code_block=function(e,t,n,r,i){var o=e[t];return""+a(e[t].content)+"\n"},s.fence=function(e,t,n,r,i){var s,u,c,l,p=e[t],f=p.info?o(p.info).trim():"",d="";return f&&(d=f.split(/\s+/g)[0]),s=n.highlight?n.highlight(p.content,d)||a(p.content):a(p.content),0===s.indexOf(""+s+"\n"):"
"+s+"
\n"},s.image=function(e,t,n,r,i){var o=e[t];return o.attrs[o.attrIndex("alt")][1]=i.renderInlineAsText(o.children,n,r),i.renderToken(e,t,n)},s.hardbreak=function(e,t,n){return n.xhtmlOut?"
\n":"
\n"},s.softbreak=function(e,t,n){return n.breaks?n.xhtmlOut?"
\n":"
\n":"\n"},s.text=function(e,t){return a(e[t].content)},s.html_block=function(e,t){return e[t].content},s.html_inline=function(e,t){return e[t].content},r.prototype.renderAttrs=function(e){var t,n,r;if(!e.attrs)return"";for(r="",t=0,n=e.attrs.length;t\n":">")},r.prototype.renderInline=function(e,t,n){for(var r,i="",o=this.rules,a=0,s=e.length;a\s]/i.test(e)}function i(e){return/^<\/a\s*>/i.test(e)}var o=n(4).arrayReplaceAt;e.exports=function(e){var t,n,a,s,u,c,l,p,f,d,h,m,g,y,v,b,x,C=e.tokens;if(e.md.options.linkify)for(n=0,a=C.length;n=0;t--)if(c=s[t],"link_close"!==c.type){if("html_inline"===c.type&&(r(c.content)&&g>0&&g--,i(c.content)&&g++),!(g>0)&&"text"===c.type&&e.md.linkify.test(c.content)){for(f=c.content,x=e.md.linkify.match(f),l=[],m=c.level,h=0,p=0;ph&&(u=new e.Token("text","",0),u.content=f.slice(h,d),u.level=m,l.push(u)),u=new e.Token("link_open","a",1),u.attrs=[["href",v]],u.level=m++,u.markup="linkify",u.info="auto",l.push(u),u=new e.Token("text","",0),u.content=b,u.level=m,l.push(u),u=new e.Token("link_close","a",-1),u.level=--m,u.markup="linkify",u.info="auto",l.push(u),h=x[p].lastIndex);h=0;t--)n=e[t],"text"!==n.type||i||(n.content=n.content.replace(u,r)),"link_open"===n.type&&"auto"===n.info&&i--,"link_close"===n.type&&"auto"===n.info&&i++}function o(e){var t,n,r=0;for(t=e.length-1;t>=0;t--)n=e[t],"text"!==n.type||r||a.test(n.content)&&(n.content=n.content.replace(/\+-/g,"\xb1").replace(/\.{2,}/g,"\u2026").replace(/([?!])\u2026/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---([^-]|$)/gm,"$1\u2014$2").replace(/(^|\s)--(\s|$)/gm,"$1\u2013$2").replace(/(^|[^-\s])--([^-\s]|$)/gm,"$1\u2013$2")),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}var a=/\+-|\.\.|\?\?\?\?|!!!!|,,|--/,s=/\((c|tm|r|p)\)/i,u=/\((c|tm|r|p)\)/gi,c={c:"\xa9",r:"\xae",p:"\xa7",tm:"\u2122"};e.exports=function(e){var t;if(e.md.options.typographer)for(t=e.tokens.length-1;t>=0;t--)"inline"===e.tokens[t].type&&(s.test(e.tokens[t].content)&&i(e.tokens[t].children),a.test(e.tokens[t].content)&&o(e.tokens[t].children))}},function(e,t,n){"use strict";function r(e,t,n){return e.substr(0,t)+n+e.substr(t+1)}function i(e,t){var n,i,u,p,f,d,h,m,g,y,v,b,x,C,E,D,w,S,k,A,_;for(k=[],n=0;n=0&&!(k[w].level<=h);w--);if(k.length=w+1,"text"===i.type){u=i.content,f=0,d=u.length;e:for(;f=0)g=u.charCodeAt(p.index-1);else for(w=n-1;w>=0&&("softbreak"!==e[w].type&&"hardbreak"!==e[w].type);w--)if("text"===e[w].type){g=e[w].content.charCodeAt(e[w].content.length-1);break}if(y=32,f=48&&g<=57&&(D=E=!1),E&&D&&(E=!1,D=b),E||D){if(D)for(w=k.length-1;w>=0&&(m=k[w],!(k[w].level=0;t--)"inline"===e.tokens[t].type&&u.test(e.tokens[t].content)&&i(e.tokens[t].children,e)}},function(e,t,n){"use strict";function r(e,t,n){this.src=e,this.env=n,this.tokens=[],this.inlineMode=!1,this.md=t}var i=n(135);r.prototype.Token=i,e.exports=r},function(e,t,n){"use strict";function r(){this.ruler=new i;for(var e=0;e=n))&&!(e.sCount[a]=u){e.line=n;break}for(r=0;rn)return!1;if(p=t+1,e.sCount[p]=4)return!1;if((c=e.bMarks[p]+e.tShift[p])>=e.eMarks[p])return!1;if(124!==(s=e.src.charCodeAt(c++))&&45!==s&&58!==s)return!1;for(;c=4)return!1;if(f=i(u.replace(/^\||\|$/g,"")),(d=f.length)>m.length)return!1;if(a)return!0;for(h=e.push("table_open","table",1),h.map=y=[t,0],h=e.push("thead_open","thead",1),h.map=[t,t+1],h=e.push("tr_open","tr",1),h.map=[t,t+1],l=0;l=4);p++){for(f=i(u.replace(/^\||\|$/g,"")),h=e.push("tr_open","tr",1),l=0;l=4))break;r++,i=r}return e.line=i,o=e.push("code_block","code",0),o.content=e.getLines(t,i,4+e.blkIndent,!0),o.map=[t,e.line],!0}},function(e,t,n){"use strict";e.exports=function(e,t,n,r){var i,o,a,s,u,c,l,p=!1,f=e.bMarks[t]+e.tShift[t],d=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(f+3>d)return!1;if(126!==(i=e.src.charCodeAt(f))&&96!==i)return!1;if(u=f,f=e.skipChars(f,i),(o=f-u)<3)return!1;if(l=e.src.slice(u,f),a=e.src.slice(f,d),a.indexOf(String.fromCharCode(i))>=0)return!1;if(r)return!0;for(s=t;!(++s>=n)&&(f=u=e.bMarks[s]+e.tShift[s],d=e.eMarks[s],!(f=4)&&!((f=e.skipChars(f,i))-u=4)return!1;if(62!==e.src.charCodeAt(k++))return!1;if(i)return!0;for(u=d=e.sCount[t]+k-(e.bMarks[t]+e.tShift[t]),32===e.src.charCodeAt(k)?(k++,u++,d++,o=!1,x=!0):9===e.src.charCodeAt(k)?(x=!0,(e.bsCount[t]+d)%4===3?(k++,u++,d++,o=!1):o=!0):x=!1,h=[e.bMarks[t]],e.bMarks[t]=k;k=A,v=[e.sCount[t]],e.sCount[t]=d-u,b=[e.tShift[t]],e.tShift[t]=k-e.bMarks[t],E=e.md.block.ruler.getRules("blockquote"),y=e.parentType,e.parentType="blockquote",w=!1,f=t+1;f=A));f++)if(62!==e.src.charCodeAt(k++)||w){if(l)break;for(C=!1,s=0,c=E.length;s=A,m.push(e.bsCount[f]),e.bsCount[f]=e.sCount[f]+1+(x?1:0),v.push(e.sCount[f]),e.sCount[f]=d-u,b.push(e.tShift[f]),e.tShift[f]=k-e.bMarks[f]}for(g=e.blkIndent,e.blkIndent=0,D=e.push("blockquote_open","blockquote",1),D.markup=">",D.map=p=[t,0],e.md.block.tokenize(e,t,f),D=e.push("blockquote_close","blockquote",-1),D.markup=">",e.lineMax=S,e.parentType=y,p[1]=e.line,s=0;s=4)return!1;if(42!==(o=e.src.charCodeAt(c++))&&45!==o&&95!==o)return!1;for(a=1;c=o)return-1;if((n=e.src.charCodeAt(i++))<48||n>57)return-1;for(;;){if(i>=o)return-1;n=e.src.charCodeAt(i++);{if(!(n>=48&&n<=57)){if(41===n||46===n)break;return-1}if(i-r>=10)return-1}}return i=4)return!1;if(a&&"paragraph"===e.parentType&&e.tShift[t]>=e.blkIndent&&(P=!0),(T=i(e,t))>=0){if(d=!0,F=e.bMarks[t]+e.tShift[t],b=Number(e.src.substr(F,T-F-1)),P&&1!==b)return!1}else{if(!((T=r(e,t))>=0))return!1;d=!1}if(P&&e.skipSpaces(T)>=e.eMarks[t])return!1;if(v=e.src.charCodeAt(T-1),a)return!0;for(y=e.tokens.length,d?(L=e.push("ordered_list_open","ol",1),1!==b&&(L.attrs=[["start",b]])):L=e.push("bullet_list_open","ul",1),L.map=g=[t,0],L.markup=String.fromCharCode(v),C=t,O=!1,I=e.md.block.ruler.getRules("list"),S=e.parentType,e.parentType="list";C=x?1:E-f,p>4&&(p=1),l=f+p,L=e.push("list_item_open","li",1),L.markup=String.fromCharCode(v),L.map=h=[t,0],D=e.blkIndent,A=e.tight,k=e.tShift[t],w=e.sCount[t],e.blkIndent=l,e.tight=!0,e.tShift[t]=u-e.bMarks[t],e.sCount[t]=E,u>=x&&e.isEmpty(t+1)?e.line=Math.min(e.line+2,n):e.md.block.tokenize(e,t,n,!0),e.tight&&!O||(M=!1),O=e.line-t>1&&e.isEmpty(e.line-1),e.blkIndent=D,e.tShift[t]=k,e.sCount[t]=w,e.tight=A,L=e.push("list_item_close","li",-1),L.markup=String.fromCharCode(v),C=t=e.line,h[1]=C,u=e.bMarks[t],C>=n)break;if(e.sCount[C]=4)return!1;if(91!==e.src.charCodeAt(D))return!1;for(;++D3)&&!(e.sCount[S]<0)){for(b=!1,p=0,f=x.length;p=4)return!1;if(35!==(o=e.src.charCodeAt(c))||c>=l)return!1;for(a=1,o=e.src.charCodeAt(++c);35===o&&c6||cc&&r(e.src.charCodeAt(s-1))&&(l=s),e.line=t+1,u=e.push("heading_open","h"+String(a),1),u.markup="########".slice(0,a),u.map=[t,e.line],u=e.push("inline","",0),u.content=e.src.slice(c,l).trim(),u.map=[t,e.line],u.children=[],u=e.push("heading_close","h"+String(a),-1),u.markup="########".slice(0,a),!0))}},function(e,t,n){"use strict";e.exports=function(e,t,n){var r,i,o,a,s,u,c,l,p,f,d=t+1,h=e.md.block.ruler.getRules("paragraph");if(e.sCount[t]-e.blkIndent>=4)return!1;for(f=e.parentType,e.parentType="paragraph";d3)){if(e.sCount[d]>=e.blkIndent&&(u=e.bMarks[d]+e.tShift[d],c=e.eMarks[d],u=c))){l=61===p?1:2;break}if(!(e.sCount[d]<0)){for(i=!1,o=0,a=h.length;o|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(i.source+"\\s*$"),/^$/,!1]];e.exports=function(e,t,n,r){var i,a,s,u,c=e.bMarks[t]+e.tShift[t],l=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(c))return!1;for(u=e.src.slice(c,l),i=0;i3)&&!(e.sCount[u]<0)){for(r=!1,i=0,o=c.length;i0&&this.level++,this.tokens.push(r),r},r.prototype.isEmpty=function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]},r.prototype.skipEmptyLines=function(e){for(var t=this.lineMax;et;)if(!o(this.src.charCodeAt(--e)))return e+1;return e},r.prototype.skipChars=function(e,t){for(var n=this.src.length;en;)if(t!==this.src.charCodeAt(--e))return e+1;return e},r.prototype.getLines=function(e,t,n,r){var i,a,s,u,c,l,p,f=e;if(e>=t)return"";for(l=new Array(t-e),i=0;fn?new Array(a-n+1).join(" ")+this.src.slice(u,c):this.src.slice(u,c)}return l.join("")},r.prototype.Token=i,e.exports=r},function(e,t,n){"use strict";function r(){var e;for(this.ruler=new i,e=0;e=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},r.prototype.parse=function(e,t,n,r){var i,o,a,s=new this.State(e,t,n,r);for(this.tokenize(s),o=this.ruler2.getRules(""),a=o.length,i=0;i=0&&32===e.pending.charCodeAt(n)?n>=1&&32===e.pending.charCodeAt(n-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),o++;o?@[]^_`{|}~-".split("").forEach(function(e){i[e.charCodeAt(0)]=1}),e.exports=function(e,t){var n,o=e.pos,a=e.posMax;if(92!==e.src.charCodeAt(o))return!1;if(++o=g)return!1;for(y=c,l=e.md.helpers.parseLinkDestination(e.src,c,e.posMax),l.ok&&(h=e.md.normalizeLink(l.str),e.md.validateLink(h)?c=l.pos:h=""),y=c;c=g||41!==e.src.charCodeAt(c))&&(v=!0),c++}if(v){if("undefined"===typeof e.env.references)return!1;if(c=0?a=e.src.slice(y,c++):c=s+1):c=s+1,a||(a=e.src.slice(u,s)),!(p=e.env.references[r(a)]))return e.pos=m,!1;h=p.href,f=p.title}return t||(e.pos=u,e.posMax=s,d=e.push("link_open","a",1),d.attrs=n=[["href",h]],f&&n.push(["title",f]),e.md.inline.tokenize(e),d=e.push("link_close","a",-1)),e.pos=c,e.posMax=g,!0}},function(e,t,n){"use strict";var r=n(4).normalizeReference,i=n(4).isSpace;e.exports=function(e,t){var n,o,a,s,u,c,l,p,f,d,h,m,g,y="",v=e.pos,b=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(c=e.pos+2,(u=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((l=u+1)=b)return!1;for(g=l,f=e.md.helpers.parseLinkDestination(e.src,l,e.posMax),f.ok&&(y=e.md.normalizeLink(f.str),e.md.validateLink(y)?l=f.pos:y=""),g=l;l=b||41!==e.src.charCodeAt(l))return e.pos=v,!1;l++}else{if("undefined"===typeof e.env.references)return!1;if(l=0?s=e.src.slice(g,l++):l=u+1):l=u+1,s||(s=e.src.slice(c,u)),!(p=e.env.references[r(s)]))return e.pos=v,!1;y=p.href,d=p.title}return t||(a=e.src.slice(c,u),e.md.inline.parse(a,e.md,e.env,m=[]),h=e.push("image","img",0),h.attrs=n=[["src",y],["alt",""]],h.children=m,h.content=a,d&&n.push(["title",d])),e.pos=l,e.posMax=b,!0}},function(e,t,n){"use strict";var r=/^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/,i=/^<([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)>/;e.exports=function(e,t){var n,o,a,s,u,c,l=e.pos;return 60===e.src.charCodeAt(l)&&(n=e.src.slice(l),!(n.indexOf(">")<0)&&(i.test(n)?(o=n.match(i),s=o[0].slice(1,-1),u=e.md.normalizeLink(s),!!e.md.validateLink(u)&&(t||(c=e.push("link_open","a",1),c.attrs=[["href",u]],c.markup="autolink",c.info="auto",c=e.push("text","",0),c.content=e.md.normalizeLinkText(s),c=e.push("link_close","a",-1),c.markup="autolink",c.info="auto"),e.pos+=o[0].length,!0)):!!r.test(n)&&(a=n.match(r),s=a[0].slice(1,-1),u=e.md.normalizeLink("mailto:"+s),!!e.md.validateLink(u)&&(t||(c=e.push("link_open","a",1),c.attrs=[["href",u]],c.markup="autolink",c.info="auto",c=e.push("text","",0),c.content=e.md.normalizeLinkText(s),c=e.push("link_close","a",-1),c.markup="autolink",c.info="auto"),e.pos+=a[0].length,!0))))}},function(e,t,n){"use strict";function r(e){var t=32|e;return t>=97&&t<=122}var i=n(264).HTML_TAG_RE;e.exports=function(e,t){var n,o,a,s,u=e.pos;return!!e.md.options.html&&(a=e.posMax,!(60!==e.src.charCodeAt(u)||u+2>=a)&&(!(33!==(n=e.src.charCodeAt(u+1))&&63!==n&&47!==n&&!r(n))&&(!!(o=e.src.slice(u).match(i))&&(t||(s=e.push("html_inline","",0),s.content=e.src.slice(u,u+o[0].length)),e.pos+=o[0].length,!0))))}},function(e,t,n){"use strict";var r=n(261),i=n(4).has,o=n(4).isValidEntityCode,a=n(4).fromCodePoint,s=/^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i,u=/^&([a-z][a-z0-9]{1,31});/i;e.exports=function(e,t){var n,c,l=e.pos,p=e.posMax;if(38!==e.src.charCodeAt(l))return!1;if(l+1=0;){if(i=o[n],i.open&&i.marker===r.marker&&i.end<0&&i.level===r.level){var s=(i.close||r.open)&&"undefined"!==typeof i.length&&"undefined"!==typeof r.length&&(i.length+r.length)%3===0;if(!s){r.jump=t-n,r.open=!1,i.end=t,i.jump=0;break}}n-=i.jump+1}}},function(e,t,n){"use strict";e.exports=function(e){var t,n,r=0,i=e.tokens,o=e.tokens.length;for(t=n=0;t0&&this.level++,this.pendingLevel=this.level,this.tokens.push(r),r},r.prototype.scanDelims=function(e,t){var n,r,i,u,c,l,p,f,d,h=e,m=!0,g=!0,y=this.posMax,v=this.src.charCodeAt(e);for(n=e>0?this.src.charCodeAt(e-1):32;h<\uff5c]|[()[\\]{}.,\"'?!\\-]).|\\[(?:(?!"+t.src_ZCc+"|\\]).)*\\]|\\((?:(?!"+t.src_ZCc+"|[)]).)*\\)|\\{(?:(?!"+t.src_ZCc+'|[}]).)*\\}|\\"(?:(?!'+t.src_ZCc+'|["]).)+\\"|\\\'(?:(?!'+t.src_ZCc+"|[']).)+\\'|\\'(?="+t.src_pseudo_letter+"|[-]).|\\.{2,3}[a-zA-Z0-9%/]|\\.(?!"+t.src_ZCc+"|[.]).|"+(e&&e["---"]?"\\-(?!--(?:[^-]|$))(?:-*)|":"\\-+|")+"\\,(?!"+t.src_ZCc+").|\\!(?!"+t.src_ZCc+"|[!]).|\\?(?!"+t.src_ZCc+"|[?]).)+|\\/)?",t.src_email_name='[\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]+',t.src_xn="xn--[a-z0-9\\-]{1,59}",t.src_domain_root="(?:"+t.src_xn+"|"+t.src_pseudo_letter+"{1,63})",t.src_domain="(?:"+t.src_xn+"|(?:"+t.src_pseudo_letter+")|(?:"+t.src_pseudo_letter+"(?:-(?!-)|"+t.src_pseudo_letter+"){0,61}"+t.src_pseudo_letter+"))",t.src_host="(?:(?:(?:(?:"+t.src_domain+")\\.)*"+t.src_domain+"))",t.tpl_host_fuzzy="(?:"+t.src_ip4+"|(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%)))",t.tpl_host_no_ip_fuzzy="(?:(?:(?:"+t.src_domain+")\\.)+(?:%TLDS%))",t.src_host_strict=t.src_host+t.src_host_terminator,t.tpl_host_fuzzy_strict=t.tpl_host_fuzzy+t.src_host_terminator,t.src_host_port_strict=t.src_host+t.src_port+t.src_host_terminator,t.tpl_host_port_fuzzy_strict=t.tpl_host_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_port_no_ip_fuzzy_strict=t.tpl_host_no_ip_fuzzy+t.src_port+t.src_host_terminator,t.tpl_host_fuzzy_test="localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:"+t.src_ZPCc+"|>|$))",t.tpl_email_fuzzy="(^|[><\uff5c]|\\(|"+t.src_ZCc+")("+t.src_email_name+"@"+t.tpl_host_fuzzy_strict+")",t.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|"+t.src_ZPCc+"))((?![$+<=>^`|\uff5c])"+t.tpl_host_port_fuzzy_strict+t.src_path+")",t.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|"+t.src_ZPCc+"))((?![$+<=>^`|\uff5c])"+t.tpl_host_port_no_ip_fuzzy_strict+t.src_path+")",t}},function(e,t,n){"use strict";e.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:100},components:{core:{},block:{},inline:{}}}},function(e,t,n){"use strict";e.exports={options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["paragraph"]},inline:{rules:["text"],rules2:["balance_pairs","text_collapse"]}}}},function(e,t,n){"use strict";e.exports={options:{html:!0,xhtmlOut:!0,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline"]},block:{rules:["blockquote","code","fence","heading","hr","html_block","lheading","list","reference","paragraph"]},inline:{rules:["autolink","backticks","emphasis","entity","escape","html_inline","image","link","newline","text"],rules2:["balance_pairs","emphasis","text_collapse"]}}}},function(e,t,n){(function(t){!function(t){"use strict";function n(e){this.tokens=[],this.tokens.links={},this.options=e||d.defaults,this.rules=h.normal,this.options.gfm&&(this.options.tables?this.rules=h.tables:this.rules=h.gfm)}function r(e,t){if(this.options=t||d.defaults,this.links=e,this.rules=m.normal,this.renderer=this.options.renderer||new i,this.renderer.options=this.options,!this.links)throw new Error("Tokens array requires a `links` property.");this.options.gfm?this.options.breaks?this.rules=m.breaks:this.rules=m.gfm:this.options.pedantic&&(this.rules=m.pedantic)}function i(e){this.options=e||{}}function o(){}function a(e){this.tokens=[],this.token=null,this.options=e||d.defaults,this.options.renderer=this.options.renderer||new i,this.renderer=this.options.renderer,this.renderer.options=this.options}function s(e,t){return e.replace(t?/&/g:/&(?!#?\w+;)/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function u(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,function(e,t){return t=t.toLowerCase(),"colon"===t?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function c(e,t){return e=e.source,t=t||"",{replace:function(t,n){return n=n.source||n,n=n.replace(/(^|[^\[])\^/g,"$1"),e=e.replace(t,n),this},getRegex:function(){return new RegExp(e,t)}}}function l(e,t){return g[" "+e]||(/^[^:]+:\/*[^\/]*$/.test(e)?g[" "+e]=e+"/":g[" "+e]=e.replace(/[^\/]*$/,"")),e=g[" "+e],"//"===t.slice(0,2)?e.replace(/:[\s\S]*/,":")+t:"/"===t.charAt(0)?e.replace(/(:\/*[^\/]*)[\s\S]*/,"$1")+t:e+t}function p(){}function f(e){for(var t,n,r=1;rAn error occurred:

"+s(e.message+"",!0)+"
";throw e}}var h={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:p,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:p,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:p,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n?(?!hr|heading|lheading| {0,3}>|tag)[^\n]+)+)/,text:/^[^\n]+/};h._label=/(?:\\[\[\]]|[^\[\]])+/,h._title=/(?:"(?:\\"|[^"]|"[^"\n]*")*"|'\n?(?:[^'\n]+\n?)*'|\([^()]*\))/,h.def=c(h.def).replace("label",h._label).replace("title",h._title).getRegex(),h.bullet=/(?:[*+-]|\d+\.)/,h.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,h.item=c(h.item,"gm").replace(/bull/g,h.bullet).getRegex(),h.list=c(h.list).replace(/bull/g,h.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+h.def.source+")").getRegex(),h._tag="(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b",h.html=c(h.html).replace("comment",//).replace("closed",/<(tag)[\s\S]+?<\/\1>/).replace("closing",/\s]*)*?\/?>/).replace(/tag/g,h._tag).getRegex(),h.paragraph=c(h.paragraph).replace("hr",h.hr).replace("heading",h.heading).replace("lheading",h.lheading).replace("tag","<"+h._tag).getRegex(),h.blockquote=c(h.blockquote).replace("paragraph",h.paragraph).getRegex(),h.normal=f({},h),h.gfm=f({},h.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),h.gfm.paragraph=c(h.paragraph).replace("(?!","(?!"+h.gfm.fences.source.replace("\\1","\\2")+"|"+h.list.source.replace("\\1","\\3")+"|").getRegex(),h.tables=f({},h.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/}),n.rules=h,n.lex=function(e,t){return new n(t).lex(e)},n.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},n.prototype.token=function(e,t){e=e.replace(/^ +$/gm,"");for(var n,r,i,o,a,s,u,c,l,p,f;e;)if((i=this.rules.newline.exec(e))&&(e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"})),i=this.rules.code.exec(e))e=e.substring(i[0].length),i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?i:i.replace(/\n+$/,"")});else if(i=this.rules.fences.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2],text:i[3]||""});else if(i=this.rules.heading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});else if(t&&(i=this.rules.nptable.exec(e))){for(e=e.substring(i[0].length),s={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/\n$/,"").split("\n")},c=0;c ?/gm,""),this.token(i,t),this.tokens.push({type:"blockquote_end"});else if(i=this.rules.list.exec(e)){for(e=e.substring(i[0].length),o=i[2],f=o.length>1,this.tokens.push({type:"list_start",ordered:f,start:f?+o:""}),i=i[0].match(this.rules.item),n=!1,p=i.length,c=0;c1&&a.length>1||(e=i.slice(c+1).join("\n")+e,c=p-1)),r=n||/\n\n(?!\s*$)/.test(s),c!==p-1&&(n="\n"===s.charAt(s.length-1),r||(r=n)),this.tokens.push({type:r?"loose_item_start":"list_item_start"}),this.token(s,!1),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(i=this.rules.html.exec(e))e=e.substring(i[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===i[1]||"script"===i[1]||"style"===i[1]),text:i[0]});else if(t&&(i=this.rules.def.exec(e)))e=e.substring(i[0].length),i[3]&&(i[3]=i[3].substring(1,i[3].length-1)),l=i[1].toLowerCase(),this.tokens.links[l]||(this.tokens.links[l]={href:i[2],title:i[3]});else if(t&&(i=this.rules.table.exec(e))){for(e=e.substring(i[0].length),s={type:"table",header:i[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3].replace(/(?: *\| *)?\n$/,"").split("\n")},c=0;c])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:p,tag:/^|^<\/?[a-zA-Z0-9\-]+(?:"[^"]*"|'[^']*'|\s[^<'">\/\s]*)*?\/?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^_([^\s_](?:[^_]|__)+?[^\s_])_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:p,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/,m.link=c(m.link).replace("inside",m._inside).replace("href",m._href).getRegex(),m.reflink=c(m.reflink).replace("inside",m._inside).getRegex(),m.normal=f({},m),m.pedantic=f({},m.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/}),m.gfm=f({},m.normal,{escape:c(m.escape).replace("])","~|])").getRegex(),url:c(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("email",m._email).getRegex(),_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:c(m.text).replace("]|","~]|").replace("|","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|").getRegex()}),m.breaks=f({},m.gfm,{br:c(m.br).replace("{2,}","*").getRegex(),text:c(m.gfm.text).replace("{2,}","*").getRegex()}),r.rules=m,r.output=function(e,t,n){return new r(t,n).output(e)},r.prototype.output=function(e){for(var t,n,r,i,o="";e;)if(i=this.rules.escape.exec(e))e=e.substring(i[0].length),o+=i[1];else if(i=this.rules.autolink.exec(e))e=e.substring(i[0].length),"@"===i[2]?(n=s(this.mangle(i[1])),r="mailto:"+n):(n=s(i[1]),r=n),o+=this.renderer.link(r,null,n);else if(this.inLink||!(i=this.rules.url.exec(e))){if(i=this.rules.tag.exec(e))!this.inLink&&/^/i.test(i[0])&&(this.inLink=!1),e=e.substring(i[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):s(i[0]):i[0];else if(i=this.rules.link.exec(e))e=e.substring(i[0].length),this.inLink=!0,o+=this.outputLink(i,{href:i[2],title:i[3]}),this.inLink=!1;else if((i=this.rules.reflink.exec(e))||(i=this.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=i[0].charAt(0),e=i[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(i,t),this.inLink=!1}else if(i=this.rules.strong.exec(e))e=e.substring(i[0].length),o+=this.renderer.strong(this.output(i[2]||i[1]));else if(i=this.rules.em.exec(e))e=e.substring(i[0].length),o+=this.renderer.em(this.output(i[2]||i[1]));else if(i=this.rules.code.exec(e))e=e.substring(i[0].length),o+=this.renderer.codespan(s(i[2].trim(),!0));else if(i=this.rules.br.exec(e))e=e.substring(i[0].length),o+=this.renderer.br();else if(i=this.rules.del.exec(e))e=e.substring(i[0].length),o+=this.renderer.del(this.output(i[1]));else if(i=this.rules.text.exec(e))e=e.substring(i[0].length),o+=this.renderer.text(s(this.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else i[0]=this.rules._backpedal.exec(i[0])[0],e=e.substring(i[0].length),"@"===i[2]?(n=s(i[0]),r="mailto:"+n):(n=s(i[0]),r="www."===i[1]?"http://"+n:n),o+=this.renderer.link(r,null,n);return o},r.prototype.outputLink=function(e,t){var n=s(t.href),r=t.title?s(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,s(e[1]))},r.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"\u2014").replace(/--/g,"\u2013").replace(/(^|[-\u2014\/(\[{"\s])'/g,"$1\u2018").replace(/'/g,"\u2019").replace(/(^|[-\u2014\/(\[{\u2018\s])"/g,"$1\u201c").replace(/"/g,"\u201d").replace(/\.{3}/g,"\u2026"):e},r.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,i=0;i.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},i.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'
'+(n?e:s(e,!0))+"\n
\n":"
"+(n?e:s(e,!0))+"\n
"},i.prototype.blockquote=function(e){return"
\n"+e+"
\n"},i.prototype.html=function(e){return e},i.prototype.heading=function(e,t,n){return"'+e+"\n"},i.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},i.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},i.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},i.prototype.paragraph=function(e){return"

    "+e+"

    \n"},i.prototype.table=function(e,t){return"\n\n"+e+"\n\n"+t+"\n
    \n"},i.prototype.tablerow=function(e){return"\n"+e+"\n"},i.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' style="text-align:'+t.align+'">':"<"+n+">")+e+"\n"},i.prototype.strong=function(e){return""+e+""},i.prototype.em=function(e){return""+e+""},i.prototype.codespan=function(e){return""+e+""},i.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},i.prototype.del=function(e){return""+e+""},i.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(u(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return n}this.options.baseUrl&&!y.test(e)&&(e=l(this.options.baseUrl,e));var i='
    "},i.prototype.image=function(e,t,n){this.options.baseUrl&&!y.test(e)&&(e=l(this.options.baseUrl,e));var r=''+n+'":">"},i.prototype.text=function(e){return e},o.prototype.strong=o.prototype.em=o.prototype.codespan=o.prototype.del=o.prototype.text=function(e){return e},o.prototype.link=o.prototype.image=function(e,t,n){return""+n},o.prototype.br=function(){return""},a.parse=function(e,t){return new a(t).parse(e)},a.prototype.parse=function(e){this.inline=new r(e.links,this.options),this.inlineText=new r(e.links,f({},this.options,{renderer:new o})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},a.prototype.next=function(){return this.token=this.tokens.pop()},a.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},a.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},a.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,u(this.inlineText.output(this.token.text)));case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,i="",o="";for(n="",e=0;et.firstLine();)i=e.Pos(i.line-1,0),l=s(!1);if(l&&!l.cleared&&"unfold"!==a){var p=n(t,o);e.on(p,"mousedown",function(t){f.clear(),e.e_preventDefault(t)});var f=t.markText(l.from,l.to,{replacedWith:p,clearOnEnter:r(t,o,"clearOnEnter"),__isFold:!0});f.on("clear",function(n,r){e.signal(t,"unfold",t,n,r)}),e.signal(t,"fold",t,l.from,l.to)}}function n(e,t){var n=r(e,t,"widget");if("string"==typeof n){var i=document.createTextNode(n);n=document.createElement("span"),n.appendChild(i),n.className="CodeMirror-foldmarker"}else n&&(n=n.cloneNode(!0));return n}function r(e,t,n){if(t&&void 0!==t[n])return t[n];var r=e.options.foldOptions;return r&&void 0!==r[n]?r[n]:i[n]}e.newFoldFunction=function(e,n){return function(r,i){t(r,i,{rangeFinder:e,widget:n})}},e.defineExtension("foldCode",function(e,n,r){t(this,e,n,r)}),e.defineExtension("isFolded",function(e){for(var t=this.findMarksAt(e),n=0;n",type:"keyToKey",toKeys:"h"},{keys:"",type:"keyToKey",toKeys:"l"},{keys:"",type:"keyToKey",toKeys:"k"},{keys:"",type:"keyToKey",toKeys:"j"},{keys:"",type:"keyToKey",toKeys:"l"},{keys:"",type:"keyToKey",toKeys:"h",context:"normal"},{keys:"",type:"keyToKey",toKeys:"W"},{keys:"",type:"keyToKey",toKeys:"B",context:"normal"},{keys:"",type:"keyToKey",toKeys:"w"},{keys:"",type:"keyToKey",toKeys:"b",context:"normal"},{keys:"",type:"keyToKey",toKeys:"j"},{keys:"",type:"keyToKey",toKeys:"k"},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:"",context:"insert"},{keys:"",type:"keyToKey",toKeys:"",context:"insert"},{keys:"s",type:"keyToKey",toKeys:"cl",context:"normal"},{keys:"s",type:"keyToKey",toKeys:"c",context:"visual"},{keys:"S",type:"keyToKey",toKeys:"cc",context:"normal"},{keys:"S",type:"keyToKey",toKeys:"VdO",context:"visual"},{keys:"",type:"keyToKey",toKeys:"0"},{keys:"",type:"keyToKey",toKeys:"$"},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:""},{keys:"",type:"keyToKey",toKeys:"j^",context:"normal"},{keys:"",type:"action",action:"toggleOverwrite",context:"insert"},{keys:"H",type:"motion",motion:"moveToTopLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"M",type:"motion",motion:"moveToMiddleLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"L",type:"motion",motion:"moveToBottomLine",motionArgs:{linewise:!0,toJumplist:!0}},{keys:"h",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!1}},{keys:"l",type:"motion",motion:"moveByCharacters",motionArgs:{forward:!0}},{keys:"j",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,linewise:!0}},{keys:"k",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,linewise:!0}},{keys:"gj",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!0}},{keys:"gk",type:"motion",motion:"moveByDisplayLines",motionArgs:{forward:!1}},{keys:"w",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1}},{keys:"W",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!1,bigWord:!0}},{keys:"e",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,inclusive:!0}},{keys:"E",type:"motion",motion:"moveByWords",motionArgs:{forward:!0,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"b",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1}},{keys:"B",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1,bigWord:!0}},{keys:"ge",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,inclusive:!0}},{keys:"gE",type:"motion",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!0,bigWord:!0,inclusive:!0}},{keys:"{",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!1,toJumplist:!0}},{keys:"}",type:"motion",motion:"moveByParagraph",motionArgs:{forward:!0,toJumplist:!0}},{keys:"(",type:"motion",motion:"moveBySentence",motionArgs:{forward:!1}},{keys:")",type:"motion",motion:"moveBySentence",motionArgs:{forward:!0}},{keys:"",type:"motion",motion:"moveByPage",motionArgs:{forward:!0}},{keys:"",type:"motion",motion:"moveByPage",motionArgs:{forward:!1}},{keys:"",type:"motion",motion:"moveByScroll",motionArgs:{forward:!0,explicitRepeat:!0}},{keys:"",type:"motion",motion:"moveByScroll",motionArgs:{forward:!1,explicitRepeat:!0}},{keys:"gg",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!1,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"G",type:"motion",motion:"moveToLineOrEdgeOfDocument",motionArgs:{forward:!0,explicitRepeat:!0,linewise:!0,toJumplist:!0}},{keys:"0",type:"motion",motion:"moveToStartOfLine"},{keys:"^",type:"motion",motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"+",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0}},{keys:"-",type:"motion",motion:"moveByLines",motionArgs:{forward:!1,toFirstChar:!0}},{keys:"_",type:"motion",motion:"moveByLines",motionArgs:{forward:!0,toFirstChar:!0,repeatOffset:-1}},{keys:"$",type:"motion",motion:"moveToEol",motionArgs:{inclusive:!0}},{keys:"%",type:"motion",motion:"moveToMatchedSymbol",motionArgs:{inclusive:!0,toJumplist:!0}},{keys:"f",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"F",type:"motion",motion:"moveToCharacter",motionArgs:{forward:!1}},{keys:"t",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!0,inclusive:!0}},{keys:"T",type:"motion",motion:"moveTillCharacter",motionArgs:{forward:!1}},{keys:";",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!0}},{keys:",",type:"motion",motion:"repeatLastCharacterSearch",motionArgs:{forward:!1}},{keys:"'",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0,linewise:!0}},{keys:"`",type:"motion",motion:"goToMark",motionArgs:{toJumplist:!0}},{keys:"]`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0}},{keys:"[`",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1}},{keys:"]'",type:"motion",motion:"jumpToMark",motionArgs:{forward:!0,linewise:!0}},{keys:"['",type:"motion",motion:"jumpToMark",motionArgs:{forward:!1,linewise:!0}},{keys:"]p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0,matchIndent:!0}},{keys:"[p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0,matchIndent:!0}},{keys:"]",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!0,toJumplist:!0}},{keys:"[",type:"motion",motion:"moveToSymbol",motionArgs:{forward:!1,toJumplist:!0}},{keys:"|",type:"motion",motion:"moveToColumn"},{keys:"o",type:"motion",motion:"moveToOtherHighlightedEnd",context:"visual"},{keys:"O",type:"motion",motion:"moveToOtherHighlightedEnd",motionArgs:{sameLine:!0},context:"visual"},{keys:"d",type:"operator",operator:"delete"},{keys:"y",type:"operator",operator:"yank"},{keys:"c",type:"operator",operator:"change"},{keys:">",type:"operator",operator:"indent",operatorArgs:{indentRight:!0}},{keys:"<",type:"operator",operator:"indent",operatorArgs:{indentRight:!1}},{keys:"g~",type:"operator",operator:"changeCase"},{keys:"gu",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},isEdit:!0},{keys:"gU",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},isEdit:!0},{keys:"n",type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:!0}},{keys:"N",type:"motion",motion:"findNext",motionArgs:{forward:!1,toJumplist:!0}},{keys:"x",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!0},operatorMotionArgs:{visualLine:!1}},{keys:"X",type:"operatorMotion",operator:"delete",motion:"moveByCharacters",motionArgs:{forward:!1},operatorMotionArgs:{visualLine:!0}},{keys:"D",type:"operatorMotion",operator:"delete",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"D",type:"operator",operator:"delete",operatorArgs:{linewise:!0},context:"visual"},{keys:"Y",type:"operatorMotion",operator:"yank",motion:"expandToLine",motionArgs:{linewise:!0},context:"normal"},{keys:"Y",type:"operator",operator:"yank",operatorArgs:{linewise:!0},context:"visual"},{keys:"C",type:"operatorMotion",operator:"change",motion:"moveToEol",motionArgs:{inclusive:!0},context:"normal"},{keys:"C",type:"operator",operator:"change",operatorArgs:{linewise:!0},context:"visual"},{keys:"~",type:"operatorMotion",operator:"changeCase",motion:"moveByCharacters",motionArgs:{forward:!0},operatorArgs:{shouldMoveCursor:!0},context:"normal"},{keys:"~",type:"operator",operator:"changeCase",context:"visual"},{keys:"",type:"operatorMotion",operator:"delete",motion:"moveByWords",motionArgs:{forward:!1,wordEnd:!1},context:"insert"},{keys:"",type:"action",action:"jumpListWalk",actionArgs:{forward:!0}},{keys:"",type:"action",action:"jumpListWalk",actionArgs:{forward:!1}},{keys:"",type:"action",action:"scroll",actionArgs:{forward:!0,linewise:!0}},{keys:"",type:"action",action:"scroll",actionArgs:{forward:!1,linewise:!0}},{keys:"a",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"charAfter"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"eol"},context:"normal"},{keys:"A",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"endOfSelectedArea"},context:"visual"},{keys:"i",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"inplace"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"firstNonBlank"},context:"normal"},{keys:"I",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{insertAt:"startOfSelectedArea"},context:"visual"},{keys:"o",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!0},context:"normal"},{keys:"O",type:"action",action:"newLineAndEnterInsertMode",isEdit:!0,interlaceInsertRepeat:!0,actionArgs:{after:!1},context:"normal"},{keys:"v",type:"action",action:"toggleVisualMode"},{keys:"V",type:"action",action:"toggleVisualMode",actionArgs:{linewise:!0}},{keys:"",type:"action",action:"toggleVisualMode",actionArgs:{blockwise:!0}},{keys:"",type:"action",action:"toggleVisualMode",actionArgs:{blockwise:!0}},{keys:"gv",type:"action",action:"reselectLastSelection"},{keys:"J",type:"action",action:"joinLines",isEdit:!0},{keys:"p",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!0,isEdit:!0}},{keys:"P",type:"action",action:"paste",isEdit:!0,actionArgs:{after:!1,isEdit:!0}},{keys:"r",type:"action",action:"replace",isEdit:!0},{keys:"@",type:"action",action:"replayMacro"},{keys:"q",type:"action",action:"enterMacroRecordMode"},{keys:"R",type:"action",action:"enterInsertMode",isEdit:!0,actionArgs:{replace:!0}},{keys:"u",type:"action",action:"undo",context:"normal"},{keys:"u",type:"operator",operator:"changeCase",operatorArgs:{toLower:!0},context:"visual",isEdit:!0},{keys:"U",type:"operator",operator:"changeCase",operatorArgs:{toLower:!1},context:"visual",isEdit:!0},{keys:"",type:"action",action:"redo"},{keys:"m",type:"action",action:"setMark"},{keys:'"',type:"action",action:"setRegister"},{keys:"zz",type:"action",action:"scrollToCursor",actionArgs:{position:"center"}},{keys:"z.",type:"action",action:"scrollToCursor",actionArgs:{position:"center"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"zt",type:"action",action:"scrollToCursor",actionArgs:{position:"top"}},{keys:"z",type:"action",action:"scrollToCursor",actionArgs:{position:"top"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:"z-",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"}},{keys:"zb",type:"action",action:"scrollToCursor",actionArgs:{position:"bottom"},motion:"moveToFirstNonWhiteSpaceCharacter"},{keys:".",type:"action",action:"repeatLastEdit"},{keys:"",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!0,backtrack:!1}},{keys:"",type:"action",action:"incrementNumberToken",isEdit:!0,actionArgs:{increase:!1,backtrack:!1}},{keys:"",type:"action",action:"indent",actionArgs:{indentRight:!0},context:"insert"},{keys:"",type:"action",action:"indent",actionArgs:{indentRight:!1},context:"insert"},{keys:"a",type:"motion",motion:"textObjectManipulation"},{keys:"i",type:"motion",motion:"textObjectManipulation",motionArgs:{textObjectInner:!0}},{keys:"/",type:"search",searchArgs:{forward:!0,querySrc:"prompt",toJumplist:!0}},{keys:"?",type:"search",searchArgs:{forward:!1,querySrc:"prompt",toJumplist:!0}},{keys:"*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",wholeWordOnly:!0,toJumplist:!0}},{keys:"g*",type:"search",searchArgs:{forward:!0,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:"g#",type:"search",searchArgs:{forward:!1,querySrc:"wordUnderCursor",toJumplist:!0}},{keys:":",type:"ex"}],n=[{name:"colorscheme",shortName:"colo"},{name:"map"},{name:"imap",shortName:"im"},{name:"nmap",shortName:"nm"},{name:"vmap",shortName:"vm"},{name:"unmap"},{name:"write",shortName:"w"},{name:"undo",shortName:"u"},{name:"redo",shortName:"red"},{name:"set",shortName:"se"},{name:"set",shortName:"se"},{name:"setlocal",shortName:"setl"},{name:"setglobal",shortName:"setg"},{name:"sort",shortName:"sor"},{name:"substitute",shortName:"s",possiblyAsync:!0},{name:"nohlsearch",shortName:"noh"},{name:"yank",shortName:"y"},{name:"delmarks",shortName:"delm"},{name:"registers",shortName:"reg",excludeFromCommandHistory:!0},{name:"global",shortName:"g"}],r=e.Pos;e.Vim=function(){function i(t){t.setOption("disableInput",!0),t.setOption("showCursorWhenSelecting",!1),e.signal(t,"vim-mode-change",{mode:"normal"}),t.on("cursorActivity",ct),_(t),e.on(t.getInputField(),"paste",h(t))}function o(t){t.setOption("disableInput",!1),t.off("cursorActivity",ct),e.off(t.getInputField(),"paste",h(t)),t.state.vim=null}function a(t,n){this==e.keyMap.vim&&(e.rmClass(t.getWrapperElement(),"cm-fat-cursor"),"contenteditable"==t.getOption("inputStyle")&&null!=document.body.style.caretColor&&(p(t),t.getInputField().style.caretColor="")),n&&n.attach==s||o(t)}function s(t,n){this==e.keyMap.vim&&(e.addClass(t.getWrapperElement(),"cm-fat-cursor"),"contenteditable"==t.getOption("inputStyle")&&null!=document.body.style.caretColor&&(l(t),t.getInputField().style.caretColor="transparent")),n&&n.attach==s||i(t)}function u(e){for(var t=e.listSelections(),n=[],i=0;i")}function h(e){var t=e.state.vim;return t.onPasteFn||(t.onPasteFn=function(){t.insertMode||(e.setCursor(z(e.getCursor(),0,1)),Pt.enterInsertMode(e,{},t))}),t.onPasteFn}function m(e,t){for(var n=[],r=e;r=e.firstLine()&&t<=e.lastLine()}function y(e){return/^[a-z]$/.test(e)}function v(e){return-1!="()[]{}".indexOf(e)}function b(e){return vt.test(e)}function x(e){return/^[A-Z]$/.test(e)}function C(e){return/^\s*$/.test(e)}function E(e){return-1!=".?!".indexOf(e)}function D(e,t){for(var n=0;n"==t.slice(-11)){var n=t.length-11,r=e.slice(0,n),i=t.slice(0,n);return r==i&&e.length>n?"full":0==i.indexOf(r)&&"partial"}return e==t?"full":0==t.indexOf(e)&&"partial"}function H(e){var t=/^.*(<[^>]+>)$/.exec(e),n=t?t[1]:e.slice(-1);if(n.length>1)switch(n){case"":n="\n";break;case"":n=" ";break;default:n=""}return n}function W(e,t,n){return function(){for(var r=0;r2&&(t=Y.apply(void 0,Array.prototype.slice.call(arguments,1))),J(e,t)?e:t}function X(e,t){return arguments.length>2&&(t=X.apply(void 0,Array.prototype.slice.call(arguments,1))),J(e,t)?t:e}function Z(e,t,n){var r=J(e,t),i=J(t,n);return r&&i}function ee(e,t){return e.getLine(t).length}function te(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function ne(e){return e.replace(/([.?*+$\[\]\/\\(){}|\-])/g,"\\$1")}function re(e,t,n){var i=ee(e,t),o=new Array(n-i+1).join(" ");e.setCursor(r(t,i)),e.replaceRange(o,e.getCursor())}function ie(e,t){var n=[],i=e.listSelections(),o=Q(e.clipPos(t)),a=!K(t,o),s=e.getCursor("head"),u=ae(i,s),c=K(i[u].head,i[u].anchor),l=i.length-1,p=l-u>u?l:0,f=i[p].anchor,d=Math.min(f.line,o.line),h=Math.max(f.line,o.line),m=f.ch,g=o.ch,y=i[p].head.ch-m,v=g-m;y>0&&v<=0?(m++,a||g--):y<0&&v>=0?(m--,c||g++):y<0&&-1==v&&(m--,g++);for(var b=d;b<=h;b++){var x={anchor:new r(b,m),head:new r(b,g)};n.push(x)}return e.setSelections(n),t.ch=g,f.ch=m,f}function oe(e,t,n){for(var r=[],i=0;ic&&(o.line=c),o.ch=ee(e,o.line)}return{ranges:[{anchor:a,head:o}],primary:0}}if("block"==n){for(var l=Math.min(a.line,o.line),p=Math.min(a.ch,o.ch),f=Math.max(a.line,o.line),d=Math.max(a.ch,o.ch)+1,h=f-l+1,m=o.line==l?0:h-1,g=[],y=0;y0&&o&&C(o);o=i.pop())n.line--,n.ch=0;o?(n.line--,n.ch=ee(e,n.line)):n.ch=0}}function me(e,t,n){t.ch=0,n.ch=0,n.line++}function ge(e){if(!e)return 0;var t=e.search(/\S/);return-1==t?e.length:t}function ye(e,t,n,i,o){for(var a=fe(e),s=e.getLine(a.line),u=a.ch,c=o?bt[0]:xt[0];!c(s.charAt(u));)if(++u>=s.length)return null;i?c=xt[0]:(c=bt[0])(s.charAt(u))||(c=bt[1]);for(var l=u,p=u;c(s.charAt(l))&&l=0;)p--;if(p++,t){for(var f=l;/\s/.test(s.charAt(l))&&l0;)p--;p||(p=d)}}return{start:r(a.line,p),end:r(a.line,l)}}function ve(e,t,n){K(t,n)||Tt.jumpList.add(e,t,n)}function be(e,t){Tt.lastCharacterSearch.increment=e,Tt.lastCharacterSearch.forward=t.forward,Tt.lastCharacterSearch.selectedCharacter=t.selectedCharacter}function xe(e,t,n,i){var o=Q(e.getCursor()),a=n?1:-1,s=n?e.lineCount():-1,u=o.ch,c=o.line,l=e.getLine(c),p={lineText:l,nextCh:l.charAt(u),lastCh:null,index:u,symb:i,reverseSymb:(n?{")":"(","}":"{"}:{"(":")","{":"}"})[i],forward:n,depth:0,curMoveThrough:!1},f=Mt[i];if(!f)return o;var d=jt[f].init,h=jt[f].isComplete;for(d&&d(p);c!==s&&t;){if(p.index+=a,p.nextCh=p.lineText.charAt(p.index),!p.nextCh){if(c+=a,p.lineText=e.getLine(c)||"",a>0)p.index=0;else{var m=p.lineText.length;p.index=m>0?m-1:0}p.nextCh=p.lineText.charAt(p.index)}h(p)&&(o.line=c,o.ch=p.index,t--)}return p.nextCh||p.curMoveThrough?r(c,p.index):o}function Ce(e,t,n,r,i){var o=t.line,a=t.ch,s=e.getLine(o),u=n?1:-1,c=r?xt:bt;if(i&&""==s){if(o+=u,s=e.getLine(o),!g(e,o))return null;a=n?0:s.length}for(;;){if(i&&""==s)return{from:0,to:0,line:o};for(var l=u>0?s.length:-1,p=l,f=l;a!=l;){for(var d=!1,h=0;h0?0:s.length}}function Ee(e,t,n,i,o,a){var s=Q(t),u=[];(i&&!o||!i&&o)&&n++;for(var c=!(i&&o),l=0;l0;)s(d,i)&&n--,d+=i;return new r(d,0)}var h=e.state.vim;if(h.visualLine&&s(l,1,!0)){var m=h.sel.anchor;s(m.line,-1,!0)&&(o&&m.line==l||(l+=1))}var g=a(l);for(d=l;d<=f&&n;d++)s(d,1,!0)&&(o&&a(d)==g||n--);for(c=new r(d,0),d>f&&!g?g=!0:o=!1,d=l;d>p&&(o&&a(d)!=g&&d!=l||!s(d,-1,!0));d--);return u=new r(d,0),{start:u,end:c}}function _e(e,t,n,i){function o(e,t){if(t.pos+t.dir<0||t.pos+t.dir>=t.line.length){if(t.ln+=t.dir,!g(e,t.ln))return t.line=null,t.ln=null,void(t.pos=null);t.line=e.getLine(t.ln),t.pos=t.dir>0?0:t.line.length-1}else t.pos+=t.dir}for(var a={ln:t.line,pos:t.ch};n>0;)a=i<0?function(e,t,n,r){var i=e.getLine(t),a={line:i,ln:t,pos:n,dir:r},s={ln:a.ln,pos:null},u=""===a.line;for(o(e,a);null!==a.line;){if(""===a.line&&!u)return null!==s.pos?s:{ln:a.ln,pos:a.pos};if(E(a.line[a.pos])&&null!==s.pos&&(a.ln!==s.ln||a.pos+1!==s.pos))return s;""===a.line||C(a.line[a.pos])||(u=!1,s={ln:a.ln,pos:a.pos}),o(e,a)}var i=e.getLine(s.ln);s.pos=0;for(var c=0;c=0;--l)if(!C(i[l])){u.pos=l;break}return u}(e,a.ln,a.pos,i),n--;return r(a.ln,a.pos)}function Te(e,t,n,i){var o,a,s=t,u={"(":/[()]/,")":/[()]/,"[":/[[\]]/,"]":/[[\]]/,"{":/[{}]/,"}":/[{}]/}[n],c={"(":"(",")":"(","[":"[","]":"[","{":"{","}":"{"}[n],l=e.getLine(s.line).charAt(s.ch),p=l===c?1:0;if(o=e.scanForBracket(r(s.line,s.ch+p),-1,void 0,{bracketRegex:u}),a=e.scanForBracket(r(s.line,s.ch+p),1,void 0,{bracketRegex:u}),!o||!a)return{start:s,end:s};if(o=o.pos,a=a.pos,o.line==a.line&&o.ch>a.ch||o.line>a.line){var f=o;o=a,a=f}return i?a.ch+=1:o.ch+=1,{start:o,end:a}}function Oe(e,t,n,i){var o,a,s,u,c=Q(t),l=e.getLine(c.line),p=l.split(""),f=p.indexOf(n);if(c.ch-1&&!o;s--)p[s]==n&&(o=s+1);else o=c.ch+1;if(o&&!a)for(s=o,u=p.length;s'+t+"",{bottom:!0,duration:5e3}):alert(t)}function Ge(e,t){var n=''+(e||"")+'';return t&&(n+=' '+t+""),n}function Ve(e,t){var n=(t.prefix||"")+" "+(t.desc||"");Ie(e,Ge(t.prefix,t.desc),n,t.onClose,t)}function qe(e,t){if(e instanceof RegExp&&t instanceof RegExp){for(var n=["global","multiline","ignoreCase","source"],r=0;r=t&&e<=n:e==t}function Xe(e){var t=e.getScrollInfo(),n=e.coordsChar({left:0,top:6+t.top},"local"),r=t.clientHeight-10+t.top,i=e.coordsChar({left:0,top:r},"local");return{top:n.line,bottom:i.line}}function Ze(e,t,n){if("'"==n){var r=e.doc.history.done,i=r[r.length-2];return i&&i.ranges&&i.ranges[0].head}if("."==n){if(0==e.doc.history.lastModTime)return;var o=e.doc.history.done.filter(function(e){if(void 0!==e.changes)return e});o.reverse();return o[0].changes[0].to}var a=t.marks[n];return a&&a.find()}function et(t,n,r,i,o,a,s,u,c){function l(){t.operation(function(){for(;!m;)p(),f();d()})}function p(){var e=t.getRange(a.from(),a.to()),n=e.replace(s,u);a.replace(n)}function f(){for(;a.findNext()&&Ye(a.from(),i,o);)if(r||!g||a.from().line!=g.line)return t.scrollIntoView(a.from(),30),t.setSelection(a.from(),a.to()),g=a.from(),void(m=!1);m=!0}function d(e){if(e&&e(),t.focus(),g){t.setCursor(g);var n=t.state.vim;n.exMode=!1,n.lastHPos=n.lastHSPos=g.ch}c&&c()}function h(n,r,i){switch(e.e_stop(n),e.keyName(n)){case"Y":p(),f();break;case"N":f();break;case"A":var o=c;c=void 0,t.operation(l),c=o;break;case"L":p();case"Q":case"Esc":case"Ctrl-C":case"Ctrl-[":d(i)}return m&&d(i),!0}t.state.vim.exMode=!0;var m=!1,g=a.from();return f(),m?void ze(t,"No matches for "+s.source):n?void Ve(t,{prefix:"replace with "+u+" (y/n/a/q/l)",onKeyDown:h}):(l(),void(c&&c()))}function tt(t){var n=t.state.vim,r=Tt.macroModeState,i=Tt.registerController.getRegister("."),o=r.isPlaying,a=r.lastInsertModeChanges,s=[];if(!o){for(var u=a.inVisualBlock&&n.lastSelection?n.lastSelection.visualBlock.height:1,c=a.changes,s=[],l=0;l1&&(ht(t,n,n.insertModeRepeat-1,!0),n.lastEditInputState.repeatOverride=n.insertModeRepeat),delete n.insertModeRepeat,n.insertMode=!1,t.setCursor(t.getCursor().line,t.getCursor().ch-1),t.setOption("keyMap","vim"),t.setOption("disableInput",!0),t.toggleOverwrite(!1),i.setText(a.changes.join("")),e.signal(t,"vim-mode-change",{mode:"normal"}),r.isRecording&&at(r)}function nt(e){t.unshift(e)}function rt(e,t,n,r,i){var o={keys:e,type:t};o[t]=n,o[t+"Args"]=r;for(var a in i)o[a]=i[a];nt(o)}function it(t,n,r,i){var o=Tt.registerController.getRegister(i);if(":"==i)return o.keyBuffer[0]&&Gt.processCommand(t,o.keyBuffer[0]),void(r.isPlaying=!1);var a=o.keyBuffer,s=0;r.isPlaying=!0,r.replaySearchQueries=o.searchQueries.slice(0);for(var u=0;u|<\w+>|./.exec(p),l=c[0],p=p.substring(c.index+l.length),e.Vim.handleKey(t,l,"macro"),n.insertMode){var f=o.insertModeChanges[s++].changes;Tt.macroModeState.lastInsertModeChanges.changes=f,mt(t,f,1),tt(t)}r.isPlaying=!1}function ot(e,t){if(!e.isPlaying){var n=e.latestRegister,r=Tt.registerController.getRegister(n);r&&r.pushText(t)}}function at(e){if(!e.isPlaying){var t=e.latestRegister,n=Tt.registerController.getRegister(t);n&&n.pushInsertModeChanges&&n.pushInsertModeChanges(e.lastInsertModeChanges)}}function st(e,t){if(!e.isPlaying){var n=e.latestRegister,r=Tt.registerController.getRegister(n);r&&r.pushSearchQuery&&r.pushSearchQuery(t)}}function ut(e,t){var n=Tt.macroModeState,r=n.lastInsertModeChanges;if(!n.isPlaying)for(;t;){if(r.expectCursorActivityForChange=!0,"+input"==t.origin||"paste"==t.origin||void 0===t.origin){var i=t.text.join("\n");r.maybeReset&&(r.changes=[],r.maybeReset=!1),e.state.overwrite&&!/\n/.test(i)?r.changes.push([i]):r.changes.push(i)}t=t.next}}function ct(e){var t=e.state.vim;if(t.insertMode){var n=Tt.macroModeState;if(n.isPlaying)return;var r=n.lastInsertModeChanges;r.expectCursorActivityForChange?r.expectCursorActivityForChange=!1:r.maybeReset=!0}else e.curOp.isVimOp||pt(e,t);t.visualMode&<(e)}function lt(e){var t=e.state.vim,n=$(e,Q(t.sel.head)),r=z(n,0,1);t.fakeCursor&&t.fakeCursor.clear(),t.fakeCursor=e.markText(n,r,{className:"cm-animate-fat-cursor"})}function pt(t,n){var r=t.getCursor("anchor"),i=t.getCursor("head");if(n.visualMode&&!t.somethingSelected()?de(t,!1):n.visualMode||n.insertMode||!t.somethingSelected()||(n.visualMode=!0,n.visualLine=!1,e.signal(t,"vim-mode-change",{mode:"visual"})),n.visualMode){var o=J(i,r)?0:-1,a=J(i,r)?-1:0;i=z(i,0,o),r=z(r,0,a),n.sel={anchor:r,head:i},Se(t,n,"<",Y(i,r)),Se(t,n,">",X(i,r))}else n.insertMode||(n.lastHPos=t.getCursor().ch)}function ft(e){this.keyName=e}function dt(t){function n(){return i.maybeReset&&(i.changes=[],i.maybeReset=!1),i.changes.push(new ft(o)),!0}var r=Tt.macroModeState,i=r.lastInsertModeChanges,o=e.keyName(t);o&&(-1==o.indexOf("Delete")&&-1==o.indexOf("Backspace")||e.lookupKey(o,"vim-insert",n))}function ht(e,t,n,r){function i(){s?Nt.processAction(e,t,t.lastEditActionCommand):Nt.evalInput(e,t)}function o(n){if(a.lastInsertModeChanges.changes.length>0){n=t.lastEditActionCommand?n:1;var r=a.lastInsertModeChanges;mt(e,r.changes,n)}}var a=Tt.macroModeState;a.isPlaying=!0;var s=!!t.lastEditActionCommand,u=t.inputState;if(t.inputState=t.lastEditInputState,s&&t.lastEditActionCommand.interlaceInsertRepeat)for(var c=0;c"]),St=[].concat(Ct,Et,Dt,["-",'"',".",":","/"]),kt={};w("filetype",void 0,"string",["ft"],function(e,t){if(void 0!==t){if(void 0===e){var n=t.getOption("mode");return"null"==n?"":n}var n=""==e?"null":e;t.setOption("mode",n)}});var At=function(){function e(e,t,s){function u(t){var i=++r%n,o=a[i];o&&o.clear(),a[i]=e.setBookmark(t)}var c=r%n,l=a[c];if(l){var p=l.find();p&&!K(p,t)&&u(t)}else u(t);u(s),i=r,(o=r-n+1)<0&&(o=0)}function t(e,t){r+=t,r>i?r=i:r0?1:-1,l=e.getCursor();do{if(r+=c,(s=a[(n+r)%n])&&(u=s.find())&&!K(l,u))break}while(ro)}return s}var n=100,r=-1,i=0,o=0,a=new Array(n);return{cachedCursor:void 0,add:e,move:t}},_t=function(e){return e?{changes:e.changes,expectCursorActivityForChange:e.expectCursorActivityForChange}:{changes:[],expectCursorActivityForChange:!1}};A.prototype={exitMacroRecordMode:function(){var e=Tt.macroModeState;e.onRecordingDone&&e.onRecordingDone(),e.onRecordingDone=void 0,e.isRecording=!1},enterMacroRecordMode:function(e,t){var n=Tt.registerController.getRegister(t);n&&(n.clear(),this.latestRegister=t,e.openDialog&&(this.onRecordingDone=e.openDialog("(recording)["+t+"]",null,{bottom:!0})),this.isRecording=!0)}};var Tt,Ot,Ft={buildKeyMap:function(){},getRegisterController:function(){return Tt.registerController},resetVimGlobalState_:T,getVimGlobalState_:function(){return Tt},maybeInitVimState_:_,suppressErrorLogging:!1,InsertModeKey:ft,map:function(e,t,n){Gt.map(e,t,n)},unmap:function(e,t){Gt.unmap(e,t)},setOption:S,getOption:k,defineOption:w,defineEx:function(e,t,n){if(t){if(0!==e.indexOf(t))throw new Error('(Vim.defineEx) "'+t+'" is not a prefix of "'+e+'", command not registered')}else t=e;zt[e]=n,Gt.commandMap_[t]={name:e,shortName:t,type:"api"}},handleKey:function(e,t,n){var r=this.findKey(e,t,n);if("function"===typeof r)return r()},findKey:function(n,r,i){function o(){var e=Tt.macroModeState;if(e.isRecording){if("q"==r)return e.exitMacroRecordMode(),F(n),!0;"mapping"!=i&&ot(e,r)}}function a(){if(""==r)return F(n),c.visualMode?de(n):c.insertMode&&tt(n),!0}function s(t){for(var i;t;)i=/<\w+-.+?>|<\w+>|./.exec(t),r=i[0],t=t.substring(i.index+r.length),e.Vim.handleKey(n,r,"mapping")}var u,c=_(n);return u=c.insertMode?function(){if(a())return!0;for(var e=c.inputState.keyBuffer=c.inputState.keyBuffer+r,i=1==r.length,o=Nt.matchCommand(e,t,c.inputState,"insert");e.length>1&&"full"!=o.type;){var e=c.inputState.keyBuffer=e.slice(1),s=Nt.matchCommand(e,t,c.inputState,"insert");"none"!=s.type&&(o=s)}if("none"==o.type)return F(n),!1;if("partial"==o.type)return Ot&&window.clearTimeout(Ot),Ot=window.setTimeout(function(){c.insertMode&&c.inputState.keyBuffer&&F(n)},k("insertModeEscKeysTimeout")),!i;if(Ot&&window.clearTimeout(Ot),i){for(var u=n.listSelections(),l=0;l0||this.motionRepeat.length>0)&&(e=1,this.prefixRepeat.length>0&&(e*=parseInt(this.prefixRepeat.join(""),10)),this.motionRepeat.length>0&&(e*=parseInt(this.motionRepeat.join(""),10))),e},N.prototype={setText:function(e,t,n){this.keyBuffer=[e||""],this.linewise=!!t,this.blockwise=!!n},pushText:function(e,t){t&&(this.linewise||this.keyBuffer.push("\n"),this.linewise=!0),this.keyBuffer.push(e)},pushInsertModeChanges:function(e){this.insertModeChanges.push(_t(e))},pushSearchQuery:function(e){this.searchQueries.push(e)},clear:function(){this.keyBuffer=[],this.insertModeChanges=[],this.searchQueries=[],this.linewise=!1},toString:function(){return this.keyBuffer.join("")}},L.prototype={pushText:function(e,t,n,r,i){r&&"\n"!==n.charAt(n.length-1)&&(n+="\n");var o=this.isValidRegister(e)?this.getRegister(e):null;if(!o){switch(t){case"yank":this.registers[0]=new N(n,r,i);break;case"delete":case"change":-1==n.indexOf("\n")?this.registers["-"]=new N(n,r):(this.shiftNumericRegisters_(),this.registers[1]=new N(n,r))}return void this.unnamedRegister.setText(n,r,i)}x(e)?o.pushText(n,r):o.setText(n,r,i),this.unnamedRegister.setText(o.toString(),r)},getRegister:function(e){return this.isValidRegister(e)?(e=e.toLowerCase(),this.registers[e]||(this.registers[e]=new N),this.registers[e]):this.unnamedRegister},isValidRegister:function(e){return e&&D(e,St)},shiftNumericRegisters_:function(){for(var e=9;e>=2;e--)this.registers[e]=this.getRegister(""+(e-1))}},P.prototype={nextMatch:function(e,t){var n=this.historyBuffer,r=t?-1:1;null===this.initialPrefix&&(this.initialPrefix=e);for(var i=this.iterator+r;t?i>=0:i=n.length?(this.iterator=n.length,this.initialPrefix):i<0?e:void 0},pushInput:function(e){var t=this.historyBuffer.indexOf(e);t>-1&&this.historyBuffer.splice(t,1),e.length&&this.historyBuffer.push(e)},reset:function(){this.initialPrefix=null,this.iterator=this.historyBuffer.length}};var Nt={matchCommand:function(e,t,n,r){var i=V(e,t,r,n);if(!i.full&&!i.partial)return{type:"none"};if(!i.full&&i.partial)return{type:"partial"};for(var o,a=0;a"==o.keys.slice(-11)){var u=H(e);if(!u)return{type:"none"};n.selectedCharacter=u}return{type:"full",command:o}},processCommand:function(e,t,n){switch(t.inputState.repeatOverride=n.repeatOverride,n.type){case"motion":this.processMotion(e,t,n);break;case"operator":this.processOperator(e,t,n);break;case"operatorMotion":this.processOperatorMotion(e,t,n);break;case"action":this.processAction(e,t,n);break;case"search":this.processSearch(e,t,n);break;case"ex":case"keyToEx":this.processEx(e,t,n)}},processMotion:function(e,t,n){t.inputState.motion=n.motion,t.inputState.motionArgs=U(n.motionArgs),this.evalInput(e,t)},processOperator:function(e,t,n){var r=t.inputState;if(r.operator){if(r.operator==n.operator)return r.motion="expandToLine",r.motionArgs={linewise:!0},void this.evalInput(e,t);F(e)}r.operator=n.operator,r.operatorArgs=U(n.operatorArgs),t.visualMode&&this.evalInput(e,t)},processOperatorMotion:function(e,t,n){var r=t.visualMode,i=U(n.operatorMotionArgs);i&&r&&i.visualLine&&(t.visualLine=!0),this.processOperator(e,t,n),r||this.processMotion(e,t,n)},processAction:function(e,t,n){var r=t.inputState,i=r.getRepeat(),o=!!i,a=U(n.actionArgs)||{};r.selectedCharacter&&(a.selectedCharacter=r.selectedCharacter),n.operator&&this.processOperator(e,t,n),n.motion&&this.processMotion(e,t,n),(n.motion||n.operator)&&this.evalInput(e,t),a.repeat=i||1,a.repeatIsExplicit=o,a.registerName=r.registerName,F(e),t.lastMotion=null,n.isEdit&&this.recordLastEdit(t,r,n),Pt[n.action](e,a,t)},processSearch:function(t,n,r){function i(e,i,o){Tt.searchHistoryController.pushInput(e),Tt.searchHistoryController.reset();try{He(t,e,i,o)}catch(n){return ze(t,"Invalid regex: "+e),void F(t)}Nt.processMotion(t,n,{type:"motion",motion:"findNext",motionArgs:{forward:!0,toJumplist:r.searchArgs.toJumplist}})}function o(e){t.scrollTo(f.left,f.top),i(e,!0,!0);var n=Tt.macroModeState;n.isRecording&&st(n,e)}function a(n,r,i){var o,a,s=e.keyName(n);"Up"==s||"Down"==s?(o="Up"==s,a=n.target?n.target.selectionEnd:0,r=Tt.searchHistoryController.nextMatch(r,o)||"",i(r),a&&n.target&&(n.target.selectionEnd=n.target.selectionStart=Math.min(a,n.target.value.length))):"Left"!=s&&"Right"!=s&&"Ctrl"!=s&&"Alt"!=s&&"Shift"!=s&&Tt.searchHistoryController.reset();var c;try{c=He(t,r,!0,!0)}catch(n){}c?t.scrollIntoView(Ke(t,!u,c),30):(Je(t),t.scrollTo(f.left,f.top))}function s(n,r,i){var o=e.keyName(n);"Esc"==o||"Ctrl-C"==o||"Ctrl-["==o||"Backspace"==o&&""==r?(Tt.searchHistoryController.pushInput(r),Tt.searchHistoryController.reset(),He(t,p),Je(t),t.scrollTo(f.left,f.top),e.e_stop(n),F(t),i(),t.focus()):"Up"==o||"Down"==o?e.e_stop(n):"Ctrl-U"==o&&(e.e_stop(n),i(""))}if(t.getSearchCursor){var u=r.searchArgs.forward,c=r.searchArgs.wholeWordOnly;Ne(t).setReversed(!u);var l=u?"/":"?",p=Ne(t).getQuery(),f=t.getScrollInfo();switch(r.searchArgs.querySrc){case"prompt":var d=Tt.macroModeState;if(d.isPlaying){var h=d.replaySearchQueries.shift();i(h,!0,!1)}else Ve(t,{onClose:o,prefix:l,desc:$t,onKeyUp:a,onKeyDown:s});break;case"wordUnderCursor":var m=ye(t,!1,!0,!1,!0),g=!0;if(m||(m=ye(t,!1,!0,!1,!1),g=!1),!m)return;var h=t.getLine(m.start.line).substring(m.start.ch,m.end.ch);h=g&&c?"\\b"+h+"\\b":ne(h),Tt.jumpList.cachedCursor=t.getCursor(),t.setCursor(m.start),i(h,!0,!1)}}},processEx:function(t,n,r){function i(e){Tt.exCommandHistoryController.pushInput(e),Tt.exCommandHistoryController.reset(),Gt.processCommand(t,e)}function o(n,r,i){var o,a,s=e.keyName(n);("Esc"==s||"Ctrl-C"==s||"Ctrl-["==s||"Backspace"==s&&""==r)&&(Tt.exCommandHistoryController.pushInput(r),Tt.exCommandHistoryController.reset(),e.e_stop(n),F(t),i(),t.focus()),"Up"==s||"Down"==s?(e.e_stop(n),o="Up"==s,a=n.target?n.target.selectionEnd:0,r=Tt.exCommandHistoryController.nextMatch(r,o)||"",i(r),a&&n.target&&(n.target.selectionEnd=n.target.selectionStart=Math.min(a,n.target.value.length))):"Ctrl-U"==s?(e.e_stop(n),i("")):"Left"!=s&&"Right"!=s&&"Ctrl"!=s&&"Alt"!=s&&"Shift"!=s&&Tt.exCommandHistoryController.reset()}"keyToEx"==r.type?Gt.processCommand(t,r.exArgs.input):n.visualMode?Ve(t,{onClose:i,prefix:":",value:"'<,'>",onKeyDown:o,selectValueOnOpen:!1}):Ve(t,{onClose:i,prefix:":",onKeyDown:o})},evalInput:function(e,t){var n,i,o,a=t.inputState,s=a.motion,u=a.motionArgs||{},c=a.operator,l=a.operatorArgs||{},p=a.registerName,f=t.sel,d=Q(t.visualMode?$(e,f.head):e.getCursor("head")),h=Q(t.visualMode?$(e,f.anchor):e.getCursor("anchor")),m=Q(d),g=Q(h);if(c&&this.recordLastEdit(t,a),o=void 0!==a.repeatOverride?a.repeatOverride:a.getRepeat(),o>0&&u.explicitRepeat?u.repeatIsExplicit=!0:(u.noRepeat||!u.explicitRepeat&&0===o)&&(o=1,u.repeatIsExplicit=!1),a.selectedCharacter&&(u.selectedCharacter=l.selectedCharacter=a.selectedCharacter),u.repeat=o,F(e),s){var y=It[s](e,d,u,t);if(t.lastMotion=It[s],!y)return;if(u.toJumplist){var v=Tt.jumpList,b=v.cachedCursor;b?(ve(e,b,y),delete v.cachedCursor):ve(e,d,y)}y instanceof Array?(i=y[0],n=y[1]):n=y,n||(n=Q(d)),t.visualMode?(t.visualBlock&&n.ch===1/0||(n=$(e,n,t.visualBlock)),i&&(i=$(e,i,!0)),i=i||g,f.anchor=i,f.head=n,le(e),Se(e,t,"<",J(i,n)?i:n),Se(e,t,">",J(i,n)?n:i)):c||(n=$(e,n),e.setCursor(n.line,n.ch))}if(c){if(l.lastSel){i=g;var x=l.lastSel,C=Math.abs(x.head.line-x.anchor.line),E=Math.abs(x.head.ch-x.anchor.ch);n=x.visualLine?r(g.line+C,g.ch):x.visualBlock?r(g.line+C,g.ch+E):x.head.line==x.anchor.line?r(g.line,g.ch+E):r(g.line+C,g.ch),t.visualMode=!0,t.visualLine=x.visualLine,t.visualBlock=x.visualBlock,f=t.sel={anchor:i,head:n},le(e)}else t.visualMode&&(l.lastSel={anchor:Q(f.anchor),head:Q(f.head),visualBlock:t.visualBlock,visualLine:t.visualLine});var D,w,S,k,A;if(t.visualMode){if(D=Y(f.head,f.anchor),w=X(f.head,f.anchor),S=t.visualLine||l.linewise,k=t.visualBlock?"block":S?"line":"char",A=pe(e,{anchor:D,head:w},k),S){var _=A.ranges;if("block"==k)for(var T=0;T<_.length;T++)_[T].head.ch=ee(e,_[T].head.line);else"line"==k&&(_[0].head=r(_[0].head.line+1,0))}}else{if(D=Q(i||g),w=Q(n||m),J(w,D)){var O=D;D=w,w=O}S=u.linewise||l.linewise,S?me(e,D,w):u.forward&&he(e,D,w),k="char";A=pe(e,{anchor:D,head:w},k,!u.inclusive||S)}e.setSelections(A.ranges,A.primary),t.lastMotion=null,l.repeat=o,l.registerName=p,l.linewise=S;var N=Lt[c](e,l,A.ranges,g,n);t.visualMode&&de(e,null!=N),N&&e.setCursor(N)}},recordLastEdit:function(e,t,n){var r=Tt.macroModeState;r.isPlaying||(e.lastEditInputState=t,e.lastEditActionCommand=n,r.lastInsertModeChanges.changes=[],r.lastInsertModeChanges.expectCursorActivityForChange=!1)}},It={moveToTopLine:function(e,t,n){var i=Xe(e).top+n.repeat-1;return r(i,ge(e.getLine(i)))},moveToMiddleLine:function(e){var t=Xe(e),n=Math.floor(.5*(t.top+t.bottom));return r(n,ge(e.getLine(n)))},moveToBottomLine:function(e,t,n){var i=Xe(e).bottom-n.repeat+1;return r(i,ge(e.getLine(i)))},expandToLine:function(e,t,n){return r(t.line+n.repeat-1,1/0)},findNext:function(e,t,n){var r=Ne(e),i=r.getQuery();if(i){var o=!n.forward;return o=r.isReversed()?!o:o,Qe(e,i),Ke(e,o,i,n.repeat)}},goToMark:function(e,t,n,r){var i=Ze(e,r,n.selectedCharacter);return i?n.linewise?{line:i.line,ch:ge(e.getLine(i.line))}:i:null},moveToOtherHighlightedEnd:function(e,t,n,i){if(i.visualBlock&&n.sameLine){var o=i.sel;return[$(e,r(o.anchor.line,o.head.ch)),$(e,r(o.head.line,o.anchor.ch))]}return[i.sel.head,i.sel.anchor]},jumpToMark:function(e,t,n,i){for(var o=t,a=0;al&&o.line==l?this.moveToEol(e,t,n,i):(n.toFirstChar&&(a=ge(e.getLine(u)),i.lastHPos=a),i.lastHSPos=e.charCoords(r(u,a),"div").left,r(u,a))},moveByDisplayLines:function(e,t,n,i){var o=t;switch(i.lastMotion){case this.moveByDisplayLines:case this.moveByScroll:case this.moveByLines:case this.moveToColumn:case this.moveToEol:break;default:i.lastHSPos=e.charCoords(o,"div").left}var a=n.repeat,s=e.findPosV(o,n.forward?a:-a,"line",i.lastHSPos);if(s.hitSide)if(n.forward)var u=e.charCoords(s,"div"),c={top:u.top+8,left:i.lastHSPos},s=e.coordsChar(c,"div");else{var l=e.charCoords(r(e.firstLine(),0),"div");l.left=i.lastHSPos,s=e.coordsChar(l,"div")}return i.lastHPos=s.ch,s},moveByPage:function(e,t,n){var r=t,i=n.repeat;return e.findPosV(r,n.forward?i:-i,"page")},moveByParagraph:function(e,t,n){var r=n.forward?1:-1;return Ae(e,t,n.repeat,r)},moveBySentence:function(e,t,n){var r=n.forward?1:-1;return _e(e,t,n.repeat,r)},moveByScroll:function(e,t,n,r){var i=e.getScrollInfo(),o=null,a=n.repeat;a||(a=i.clientHeight/(2*e.defaultTextHeight()));var s=e.charCoords(t,"local");n.repeat=a;var o=It.moveByDisplayLines(e,t,n,r);if(!o)return null;var u=e.charCoords(o,"local");return e.scrollTo(null,i.top+u.top-s.top),o},moveByWords:function(e,t,n){return Ee(e,t,n.repeat,!!n.forward,!!n.wordEnd,!!n.bigWord)},moveTillCharacter:function(e,t,n){var r=n.repeat,i=De(e,r,n.forward,n.selectedCharacter),o=n.forward?-1:1;return be(o,n),i?(i.ch+=o,i):null},moveToCharacter:function(e,t,n){var r=n.repeat;return be(0,n),De(e,r,n.forward,n.selectedCharacter)||t},moveToSymbol:function(e,t,n){return xe(e,n.repeat,n.forward,n.selectedCharacter)||t},moveToColumn:function(e,t,n,r){var i=n.repeat;return r.lastHPos=i-1,r.lastHSPos=e.charCoords(t,"div").left,we(e,i)},moveToEol:function(e,t,n,i){var o=t;i.lastHPos=1/0;var a=r(o.line+n.repeat-1,1/0),s=e.clipPos(a);return s.ch--,i.lastHSPos=e.charCoords(s,"div").left,a},moveToFirstNonWhiteSpaceCharacter:function(e,t){var n=t;return r(n.line,ge(e.getLine(n.line)))},moveToMatchedSymbol:function(e,t){for(var n,i=t,o=i.line,a=i.ch,s=e.getLine(o);at.lastLine()&&n.linewise&&!h?t.replaceRange("",d,l):t.replaceRange("",c,l),n.linewise&&(h||(t.setCursor(d),e.commands.newlineAndIndent(t)),c.ch=Number.MAX_VALUE),o=c}Tt.registerController.pushText(n.registerName,"change",a,n.linewise,i.length>1),Pt.enterInsertMode(t,{head:o},t.state.vim)},delete:function(e,t,n){var i,o,a=e.state.vim;if(a.visualBlock){o=e.getSelection();var s=j("",n.length);e.replaceSelections(s),i=n[0].anchor}else{var u=n[0].anchor,c=n[0].head;t.linewise&&c.line!=e.firstLine()&&u.line==e.lastLine()&&u.line==c.line-1&&(u.line==e.firstLine()?u.ch=0:u=r(u.line-1,ee(e,u.line-1))),o=e.getRange(u,c),e.replaceRange("",u,c),i=u,t.linewise&&(i=It.moveToFirstNonWhiteSpaceCharacter(e,u))}return Tt.registerController.pushText(t.registerName,"delete",o,t.linewise,a.visualBlock),$(e,i,a.insertMode)},indent:function(e,t,n){var r=e.state.vim,i=n[0].anchor.line,o=r.visualBlock?n[n.length-1].anchor.line:n[0].head.line,a=r.visualMode?t.repeat:1;t.linewise&&o--;for(var s=i;s<=o;s++)for(var u=0;uc.top?(u.line+=(s-c.top)/i,u.line=Math.ceil(u.line),e.setCursor(u),c=e.charCoords(u,"local"),e.scrollTo(null,c.top)):e.scrollTo(null,s);else{var l=s+e.getScrollInfo().clientHeight;l=a.anchor.line?z(a.head,0,1):r(a.anchor.line,0);else if("inplace"==o&&i.visualMode)return;t.setOption("disableInput",!1),n&&n.replace?(t.toggleOverwrite(!0),t.setOption("keyMap","vim-replace"),e.signal(t,"vim-mode-change",{mode:"replace"})):(t.toggleOverwrite(!1),t.setOption("keyMap","vim-insert"),e.signal(t,"vim-mode-change",{mode:"insert"})),Tt.macroModeState.isPlaying||(t.on("change",ut),e.on(t.getInputField(),"keydown",dt)),i.visualMode&&de(t),oe(t,s,u)}},toggleVisualMode:function(t,n,i){var o,a=n.repeat,s=t.getCursor();i.visualMode?i.visualLine^n.linewise||i.visualBlock^n.blockwise?(i.visualLine=!!n.linewise,i.visualBlock=!!n.blockwise,e.signal(t,"vim-mode-change",{mode:"visual",subMode:i.visualLine?"linewise":i.visualBlock?"blockwise":""}),le(t)):de(t):(i.visualMode=!0,i.visualLine=!!n.linewise,i.visualBlock=!!n.blockwise,o=$(t,r(s.line,s.ch+a-1),!0),i.sel={anchor:s,head:o},e.signal(t,"vim-mode-change",{mode:"visual",subMode:i.visualLine?"linewise":i.visualBlock?"blockwise":""}),le(t),Se(t,i,"<",Y(s,o)),Se(t,i,">",X(s,o)))},reselectLastSelection:function(t,n,r){var i=r.lastSelection;if(r.visualMode&&ue(t,r),i){var o=i.anchorMark.find(),a=i.headMark.find();if(!o||!a)return;r.sel={anchor:o,head:a},r.visualMode=!0,r.visualLine=i.visualLine,r.visualBlock=i.visualBlock,le(t),Se(t,r,"<",Y(o,a)),Se(t,r,">",X(o,a)),e.signal(t,"vim-mode-change",{mode:"visual",subMode:r.visualLine?"linewise":r.visualBlock?"blockwise":""})}},joinLines:function(e,t,n){var i,o;if(n.visualMode){if(i=e.getCursor("anchor"),o=e.getCursor("head"),J(o,i)){var a=o;o=i,i=a}o.ch=ee(e,o.line)-1}else{var s=Math.max(t.repeat,2);i=e.getCursor(),o=$(e,r(i.line+s-1,1/0))}for(var u=0,c=i.line;c1)var a=Array(t.repeat+1).join(a);var h=o.linewise,m=o.blockwise;if(h)n.visualMode?a=n.visualLine?a.slice(0,-1):"\n"+a.slice(0,a.length-1)+"\n":t.after?(a="\n"+a.slice(0,a.length-1),i.ch=ee(e,i.line)):i.ch=0;else{if(m){a=a.split("\n");for(var g=0;ge.lastLine()&&e.replaceRange("\n",r(k,0));var A=ee(e,k);Al.length&&(o=l.length),a=r(u.line,o)}if("\n"==s)i.visualMode||t.replaceRange("",u,a),(e.commands.newlineAndIndentContinueComment||e.commands.newlineAndIndent)(t);else{var p=t.getRange(u,a);if(p=p.replace(/[^\n]/g,s),i.visualBlock){var f=new Array(t.getOption("tabSize")+1).join(" ");p=t.getSelection(),p=p.replace(/\t/g,f).replace(/[^\n]/g,s).split("\n"),t.replaceSelections(p)}else t.replaceRange(p,u,a);i.visualMode?(u=J(c[0].anchor,c[0].head)?c[0].anchor:c[0].head,t.setCursor(u),de(t,!1)):t.setCursor(z(a,0,-1))}},incrementNumberToken:function(e,t){for(var n,i,o,a,s=e.getCursor(),u=e.getLine(s.line),c=/(-?)(?:(0x)([\da-f]+)|(0b|0|)(\d+))/gi;null!==(n=c.exec(u))&&(i=n.index,o=i+n[0].length,!(s.ch=1)return!0}else e.nextCh===e.reverseSymb&&e.depth--;return!1}},section:{init:function(e){e.curMoveThrough=!0,e.symb=(e.forward?"]":"[")===e.symb?"{":"}"},isComplete:function(e){return 0===e.index&&e.nextCh===e.symb}},comment:{isComplete:function(e){var t="*"===e.lastCh&&"/"===e.nextCh;return e.lastCh=e.nextCh,t}},method:{init:function(e){e.symb="m"===e.symb?"{":"}",e.reverseSymb="{"===e.symb?"}":"{"},isComplete:function(e){return e.nextCh===e.symb}},preprocess:{init:function(e){e.index=0},isComplete:function(e){if("#"===e.nextCh){var t=e.lineText.match(/#(\w+)/)[1];if("endif"===t){if(e.forward&&0===e.depth)return!0;e.depth++}else if("if"===t){if(!e.forward&&0===e.depth)return!0;e.depth--}if("else"===t&&0===e.depth)return!0}return!1}}};w("pcre",!0,"boolean"),Fe.prototype={getQuery:function(){return Tt.query},setQuery:function(e){Tt.query=e},getOverlay:function(){return this.searchOverlay},setOverlay:function(e){this.searchOverlay=e},isReversed:function(){return Tt.isReversed},setReversed:function(e){Tt.isReversed=e},getScrollbarAnnotate:function(){return this.annotate},setScrollbarAnnotate:function(e){this.annotate=e}};var Rt={"\\n":"\n","\\r":"\r","\\t":"\t"},Bt={"\\/":"/","\\\\":"\\","\\n":"\n","\\r":"\r","\\t":"\t"},$t="(Javascript regexp)",Ut=function(){this.buildCommandMap_()};Ut.prototype={processCommand:function(e,t,n){var r=this;e.operation(function(){e.curOp.isVimOp=!0,r._processCommand(e,t,n)})},_processCommand:function(t,n,r){var i=t.state.vim,o=Tt.registerController.getRegister(":"),a=o.toString();i.visualMode&&de(t);var s=new e.StringStream(n);o.setText(n);var u=r||{};u.input=n;try{this.parseInput_(t,s,u)}catch(e){throw ze(t,e),e}var c,l;if(u.commandName){if(c=this.matchCommand_(u.commandName)){if(l=c.name,c.excludeFromCommandHistory&&o.setText(a),this.parseCommandArgs_(s,u,c),"exToKey"==c.type){for(var p=0;p0;t--){var n=e.substring(0,t);if(this.commandMap_[n]){var r=this.commandMap_[n];if(0===r.name.indexOf(e))return r}}return null},buildCommandMap_:function(){this.commandMap_={};for(var e=0;e
    ";if(n){var o;n=n.join("");for(var a=0;a"}}else for(var o in r){var u=r[o].toString();u.length&&(i+='"'+o+" "+u+"
    ")}ze(e,i)},sort:function(t,n){function i(e,t){if(a){var n;n=e,e=t,t=n}s&&(e=e.toLowerCase(),t=t.toLowerCase());var r=c&&y.exec(e),i=c&&y.exec(t);return r?(r=parseInt((r[1]+r[2]).toLowerCase(),v),i=parseInt((i[1]+i[2]).toLowerCase(),v),r-i):e1)return"Invalid arguments";c=i&&"decimal"||o&&"hex"||p&&"octal"}r[2]&&(l=new RegExp(r[2].substr(1,r[2].length-2),s?"i":""))}}();if(p)return void ze(t,p+": "+n.argString);var f=n.line||t.firstLine(),d=n.lineEnd||n.line||t.lastLine();if(f!=d){var h=r(f,0),m=r(d,ee(t,d)),g=t.getRange(h,m).split("\n"),y=l||("decimal"==c?/(-?)([\d]+)/:"hex"==c?/(-?)(?:0x)?([0-9a-f]+)/i:"octal"==c?/([0-7]+)/:null),v="decimal"==c?10:"hex"==c?16:"octal"==c?8:null,b=[],x=[];if(c||l)for(var C=0;C")}if(!r)return void ze(e,l);var f=0,d=function(){if(f=l)return void ze(t,"Invalid argument: "+n.argString.substring(o));for(var p=0;p<=l-c;p++){var f=String.fromCharCode(c+p);delete r.marks[f]}}else delete r.marks[a]}}},Gt=new Ut;return e.keyMap.vim={attach:s,detach:a,call:f},w("insertModeEscKeysTimeout",200,"number"),e.keyMap["vim-insert"]={fallthrough:["default"],attach:s,detach:a,call:f},e.keyMap["vim-replace"]={Backspace:"goCharLeft",fallthrough:["vim-insert"],attach:s,detach:a,call:f},T(),Ft}()})},function(e,t,n){"use strict";var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=n(50);i.default.registerHelper("hint","graphql",function(e,t){var n=t.schema;if(n){var r=e.getCursor(),a=e.getTokenAt(r),s=(0,o.getAutocompleteSuggestions)(n,e.getValue(),r,a),u=null!==a.type&&/"|\w/.test(a.string[0])?a.start:a.end,c={list:s.map(function(e){return{text:e.label,type:String(e.detail),description:e.documentation,isDeprecated:e.isDeprecated,deprecationReason:e.deprecationReason}}),from:{line:r.line,column:u},to:{line:r.line,column:a.end}};return c&&c.list&&c.list.length>0&&(c.from=i.default.Pos(c.from.line,c.from.column),c.to=i.default.Pos(c.to.line,c.to.column),i.default.signal(e,"hasCompletion",e,c,a)),c}})},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(t){var n=this;r(this,e),this.getStartOfToken=function(){return n._start},this.getCurrentPosition=function(){return n._pos},this.eol=function(){return n._sourceText.length===n._pos},this.sol=function(){return 0===n._pos},this.peek=function(){return n._sourceText.charAt(n._pos)?n._sourceText.charAt(n._pos):null},this.next=function(){var e=n._sourceText.charAt(n._pos);return n._pos++,e},this.eat=function(e){if(n._testNextCharacter(e))return n._start=n._pos,n._pos++,n._sourceText.charAt(n._pos-1)},this.eatWhile=function(e){var t=n._testNextCharacter(e),r=!1;for(t&&(r=t,n._start=n._pos);t;)n._pos++,t=n._testNextCharacter(e),r=!0;return r},this.eatSpace=function(){return n.eatWhile(/[\s\u00a0]/)},this.skipToEnd=function(){n._pos=n._sourceText.length},this.skipTo=function(e){n._pos=e},this.match=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],r=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=null,o=null;if("string"===typeof e){o=new RegExp(e,r?"i":"g").test(n._sourceText.substr(n._pos,e.length)),i=e}else e instanceof RegExp&&(o=n._sourceText.slice(n._pos).match(e),i=o&&o[0]);return!(null==o||!("string"===typeof e||o instanceof Array&&n._sourceText.startsWith(o[0],n._pos)))&&(t&&(n._start=n._pos,i&&i.length&&(n._pos+=i.length)),o)},this.backUp=function(e){n._pos-=e},this.column=function(){return n._pos},this.indentation=function(){var e=n._sourceText.match(/\s*/),t=0;if(e&&0===e.length)for(var r=e[0],i=0;r.length>i;)9===r.charCodeAt(i)?t+=2:t++,i++;return t},this.current=function(){return n._sourceText.slice(n._start,n._pos)},this._start=0,this._pos=0,this._sourceText=t}return e.prototype._testNextCharacter=function(e){var t=this._sourceText.charAt(this._pos);return"string"===typeof e?t===e:e instanceof RegExp?e.test(t):e(t)},e}();t.default=i},function(e,t,n){"use strict";function r(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{eatWhitespace:function(e){return e.eatWhile(d.isIgnored)},lexRules:d.LexRules,parseRules:d.ParseRules,editorConfig:{}};return{startState:function(){var t={level:0,step:0,name:null,kind:null,type:null,rule:null,needsSeperator:!1,prevState:null};return a(e.parseRules,t,"Document"),t},token:function(t,n){return i(t,n,e)}}}function i(e,t,n){var r=n.lexRules,i=n.parseRules,c=n.eatWhitespace,f=n.editorConfig;if(t.rule&&0===t.rule.length?s(t):t.needsAdvance&&(t.needsAdvance=!1,u(t,!0)),e.sol()){var d=f&&f.tabSize||2;t.indentLevel=Math.floor(e.indentation()/d)}if(c(e))return"ws";var m=p(r,e);if(!m)return e.match(/\S+/),a(h,t,"Invalid"),"invalidchar";if("Comment"===m.kind)return a(h,t,"Comment"),"comment";var g=o({},t);if("Punctuation"===m.kind)if(/^[{([]/.test(m.value))t.levels=(t.levels||[]).concat(t.indentLevel+1);else if(/^[})\]]/.test(m.value)){var y=t.levels=(t.levels||[]).slice(0,-1);t.indentLevel&&y.length>0&&y[y.length-1]0?d.filter(function(e){return-1===e.message.indexOf("Unknown directive")||!(e.nodes&&e.nodes[0]&&e.nodes[0].name&&"arguments"===e.nodes[0].name.value||e.nodes&&e.nodes[0]&&e.nodes[0].name&&e.nodes[0].name.value&&"argumentDefinitions"===e.nodes[0].name.value)}):[]}Object.defineProperty(t,"__esModule",{value:!0}),t.validateWithCustomRules=r;var i=n(7)},function(e,t,n){e.exports=n.p+"static/media/GraphQLLanguageService.js.fa07138d.flow"},function(e,t,n){e.exports=n.p+"static/media/autocompleteUtils.js.4ce7ba19.flow"},function(e,t,n){e.exports=n.p+"static/media/getAutocompleteSuggestions.js.5f735c7b.flow"},function(e,t,n){e.exports=n.p+"static/media/getDefinition.js.0c48668e.flow"},function(e,t,n){e.exports=n.p+"static/media/getDiagnostics.js.889c0b27.flow"},function(e,t,n){e.exports=n.p+"static/media/getOutline.js.458a3518.flow"},function(e,t,n){e.exports=n.p+"static/media/index.js.641230f5.flow"},function(e,t,n){"use strict";var r=n(2),i=function(e){return e&&e.__esModule?e:{default:e}}(r),o=n(50),a=["error","warning","information","hint"],s={"GraphQL: Validation":"validation","GraphQL: Deprecation":"deprecation","GraphQL: Syntax":"syntax"};i.default.registerHelper("lint","graphql",function(e,t){var n=t.schema;return(0,o.getDiagnostics)(e,n).map(function(e){return{message:e.message,severity:a[e.severity-1],type:s[e.source],from:i.default.Pos(e.range.start.line,e.range.start.character),to:i.default.Pos(e.range.end.line,e.range.end.character)}})})},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){o(e,t,n),u(e,t,n,t.type)}function o(e,t,n){var r=t.fieldDef.name;"__"!==r.slice(0,2)&&(l(e,t,n,t.parentType),d(e,".")),d(e,r,"field-name",n,(0,b.getFieldReference)(t))}function a(e,t,n){d(e,"@"+t.directiveDef.name,"directive-name",n,(0,b.getDirectiveReference)(t))}function s(e,t,n){t.directiveDef?a(e,t,n):t.fieldDef&&o(e,t,n);var r=t.argDef.name;d(e,"("),d(e,r,"arg-name",n,(0,b.getArgumentReference)(t)),u(e,t,n,t.inputType),d(e,")")}function u(e,t,n,r){d(e,": "),l(e,t,n,r)}function c(e,t,n){var r=t.enumValue.name;l(e,t,n,t.inputType),d(e,"."),d(e,r,"enum-value",n,(0,b.getEnumValueReference)(t))}function l(e,t,n,r){r instanceof h.GraphQLNonNull?(l(e,t,n,r.ofType),d(e,"!")):r instanceof h.GraphQLList?(d(e,"["),l(e,t,n,r.ofType),d(e,"]")):d(e,r.name,"type-name",n,(0,b.getTypeReference)(t,r))}function p(e,t,n){var r=n.description;if(r){var i=document.createElement("div");i.className="info-description",t.renderDescription?i.innerHTML=t.renderDescription(r):i.appendChild(document.createTextNode(r)),e.appendChild(i)}f(e,t,n)}function f(e,t,n){var r=n.deprecationReason;if(r){var i=document.createElement("div");i.className="info-deprecation",t.renderDescription?i.innerHTML=t.renderDescription(r):i.appendChild(document.createTextNode(r));var o=document.createElement("span");o.className="info-deprecation-label",o.appendChild(document.createTextNode("Deprecated: ")),i.insertBefore(o,i.firstChild),e.appendChild(i)}}function d(e,t,n,r,i){if(n){var o=r.onClick,a=document.createElement(o?"a":"span");o&&(a.href="javascript:void 0",a.addEventListener("click",function(e){o(i,e)})),a.className=n,a.appendChild(document.createTextNode(t)),e.appendChild(a)}else e.appendChild(document.createTextNode(t))}var h=n(7),m=n(2),g=r(m),y=n(280),v=r(y),b=n(282);n(609),g.default.registerHelper("info","graphql",function(e,t){if(t.schema&&e.state){var n=e.state,r=n.kind,o=n.step,u=(0,v.default)(t.schema,e.state);if("Field"===r&&0===o&&u.fieldDef||"AliasedField"===r&&2===o&&u.fieldDef){var f=document.createElement("div");return i(f,u,t),p(f,t,u.fieldDef),f}if("Directive"===r&&1===o&&u.directiveDef){var d=document.createElement("div");return a(d,u,t),p(d,t,u.directiveDef),d}if("Argument"===r&&0===o&&u.argDef){var h=document.createElement("div");return s(h,u,t),p(h,t,u.argDef),h}if("EnumValue"===r&&u.enumValue&&u.enumValue.description){var m=document.createElement("div");return c(m,u,t),p(m,t,u.enumValue),m}if("NamedType"===r&&u.type&&u.type.description){var g=document.createElement("div");return l(g,u,t,u.type),p(g,t,u.type),g}}})},function(e,t,n){"use strict";function r(e){return{options:e instanceof Function?{render:e}:!0===e?{}:e}}function i(e){var t=e.state.info.options;return t&&t.hoverTime||500}function o(e,t){var n=e.state.info,r=t.target||t.srcElement;if("SPAN"===r.nodeName&&void 0===n.hoverTimeout){var o=r.getBoundingClientRect(),s=i(e);n.hoverTimeout=setTimeout(p,s);var u=function(){clearTimeout(n.hoverTimeout),n.hoverTimeout=setTimeout(p,s)},l=function t(){c.default.off(document,"mousemove",u),c.default.off(e.getWrapperElement(),"mouseout",t),clearTimeout(n.hoverTimeout),n.hoverTimeout=void 0},p=function(){c.default.off(document,"mousemove",u),c.default.off(e.getWrapperElement(),"mouseout",l),n.hoverTimeout=void 0,a(e,o)};c.default.on(document,"mousemove",u),c.default.on(e.getWrapperElement(),"mouseout",l)}}function a(e,t){var n=e.coordsChar({left:(t.left+t.right)/2,top:(t.top+t.bottom)/2}),r=e.state.info,i=r.options,o=i.render||e.getHelper(n,"info");if(o){var a=e.getTokenAt(n,!0);if(a){var u=o(a,i,e,n);u&&s(e,t,u)}}}function s(e,t,n){var r=document.createElement("div");r.className="CodeMirror-info",r.appendChild(n),document.body.appendChild(r);var i=r.getBoundingClientRect(),o=r.currentStyle||window.getComputedStyle(r),a=i.right-i.left+parseFloat(o.marginLeft)+parseFloat(o.marginRight),s=i.bottom-i.top+parseFloat(o.marginTop)+parseFloat(o.marginBottom),u=t.bottom;s>window.innerHeight-t.bottom-15&&t.top>window.innerHeight-t.bottom&&(u=t.top-s),u<0&&(u=t.bottom);var l=Math.max(0,window.innerWidth-a-15);l>t.left&&(l=t.left),r.style.opacity=1,r.style.top=u+"px",r.style.left=l+"px";var p=void 0,f=function(){clearTimeout(p)},d=function(){clearTimeout(p),p=setTimeout(h,200)},h=function(){c.default.off(r,"mouseover",f),c.default.off(r,"mouseout",d),c.default.off(e.getWrapperElement(),"mouseout",d),r.style.opacity?(r.style.opacity=0,setTimeout(function(){r.parentNode&&r.parentNode.removeChild(r)},600)):r.parentNode&&r.parentNode.removeChild(r)};c.default.on(r,"mouseover",f),c.default.on(r,"mouseout",d),c.default.on(e.getWrapperElement(),"mouseout",d)}var u=n(2),c=function(e){return e&&e.__esModule?e:{default:e}}(u);c.default.defineOption("info",!1,function(e,t,n){if(n&&n!==c.default.Init){var i=e.state.info.onMouseOver;c.default.off(e.getWrapperElement(),"mouseover",i),clearTimeout(e.state.info.hoverTimeout),delete e.state.info}if(t){var a=e.state.info=r(t);a.onMouseOver=o.bind(null,e),c.default.on(e.getWrapperElement(),"mouseover",a.onMouseOver)}})},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}var i=n(2),o=r(i),a=n(280),s=r(a),u=n(282);n(611),o.default.registerHelper("jump","graphql",function(e,t){if(t.schema&&t.onClick&&e.state){var n=e.state,r=n.kind,i=n.step,o=(0,s.default)(t.schema,n);return"Field"===r&&0===i&&o.fieldDef||"AliasedField"===r&&2===i&&o.fieldDef?(0,u.getFieldReference)(o):"Directive"===r&&1===i&&o.directiveDef?(0,u.getDirectiveReference)(o):"Argument"===r&&0===i&&o.argDef?(0,u.getArgumentReference)(o):"EnumValue"===r&&o.enumValue?(0,u.getEnumValueReference)(o):"NamedType"===r&&o.type?(0,u.getTypeReference)(o):void 0}})},function(e,t,n){"use strict";function r(e,t){var n=t.target||t.srcElement;if("SPAN"===n.nodeName){var r=n.getBoundingClientRect(),i={left:(r.left+r.right)/2,top:(r.top+r.bottom)/2};e.state.jump.cursor=i,e.state.jump.isHoldingModifier&&s(e)}}function i(e){if(!e.state.jump.isHoldingModifier&&e.state.jump.cursor)return void(e.state.jump.cursor=null);e.state.jump.isHoldingModifier&&e.state.jump.marker&&u(e)}function o(e,t){if(!e.state.jump.isHoldingModifier&&a(t.key)){e.state.jump.isHoldingModifier=!0,e.state.jump.cursor&&s(e);var n=function n(o){o.code===t.code&&(e.state.jump.isHoldingModifier=!1,e.state.jump.marker&&u(e),l.default.off(document,"keyup",n),l.default.off(document,"click",r),e.off("mousedown",i))},r=function(t){var n=e.state.jump.destination;n&&e.state.jump.options.onClick(n,t)},i=function(t,n){e.state.jump.destination&&(n.codemirrorIgnore=!0)};l.default.on(document,"keyup",n),l.default.on(document,"click",r),e.on("mousedown",i)}}function a(e){return e===(p?"Meta":"Control")}function s(e){if(!e.state.jump.marker){var t=e.state.jump.cursor,n=e.coordsChar(t),r=e.getTokenAt(n,!0),i=e.state.jump.options,o=i.getDestination||e.getHelper(n,"jump");if(o){var a=o(r,i,e);if(a){var s=e.markText({line:n.line,ch:r.start},{line:n.line,ch:r.end},{className:"CodeMirror-jump-token"});e.state.jump.marker=s,e.state.jump.destination=a}}}}function u(e){var t=e.state.jump.marker;e.state.jump.marker=null,e.state.jump.destination=null,t.clear()}var c=n(2),l=function(e){return e&&e.__esModule?e:{default:e}}(c);l.default.defineOption("jump",!1,function(e,t,n){if(n&&n!==l.default.Init){var a=e.state.jump.onMouseOver;l.default.off(e.getWrapperElement(),"mouseover",a);var s=e.state.jump.onMouseOut;l.default.off(e.getWrapperElement(),"mouseout",s),l.default.off(document,"keydown",e.state.jump.onKeyDown),delete e.state.jump}if(t){var u=e.state.jump={options:t,onMouseOver:r.bind(null,e),onMouseOut:i.bind(null,e),onKeyDown:o.bind(null,e)};l.default.on(e.getWrapperElement(),"mouseover",u.onMouseOver),l.default.on(e.getWrapperElement(),"mouseout",u.onMouseOut),l.default.on(document,"keydown",u.onKeyDown)}});var p=navigator&&-1!==navigator.appVersion.indexOf("Mac")},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var i=function(){function e(e,t){for(var n=0;n=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t}function s(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0}),t.CopyToClipboard=void 0;var u=Object.assign||function(e){for(var t=1;t=65&&r<=90||!t.shiftKey&&r>=48&&r<=57||t.shiftKey&&189===r||t.shiftKey&&222===r)&&n.editor.execCommand("autocomplete")},n._onEdit=function(){n.ignoreChangeEvent||(n.cachedValue=n.editor.getValue(),n.props.onChange(n.cachedValue))},n._onHasCompletion=function(e,t){a.default(e,t,n.props.onHintInformationRender)},n.cachedValue=t.value||"",n.props.getRef&&n.props.getRef(n),n}return r(t,e),t.prototype.componentDidMount=function(){var e=this,t=n(2);n(137),n(69),n(138),n(70),n(89),n(139),n(38),n(90),n(39),n(91),n(286),n(287),n(288),this.editor=t(this._node,{value:this.props.value||"",lineNumbers:!0,tabSize:2,mode:"graphql-variables",theme:"graphiql",keyMap:"sublime",autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!1,foldGutter:{minFoldSize:4},lint:{variableToType:this.props.variableToType?this.props.variableToType.toJS():void 0},hintOptions:{variableToType:this.props.variableToType?this.props.variableToType.toJS():void 0,closeOnUnfocus:!1,completeSingle:!1},gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:{"Cmd-Space":function(){return e.editor.showHint({completeSingle:!1})},"Ctrl-Space":function(){return e.editor.showHint({completeSingle:!1})},"Alt-Space":function(){return e.editor.showHint({completeSingle:!1})},"Shift-Space":function(){return e.editor.showHint({completeSingle:!1})},"Cmd-Enter":function(){e.props.onRunQuery&&e.props.onRunQuery()},"Ctrl-Enter":function(){e.props.onRunQuery&&e.props.onRunQuery()},"Shift-Ctrl-P":function(){e.props.prettifyQuery&&e.props.prettifyQuery()},"Cmd-F":"findPersistent","Ctrl-F":"findPersistent","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight"}}),this.editor.on("change",this._onEdit),this.editor.on("keyup",this._onKeyUp),this.editor.on("hasCompletion",this._onHasCompletion)},t.prototype.componentDidUpdate=function(e){var t=n(2);this.ignoreChangeEvent=!0,this.props.variableToType!==e.variableToType&&(this.editor.options.lint.variableToType=this.props.variableToType?this.props.variableToType.toJS():void 0,this.editor.options.hintOptions.variableToType=this.props.variableToType?this.props.variableToType.toJS():void 0,t.signal(this.editor,"change",this.editor)),this.props.value!==e.value&&this.props.value!==this.cachedValue&&(this.cachedValue=this.props.value,this.editor.setValue(this.props.value)),this.ignoreChangeEvent=!1},t.prototype.componentWillUnmount=function(){this.editor.off("change",this._onEdit),this.editor.off("keyup",this._onKeyUp),this.editor.off("hasCompletion",this._onHasCompletion),this.editor=null},t.prototype.render=function(){var e=this;return o.createElement(g,{ref:function(t){e._node=t}})},t.prototype.getCodeMirror=function(){return this.editor},t.prototype.getClientHeight=function(){return this._node&&this._node.clientHeight},t}(o.PureComponent),d=l.createStructuredSelector({value:c.getVariables,variableToType:c.getVariableToType});t.VariableEditorComponent=s.connect(d,{onChange:u.editVariables})(f);var h=l.createStructuredSelector({value:c.getHeaders});t.HeadersEditorComponent=s.connect(h,{onChange:u.editHeaders})(f);var m,g=p.styled.div(m||(m=i(["\n flex: 1;\n height: 100%;\n position: relative;\n"],["\n flex: 1;\n height: 100%;\n position: relative;\n"])))},function(e,t,n){"use strict";function r(e,t,n){var r=i(n,a(t.string));if(r){var o=null!==t.type&&/"|\w/.test(t.string[0])?t.start:t.end;return{list:r,from:{line:e.line,column:o},to:{line:e.line,column:t.end}}}}function i(e,t){return t?o(o(e.map(function(e){return{proximity:s(a(e.text),t),entry:e}}),function(e){return e.proximity<=2}),function(e){return!e.entry.isDeprecated}).sort(function(e,t){return(e.entry.isDeprecated?1:0)-(t.entry.isDeprecated?1:0)||e.proximity-t.proximity||e.entry.text.length-t.entry.text.length}).map(function(e){return e.entry}):o(e,function(e){return!e.isDeprecated})}function o(e,t){var n=e.filter(t);return 0===n.length?e:n}function a(e){return e.toLowerCase().replace(/\W/g,"")}function s(e,t){var n=u(t,e);return e.length>t.length&&(n-=e.length-t.length-1,n+=0===e.indexOf(t)?0:.5),n}function u(e,t){var n=void 0,r=void 0,i=[],o=e.length,a=t.length;for(n=0;n<=o;n++)i[n]=[n];for(r=1;r<=a;r++)i[0][r]=r;for(n=1;n<=o;n++)for(r=1;r<=a;r++){var s=e[n-1]===t[r-1]?0:1;i[n][r]=Math.min(i[n-1][r]+1,i[n][r-1]+1,i[n-1][r-1]+s),n>1&&r>1&&e[n-1]===t[r-2]&&e[n-2]===t[r-1]&&(i[n][r]=Math.min(i[n][r],i[n-2][r-2]+s))}return i[o][a]}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";function r(e){v=e,b=e.length,x=C=E=-1,f(),d();var t=i();return c("EOF"),t}function i(){var e=x,t=[];if(c("{"),!p("}")){do{t.push(o())}while(p(","));c("}")}return{kind:"Object",start:e,end:E,members:t}}function o(){var e=x,t="String"===w?u():null;c("String"),c(":");var n=s();return{kind:"Member",start:e,end:E,key:t,value:n}}function a(){var e=x,t=[];if(c("["),!p("]")){do{t.push(s())}while(p(","));c("]")}return{kind:"Array",start:e,end:E,values:t}}function s(){switch(w){case"[":return a();case"{":return i();case"String":case"Number":case"Boolean":case"Null":var e=u();return d(),e}return c("Value")}function u(){return{kind:w,start:x,end:C,value:JSON.parse(v.slice(x,C))}}function c(e){if(w===e)return void d();var t=void 0;if("EOF"===w)t="[end of file]";else if(C-x>1)t="`"+v.slice(x,C)+"`";else{var n=v.slice(x).match(/^.+?\b/);t="`"+(n?n[0]:v[x])+"`"}throw l("Expected "+e+" but found "+t+".")}function l(e){return{message:e,start:x,end:C}}function p(e){if(w===e)return d(),!0}function f(){C31;)if(92===D)switch(f(),D){case 34:case 47:case 92:case 98:case 102:case 110:case 114:case 116:f();break;case 117:f(),m(),m(),m(),m();break;default:throw l("Bad character escape sequence.")}else{if(C===b)throw l("Unterminated string.");f()}if(34===D)return void f();throw l("Unterminated string.")}function m(){if(D>=48&&D<=57||D>=65&&D<=70||D>=97&&D<=102)return f();throw l("Expected hexadecimal digit.")}function g(){45===D&&f(),48===D?f():y(),46===D&&(f(),y()),69!==D&&101!==D||(f(),43!==D&&45!==D||f(),y())}function y(){if(D<48||D>57)throw l("Expected decimal digit.");do{f()}while(D>=48&&D<=57)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var v=void 0,b=void 0,x=void 0,C=void 0,E=void 0,D=void 0,w=void 0},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(629),a=n(630),s=n(9),u=n(8),c=n(12),l=n(1),p=n(85),f=new p.ResponseRecord({date:"",time:new Date,resultID:"default-id"}),d=function(e){var t=e.setRef,n=e.responses,r=n.get(0)||f,s=n.size>1;return i.createElement(x,{ref:t,isSubscription:s},n.size<=1?i.createElement(C,{key:"first",isSubscription:s},n.size>1&&r.time&&i.createElement(E,null,i.createElement(D,null,o.default(r.time))),i.createElement(w,{isSubscription:s},i.createElement(a.ResultViewer,{value:r.date,isSubscription:s}))):n.map(function(e){return i.createElement(C,{key:e.resultID||String(e.time),isSubscription:s},n.size>1&&e.time&&i.createElement(E,null,i.createElement(D,null,o.default(e.time))),i.createElement(w,{isSubscription:n.size>1},i.createElement(a.ResultViewer,{value:e.date,isSubscription:s})))}))},h=u.createStructuredSelector({responses:c.getResponses});t.default=s.connect(h)(d);var m,g,y,v,b,x=l.styled("div")(m||(m=r(["\n flex: 1;\n height: ",";\n position: relative;\n overflow: ",";\n max-height: none !important;\n\n .cm-string {\n color: rgb(41, 185, 115);\n }\n\n .cm-def {\n color: rgb(241, 143, 1);\n }\n\n .cm-property {\n color: rgb(51, 147, 220);\n }\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n .CodeMirror {\n background: ",";\n }\n .CodeMirror-gutters {\n cursor: col-resize;\n }\n .CodeMirror-foldgutter,\n .CodeMirror-foldgutter-open:after,\n .CodeMirror-foldgutter-folded:after {\n padding-left: 3px;\n }\n"],["\n flex: 1;\n height: ",";\n position: relative;\n overflow: ",";\n max-height: none !important;\n\n .cm-string {\n color: rgb(41, 185, 115);\n }\n\n .cm-def {\n color: rgb(241, 143, 1);\n }\n\n .cm-property {\n color: rgb(51, 147, 220);\n }\n\n &::-webkit-scrollbar {\n display: none;\n }\n\n .CodeMirror {\n background: ",";\n }\n .CodeMirror-gutters {\n cursor: col-resize;\n }\n .CodeMirror-foldgutter,\n .CodeMirror-foldgutter-open:after,\n .CodeMirror-foldgutter-folded:after {\n padding-left: 3px;\n }\n"])),function(e){return e.isSubscription?"auto":"100%"},function(e){return e.isSubscription?"auto":"visible"},function(e){return e.theme.editorColours.resultBackground}),C=l.styled("div")(g||(g=r(["\n position: relative;\n display: flex;\n flex: 1;\n height: ",";\n flex-direction: column;\n &:not(:first-child):last-of-type {\n margin-bottom: 48px;\n }\n"],["\n position: relative;\n display: flex;\n flex: 1;\n height: ",";\n flex-direction: column;\n &:not(:first-child):last-of-type {\n margin-bottom: 48px;\n }\n"])),function(e){return e.isSubscription?"auto":"100%"}),E=l.styled.div(y||(y=r(["\n position: relative;\n height: 17px;\n margin-top: 12px;\n margin-bottom: 4px;\n &:before {\n position: absolute;\n width: 100%;\n content: '';\n top: 9px;\n left: 95px;\n border-top: 1px solid\n ",";\n }\n"],["\n position: relative;\n height: 17px;\n margin-top: 12px;\n margin-bottom: 4px;\n &:before {\n position: absolute;\n width: 100%;\n content: '';\n top: 9px;\n left: 95px;\n border-top: 1px solid\n ",";\n }\n"])),function(e){return e.theme.editorColours.subscriptionTimeBoaderTop}),D=l.styled.div(v||(v=r(["\n font-size: 12px;\n color: ",";\n padding-left: 15px;\n"],["\n font-size: 12px;\n color: ",";\n padding-left: 15px;\n"])),function(e){return e.theme.editorColours.subscriptionTimeText}),w=l.styled("div")(b||(b=r(["\n display: flex;\n flex: 1;\n height: ",";\n position: ",";\n"],["\n display: flex;\n flex: 1;\n height: ",";\n position: ",";\n"])),function(e){return e.isSubscription?"auto":"100%"},function(e){return e.isSubscription?"relative":"static"})},function(e,t,n){"use strict";function r(e){var t=new Date,n=Math.abs(e.getTime()-t.getTime()),r=Math.floor(n/864e5),i=Math.floor(n%864e5/36e5),o=Math.round(n%864e5%36e5/6e4);if(r>0)return r+" days ago";if(i>0)return i+" h ago";if(o>0)return o+" min ago";var a=Math.round(n/1e3);return a+" sec"+(a>1?"s":"")+" ago"}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(1),s=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.setRef=function(e){t.node=e},t}return r(t,e),t.prototype.componentDidMount=function(){var e=n(2);n(89),n(70),n(39),n(274),n(38),n(90),n(91),n(631);var t=[];this.props.hideGutters||t.push("CodeMirror-foldgutter");var r={};this.props.hideGutters||(r={minFoldSize:4});var i=this.props.value||"";this.viewer=e(this.node,{lineWrapping:!0,value:i,readOnly:!0,theme:"graphiql",mode:"graphql-results",keyMap:"sublime",foldGutter:r,gutters:t,extraKeys:{"Cmd-F":"findPersistent","Ctrl-F":"findPersistent","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight"}})},t.prototype.shouldComponentUpdate=function(e){return this.props.value!==e.value},t.prototype.componentDidUpdate=function(){var e=this.props.value||"";this.viewer.setValue(e)},t.prototype.componentWillUnmount=function(){this.viewer=null},t.prototype.render=function(){return o.createElement(c,{ref:this.setRef,isSubscription:this.props.isSubscription})},t.prototype.getCodeMirror=function(){return this.viewer},t.prototype.getClientHeight=function(){return this.node&&this.node.clientHeight},t}(o.Component);t.ResultViewer=s;var u,c=a.styled("div")(u||(u=i(["\n position: relative;\n display: flex;\n flex: 1;\n height: ",";\n .CodeMirror {\n height: ",";\n position: ",";\n box-sizing: border-box;\n background: none;\n padding-left: 38px;\n }\n .CodeMirror-cursor {\n display: none !important;\n }\n .CodeMirror-scroll {\n overflow: auto !important;\n max-width: 50vw;\n margin-right: 10px;\n }\n .cm-string {\n color: "," !important;\n }\n"],["\n position: relative;\n display: flex;\n flex: 1;\n height: ",";\n .CodeMirror {\n height: ",";\n position: ",";\n box-sizing: border-box;\n background: none;\n padding-left: 38px;\n }\n .CodeMirror-cursor {\n display: none !important;\n }\n .CodeMirror-scroll {\n overflow: auto !important;\n max-width: 50vw;\n margin-right: 10px;\n }\n .cm-string {\n color: "," !important;\n }\n"])),function(e){return e.isSubscription?"auto":"100%"},function(e){return e.isSubscription?"auto":"100%"},function(e){return e.isSubscription?"relative":"absolute%"},function(e){return e.theme.editorColours.property})},function(e,t,n){"use strict";function r(e,t){var n=e.levels;return(n&&0!==n.length?n[n.length-1]-(this.electricInput.test(t)?1:0):e.indentLevel)*this.config.indentUnit}var i=n(2),o=function(e){return e&&e.__esModule?e:{default:e}}(i),a=n(71);o.default.defineMode("graphql-results",function(e){var t=(0,a.onlineParser)({eatWhitespace:function(e){return e.eatSpace()},lexRules:s,parseRules:u,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:r,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}});var s={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},u={Document:[(0,a.p)("{"),(0,a.list)("Entry",(0,a.p)(",")),(0,a.p)("}")],Entry:[(0,a.t)("String","def"),(0,a.p)(":"),"Value"],Value:function(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,a.t)("Number","number")],StringValue:[(0,a.t)("String","string")],BooleanValue:[(0,a.t)("Keyword","builtin")],NullValue:[(0,a.t)("Keyword","keyword")],ListValue:[(0,a.p)("["),(0,a.list)("Value",(0,a.p)(",")),(0,a.p)("]")],ObjectValue:[(0,a.p)("{"),(0,a.list)("ObjectField",(0,a.p)(",")),(0,a.p)("}")],ObjectField:[(0,a.t)("String","property"),(0,a.p)(":"),"Value"]}},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e},i=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(633),s=n(87),u=n(8),c=n(12),l=n(9),p=s.default.div(y||(y=r(["\n padding-top: 6px;\n padding-left: 25px;\n padding-right: 25px;\n color: ",";\n overflow: auto;\n position: relative;\n height: 100%;\n"],["\n padding-top: 6px;\n padding-left: 25px;\n padding-right: 25px;\n color: ",";\n overflow: auto;\n position: relative;\n height: 100%;\n"])),function(e){return e.theme.editorColours.text}),f=s.default.div(v||(v=r(["\n font-size: 14px;\n"],["\n font-size: 14px;\n"]))),d=s.default.div(b||(b=r(["\n font-size: 14px;\n color: rgba(241, 143, 1, 1);\n"],["\n font-size: 14px;\n color: rgba(241, 143, 1, 1);\n"]))),h=s.default.div(x||(x=r(["\n padding-left: 100px;\n padding-bottom: 100px;\n padding-top: 16px;\n position: absolute;\n overflow: auto;\n top: 0;\n left: 0;\n width: calc(100% + 100px);\n height: calc(100% + 116px);\n"],["\n padding-left: 100px;\n padding-bottom: 100px;\n padding-top: 16px;\n position: absolute;\n overflow: auto;\n top: 0;\n left: 0;\n width: calc(100% + 100px);\n height: calc(100% + 116px);\n"]))),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return i(t,e),t.prototype.render=function(){var e=this.props,t=e.tracing,n=e.tracingSupported,r=e.startTime,i=e.endTime,s=e.open,u=t&&r?Math.abs(new Date(t.startTime).getTime()-r.getTime()):0,c=t&&i?Math.abs(i.getTime()-new Date(t.endTime).getTime()):0,l=1e6*u;return o.createElement(p,null,t&&s?o.createElement(h,null,o.createElement(a.default,{path:["Request"],startOffset:0,duration:l}),t.execution.resolvers.map(function(e){return o.createElement(a.default,{key:e.path.join("."),path:e.path,startOffset:e.startOffset+l,duration:e.duration})}),o.createElement(a.default,{path:["Response"],startOffset:t.duration+l,duration:1e6*c})):n?o.createElement(f,null,this.props.queryRunning?"Running query ...":"Please re-run the query to show tracing results."):o.createElement(d,null,"This GraphQL server doesn\u2019t support tracing. See the following page for instructions:",o.createElement("br",null),"https://github.com/apollographql/apollo-tracing"))},t}(o.PureComponent),g=u.createStructuredSelector({tracing:c.getTracing,startTime:c.getCurrentQueryStartTime,endTime:c.getCurrentQueryEndTime,tracingSupported:c.getTracingSupported,queryRunning:c.getQueryRunning});t.default=l.connect(g)(m);var y,v,b,x},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e},i=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(87),s=a.default.div(d||(d=r(["\n position: relative;\n font-size: 12px;\n display: table;\n padding-right: 25px;\n\n color: ",";\n"],["\n position: relative;\n font-size: 12px;\n display: table;\n padding-right: 25px;\n\n color: ",";\n"])),function(e){return e.theme.editorColours.text}),u=a.default.span(h||(h=r(["\n display: inline-block;\n position: relative;\n margin: 0 10px;\n height: 1.5px;\n bottom: 4px;\n\n background: ",";\n"],["\n display: inline-block;\n position: relative;\n margin: 0 10px;\n height: 1.5px;\n bottom: 4px;\n\n background: ",";\n"])),function(e){return e.theme.editorColours.text}),c=a.default.span(m||(m=r(["\n font-size: 10px;\n color: ",";\n"],["\n font-size: 10px;\n color: ",";\n"])),function(e){return e.theme.editorColours.textInactive}),l=a.default.span(g||(g=r(["\n position: absolute;\n left: 0;\n transform: translateX(-100%);\n display: inline-flex;\n align-items: center;\n\n text-align: right;\n"],["\n position: absolute;\n left: 0;\n transform: translateX(-100%);\n display: inline-flex;\n align-items: center;\n\n text-align: right;\n"]))),p=a.default.span(y||(y=r(["\n margin-left: 10px;\n"],["\n margin-left: 10px;\n"]))),f=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.state={collapsed:!1},t}return i(t,e),t.prototype.render=function(){var e=this.props,t=e.path,n=e.startOffset,r=e.duration,i=n/1e6,a=r/1e6;return o.createElement(s,{style:{transform:"translateX("+i+"px)"}},o.createElement(l,null,o.createElement(p,null,t.slice(-2).map(function(e,n){return o.createElement("span",{style:{opacity:n===t.slice(-2).length-1?1:.6},key:e},(n>0?".":"")+e)}))),o.createElement(u,{style:{width:Math.max(a,3)}}),o.createElement(c,null,this.printDuration(r)))},t.prototype.printDuration=function(e){var t=Math.round(e/1e3);if(t>1e3){return Math.round(t/1e3)+" ms"}return t+" \xb5s"},t}(o.Component);t.default=f;var d,h,m,g,y},function(e,t,n){"use strict";function r(e,t,n){var r=[];if(!e)return{insertions:r,result:t};var c=void 0;try{c=(0,u.parse)(t)}catch(e){return{insertions:r,result:t}}var l=n||i,p=new u.TypeInfo(e);return(0,u.visit)(c,{leave:function(e){p.leave(e)},enter:function(e){if(p.enter(e),"Field"===e.kind&&!e.selectionSet){var n=p.getType(),i=o(n,l);if(i){var a=s(t,e.loc.start);r.push({index:e.loc.end,string:" "+(0,u.print)(i).replace(/\n/g,"\n"+a)})}}}}),{insertions:r,result:a(t,r)}}function i(e){if(!e.getFields)return[];var t=e.getFields();if(t.id)return["id"];if(t.edges)return["edges"];if(t.node)return["node"];var n=[];return Object.keys(t).forEach(function(e){(0,u.isLeafType)(t[e].type)&&n.push(e)}),n}function o(e,t){var n=(0,u.getNamedType)(e);if(e&&!(0,u.isLeafType)(e)){var r=t(n);if(Array.isArray(r)&&0!==r.length)return{kind:"SelectionSet",selections:r.map(function(e){var r=n.getFields()[e];return{kind:"Field",name:{kind:"Name",value:e},selectionSet:o(r?r.type:null,t)}})}}}function a(e,t){if(0===t.length)return e;var n="",r=0;return t.forEach(function(t){var i=t.index,o=t.string;n+=e.slice(r,i)+o,r=i}),n+=e.slice(r)}function s(e,t){for(var n=t,r=t;n;){var i=e.charCodeAt(n-1);if(10===i||13===i||8232===i||8233===i)break;n--,9!==i&&11!==i&&12!==i&&32!==i&&160!==i&&(r=n)}return e.substring(n,r)}Object.defineProperty(t,"__esModule",{value:!0}),t.fillLeafs=r;var u=n(7)},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e},o=function(){return o=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0?n.setState({overflowY:!0}):n.setState({overflowY:!1})},n.setRef=function(e){n.node=e},n.state={overflowY:!1},n.cachedValue=e.value||"",n.props.getRef&&n.props.getRef(n),n}return r(i,t),i.prototype.componentDidMount=function(){var t=n(2);n(70),n(273),n(283);var r=[];r.push("CodeMirror-linenumbers"),this.editor=t(this.node,{autofocus:!1,value:c.getSDL(this.props.schema,this.props.settings["schema.disableComments"])||"",lineNumbers:!1,showCursorWhenSelecting:!1,tabSize:1,mode:"graphql",theme:"graphiql",keyMap:"sublime",readOnly:!0,gutters:r}),e.editor=this.editor,this.editor.on("scroll",this.handleScroll),this.editor.refresh()},i.prototype.componentDidUpdate=function(e){var t=n(2);if((this.props.schema&&a.printSchema(this.props.schema))!==(e.schema&&a.printSchema(e.schema))){var r=this.editor.getScrollInfo();this.cachedValue=c.getSDL(this.props.schema,this.props.settings["schema.disableComments"])||"",this.editor.setValue(c.getSDL(this.props.schema,this.props.settings["schema.disableComments"])),this.props.isPollingSchema&&this.editor.scrollTo(r.left,r.top),t.signal(this.editor,"change",this.editor)}this.props.width!==e.width&&this.editor.refresh(),this.props.settings["schema.disableComments"]!==e.settings["schema.disableComments"]&&this.editor.refresh()},i.prototype.componentWillReceiveProps=function(e){this.props.sessionId!==e.sessionId&&this.editor.scrollTo(0,0)},i.prototype.componentWillUnmount=function(){this.editor.off("scroll"),this.editor=null},i.prototype.render=function(){var e=this.state.overflowY;return o.createElement(s.default,null,e&&o.createElement(h,null),o.createElement(d,{ref:this.setRef}))},i.prototype.getCodeMirror=function(){return this.editor},i.prototype.getClientHeight=function(){return this.node&&this.node.clientHeight},i}(o.PureComponent);t.default=l;var p,f,d=u.styled.div(p||(p=i(["\n flex: 1;\n height: auto;\n overflow-x: hidden;\n overflow-y: scroll;\n .CodeMirror {\n background: ",";\n padding-left: 20px;\n }\n"],["\n flex: 1;\n height: auto;\n overflow-x: hidden;\n overflow-y: scroll;\n .CodeMirror {\n background: ",";\n padding-left: 20px;\n }\n"])),function(e){return"dark"===e.theme.mode?e.theme.editorColours.editorBackground:"white"}),h=u.styled.div(f||(f=i(["\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n box-shadow: 0px 1px 3px rgba(17, 17, 17, 0.1);\n z-index: 1000;\n"],["\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 1px;\n box-shadow: 0px 1px 3px rgba(17, 17, 17, 0.1);\n z-index: 1000;\n"])))}).call(t,n(11))},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(40),s=n(9),u=n(291),c=n(641),l=n(299),p=n(67),f=n(143),d=n(36),h=n(696),m=n(66),g=n(68),y=n(12),v=n(8),b=n(292),x=n(1),C=function(e){function t(t){var n=e.call(this,t)||this;return n.setRef=function(e){n.ref=e},n.showDocFromType=function(e){n.props.addStack(n.props.sessionId,e,0,0)},n.handleSearch=function(e){n.setState({searchValue:e})},n.handleKeyDown=function(e){if(!(e.target instanceof HTMLInputElement||e.metaKey||e.shiftKey||e.altKey||e.ctrlKey)){e.preventDefault(),n.props.changeKeyMove(n.props.sessionId,!0);var t=n.props.docs.navStack.length>0&&n.props.docs.navStack[n.props.docs.navStack.length-1],r=n.props.docs.navStack.length>0&&n.props.docs.navStack[n.props.docs.navStack.length-2],i=u(e);switch(i){case"esc":n.props.setDocsVisible(n.props.sessionId,!1);break;case"left":r&&n.props.addStack(n.props.sessionId,r.field,r.x,r.y);break;case"right":if(t){var o=m.serialize(n.props.schema,t.field),a=m.getElement(o,0);a&&n.props.addStack(n.props.sessionId,a,t.x+1,0)}else{var o=m.serializeRoot(n.props.schema),s=m.getElementRoot(o,0);s&&n.props.addStack(n.props.sessionId,s,0,0)}break;case"up":case"down":if(r){var o=m.serialize(n.props.schema,r.field),s=m.getElement(o,"up"===i?t.y-1:t.y+1);s&&n.props.addStack(n.props.sessionId,s,t.x,"up"===i?t.y-1:t.y+1)}else{var o=m.serializeRoot(n.props.schema),c=t?t.y:0,s=m.getElementRoot(o,"up"===i?c-1:c+1);s&&n.props.addStack(n.props.sessionId,s,0,"up"===i?c-1:c+1)}}}},n.state={searchValue:"",widthMap:{}},window.d=n,n}return r(t,e),t.prototype.componentWillReceiveProps=function(e){(this.props.docs.navStack.length!==e.docs.navStack.length||this.props.docs.navStack.slice(-1)[0]!==e.docs.navStack.slice(-1)[0]||!this.props.schema&&e.schema)&&this.setWidth(e)},t.prototype.setWidth=function(e){void 0===e&&(e=this.props),this.props.setWidth(e)},t.prototype.getWidth=function(e){var t=this;return void 0===e&&(e=this.props),[this.state.widthMap.root||d.columnWidth].concat(e.docs.navStack.map(function(e){return t.state.widthMap[e.field.path]||d.columnWidth})).reduce(function(e,t){return e+t},0)},t.prototype.componentDidMount=function(){this.setWidth()},t.prototype.render=function(){var e,t=this,n=this.props.docs.navStack,r=this.props.schema;return void 0===r?e=o.createElement(f.default,null):null===r&&(e=o.createElement(b.ErrorContainer,null,"No Schema Available")),o.createElement(S,{onKeyDown:this.handleKeyDown,tabIndex:0,ref:this.setRef},e&&o.createElement(l.default,null,e),!e&&r&&o.createElement(h.default,{schema:r,width:this.state.widthMap.root||d.columnWidth-1,searchValue:this.state.searchValue,handleSearch:this.handleSearch,sessionId:this.props.sessionId}),n.map(function(e,n){return o.createElement(l.default,{key:n,width:t.state.widthMap[e.field.path]||d.columnWidth},o.createElement(c.default,{schema:r,field:e.field,level:n+1,sessionId:t.props.sessionId}))}))},t}(o.Component),E=function(e){return a.bindActionCreators({addStack:p.addStack,toggleDocs:p.toggleDocs,changeWidthDocs:p.changeWidthDocs,changeKeyMove:p.changeKeyMove,setDocsVisible:p.setDocsVisible},e)},D=v.createStructuredSelector({docs:g.getSessionDocs,sessionId:y.getSelectedSessionIdFromRoot});t.default=s.connect(D,E,null,{withRef:!0})(C);var w,S=x.styled.div(w||(w=i(["\n display: flex;\n position: relative;\n height: 100%;\n width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n outline: none !important;\n"],["\n display: flex;\n position: relative;\n height: 100%;\n width: 100%;\n overflow-x: auto;\n overflow-y: hidden;\n outline: none !important;\n"])))},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(642),s=n(7),u=n(644),c=n(51),l=n(692),p=n(693),f=n(694),d=n(695),h=n(66),m=n(298),g=n(1),y=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.state={showDeprecated:!1},t.setRef=function(e){t.ref=e},t}return r(t,e),t.prototype.componentDidMount=function(){this.scrollToRight()},t.prototype.shouldComponentUpdate=function(e){return this.props.field!==e.field&&(this.scrollToRight(),!0)},t.prototype.scrollToRight=function(){var e=this.ref,t=e.parentNode&&e.parentNode.parentNode;x(t,t.scrollWidth,50)},t.prototype.render=function(){var e=this,t=this.props,n=t.schema,r=t.field,i=t.level,u=r.type||r,g=h.serialize(n,r);u=h.getDeeperType(u);var y,v=g.fields.length+g.interfaces.length,b=g.fields.length+g.interfaces.length+g.args.length;return y=u instanceof s.GraphQLInterfaceType?"interface":u instanceof s.GraphQLUnionType?"union":u instanceof s.GraphQLEnumType?"enum":"type",o.createElement("div",{ref:this.setRef},o.createElement(C,null,o.createElement(c.default,{type:r,x:i,y:-1,clickable:!1,lastActive:!1})),o.createElement(E,{className:"doc-type-description",markdown:r.description||""}),o.createElement(m.CategoryTitle,null,y+" details"),u.description&&u.description.length>0&&o.createElement(E,{markdown:u.description||""}),u instanceof s.GraphQLScalarType&&o.createElement(p.default,{type:u}),u instanceof s.GraphQLEnumType&&o.createElement(f.default,{type:u}),u instanceof s.GraphQLUnionType&&o.createElement(d.default,{type:u,schema:n,level:i,sessionId:this.props.sessionId}),g.fields&&g.fields.length>0&&o.createElement(l.default,{type:u,fields:g.fields,interfaces:g.interfaces,level:i,sessionId:this.props.sessionId}),g.args&&g.args.length>0&&o.createElement("div",null,o.createElement(m.CategoryTitle,null,"arguments"),g.args.map(function(t,n){return o.createElement("div",{key:t.name},o.createElement("div",null,o.createElement(a.default,{arg:t,x:i,y:n+v,sessionId:e.props.sessionId})))})),g.implementations&&g.implementations.length>0&&o.createElement("div",null,o.createElement(m.CategoryTitle,null,"implementations"),g.implementations.map(function(e,t){return o.createElement(c.default,{key:e.name,type:e,x:i,y:t+b,collapsable:!0,lastActive:!1})})))},t}(o.Component);t.default=y;var v,b,x=function e(t,n,r){if(!(r<=0)){var i=n-t.scrollLeft,o=i/r*10;setTimeout(function(){t.scrollLeft=t.scrollLeft+o,t.scrollLeft!==n&&e(t,n,r-10)},10)}},C=g.styled.div(v||(v=i(["\n background: ",";\n padding-top: 20px;\n padding-bottom: 10px;\n\n .doc-category-item {\n font-size: 14px;\n font-weight: 600;\n word-wrap: break-word;\n }\n .doc-category-item .field-name {\n color: #f25c54;\n }\n div {\n background: transparent;\n pointer-events: none;\n }\n"],["\n background: ",";\n padding-top: 20px;\n padding-bottom: 10px;\n\n .doc-category-item {\n font-size: 14px;\n font-weight: 600;\n word-wrap: break-word;\n }\n .doc-category-item .field-name {\n color: #f25c54;\n }\n div {\n background: transparent;\n pointer-events: none;\n }\n"])),function(e){return e.theme.colours.black02}),E=g.styled(u.default)(b||(b=i(["\n font-size: 14px;\n padding: 0 16px 20px 16px;\n color: rgba(0, 0, 0, 0.5);\n"],["\n font-size: 14px;\n padding: 0 16px 20px 16px;\n color: rgba(0, 0, 0, 0.5);\n"])))},function(e,t,n){"use strict";function r(e){var t=e.arg,n=e.showDefaultValue,r=e.x,s=e.y;return i.createElement("span",null,i.createElement(a.default,{type:t,x:r,y:s,lastActive:!1,afterNode:void 0!==t.defaultValue&&!1!==n&&i.createElement("span",null," = ",i.createElement("span",{className:"arg-default-value"},o.print(o.astFromValue(t.defaultValue,t.type))))}))}Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(7),a=n(51);t.default=r},function(e,t,n){"use strict";function r(e){var t=e.arg,n=e.showDefaultValue;return a.createElement(l,null,a.createElement("span",{className:"arg-name"},t.name),": ",a.createElement("span",{className:"type-name"},i(t.type)),void 0!==t.defaultValue&&!1!==n&&a.createElement("span",null," = ",a.createElement("span",{className:"arg-default-value"},s.print(s.astFromValue(t.defaultValue,t.type)))))}function i(e){return e instanceof s.GraphQLNonNull?a.createElement("span",null,i(e.ofType),"!"):e instanceof s.GraphQLList?a.createElement("span",null,"[",i(e.ofType),"]"):a.createElement("span",null,e.name)}var o=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),s=n(7),u=n(1);t.default=r;var c,l=u.styled.div(c||(c=o(["\n margin-left: 16px;\n"],["\n margin-left: 16px;\n"])))},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t}function a(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var s=function(){function e(e,t){for(var n=0;n=0))try{t.hostname=m.toASCII(t.hostname)}catch(e){}return h.encode(h.format(t))}function o(e){var t=h.parse(e,!0);if(t.hostname&&(!t.protocol||b.indexOf(t.protocol)>=0))try{t.hostname=m.toUnicode(t.hostname)}catch(e){}return h.decode(h.format(t))}function a(e,t){if(!(this instanceof a))return new a(e,t);t||s.isString(e)||(t=e||{},e="default"),this.inline=new f,this.block=new p,this.core=new l,this.renderer=new c,this.linkify=new d,this.validateLink=r,this.normalizeLink=i,this.normalizeLinkText=o,this.utils=s,this.helpers=s.assign({},u),this.options={},this.configure(e),t&&this.set(t)}var s=n(5),u=n(649),c=n(653),l=n(654),p=n(662),f=n(676),d=n(267),h=n(88),m=n(271),g={default:n(689),zero:n(690),commonmark:n(691)},y=/^(vbscript|javascript|file|data):/,v=/^data:image\/(gif|png|jpeg|webp);/,b=["http:","https:","mailto:"];a.prototype.set=function(e){return s.assign(this.options,e),this},a.prototype.configure=function(e){var t,n=this;if(s.isString(e)&&(t=e,!(e=g[t])))throw new Error('Wrong `markdown-it` preset "'+t+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&n.set(e.options),e.components&&Object.keys(e.components).forEach(function(t){e.components[t].rules&&n[t].ruler.enableOnly(e.components[t].rules),e.components[t].rules2&&n[t].ruler2.enableOnly(e.components[t].rules2)}),this},a.prototype.enable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach(function(t){n=n.concat(this[t].ruler.enable(e,!0))},this),n=n.concat(this.inline.ruler2.enable(e,!0));var r=e.filter(function(e){return n.indexOf(e)<0});if(r.length&&!t)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+r);return this},a.prototype.disable=function(e,t){var n=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach(function(t){n=n.concat(this[t].ruler.disable(e,!0))},this),n=n.concat(this.inline.ruler2.disable(e,!0));var r=e.filter(function(e){return n.indexOf(e)<0});if(r.length&&!t)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+r);return this},a.prototype.use=function(e){var t=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,t),this},a.prototype.parse=function(e,t){if("string"!==typeof e)throw new Error("Input data should be a String");var n=new this.core.State(e,this,t);return this.core.process(n),n.tokens},a.prototype.render=function(e,t){return t=t||{},this.renderer.render(this.parse(e,t),this.options,t)},a.prototype.parseInline=function(e,t){var n=new this.core.State(e,this,t);return n.inlineMode=!0,this.core.process(n),n.tokens},a.prototype.renderInline=function(e,t){return t=t||{},this.renderer.render(this.parseInline(e,t),this.options,t)},e.exports=a},function(e,t,n){"use strict";t.Any=n(268),t.Cc=n(269),t.Cf=n(648),t.P=n(136),t.Z=n(270)},function(e,t){e.exports=/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804\uDCBD|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/},function(e,t,n){"use strict";t.parseLinkLabel=n(650),t.parseLinkDestination=n(651),t.parseLinkTitle=n(652)},function(e,t,n){"use strict";e.exports=function(e,t,n){var r,i,o,a,s=-1,u=e.posMax,c=e.pos;for(e.pos=t+1,r=1;e.pos=n)return u;if(34!==(o=e.charCodeAt(t))&&39!==o&&40!==o)return u;for(t++,40===o&&(o=41);t"+a(e[t].content)+""},s.code_block=function(e,t,n,r,i){var o=e[t];return""+a(e[t].content)+"\n"},s.fence=function(e,t,n,r,i){var s,u,c,l,p=e[t],f=p.info?o(p.info).trim():"",d="";return f&&(d=f.split(/\s+/g)[0]),s=n.highlight?n.highlight(p.content,d)||a(p.content):a(p.content),0===s.indexOf(""+s+"\n"):"
    "+s+"
    \n"},s.image=function(e,t,n,r,i){var o=e[t];return o.attrs[o.attrIndex("alt")][1]=i.renderInlineAsText(o.children,n,r),i.renderToken(e,t,n)},s.hardbreak=function(e,t,n){return n.xhtmlOut?"
    \n":"
    \n"},s.softbreak=function(e,t,n){return n.breaks?n.xhtmlOut?"
    \n":"
    \n":"\n"},s.text=function(e,t){return a(e[t].content)},s.html_block=function(e,t){return e[t].content},s.html_inline=function(e,t){return e[t].content},r.prototype.renderAttrs=function(e){var t,n,r;if(!e.attrs)return"";for(r="",t=0,n=e.attrs.length;t\n":">")},r.prototype.renderInline=function(e,t,n){for(var r,i="",o=this.rules,a=0,s=e.length;a\s]/i.test(e)}function i(e){return/^<\/a\s*>/i.test(e)}var o=n(5).arrayReplaceAt;e.exports=function(e){var t,n,a,s,u,c,l,p,f,d,h,m,g,y,v,b,x,C=e.tokens;if(e.md.options.linkify)for(n=0,a=C.length;n=0;t--)if(c=s[t],"link_close"!==c.type){if("html_inline"===c.type&&(r(c.content)&&g>0&&g--,i(c.content)&&g++),!(g>0)&&"text"===c.type&&e.md.linkify.test(c.content)){for(f=c.content,x=e.md.linkify.match(f),l=[],m=c.level,h=0,p=0;ph&&(u=new e.Token("text","",0),u.content=f.slice(h,d),u.level=m,l.push(u)),u=new e.Token("link_open","a",1),u.attrs=[["href",v]],u.level=m++,u.markup="linkify",u.info="auto",l.push(u),u=new e.Token("text","",0),u.content=b,u.level=m,l.push(u),u=new e.Token("link_close","a",-1),u.level=--m,u.markup="linkify",u.info="auto",l.push(u),h=x[p].lastIndex);h=0;t--)n=e[t],"text"!==n.type||i||(n.content=n.content.replace(u,r)),"link_open"===n.type&&"auto"===n.info&&i--,"link_close"===n.type&&"auto"===n.info&&i++}function o(e){var t,n,r=0;for(t=e.length-1;t>=0;t--)n=e[t],"text"!==n.type||r||a.test(n.content)&&(n.content=n.content.replace(/\+-/g,"\xb1").replace(/\.{2,}/g,"\u2026").replace(/([?!])\u2026/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---([^-]|$)/gm,"$1\u2014$2").replace(/(^|\s)--(\s|$)/gm,"$1\u2013$2").replace(/(^|[^-\s])--([^-\s]|$)/gm,"$1\u2013$2")),"link_open"===n.type&&"auto"===n.info&&r--,"link_close"===n.type&&"auto"===n.info&&r++}var a=/\+-|\.\.|\?\?\?\?|!!!!|,,|--/,s=/\((c|tm|r|p)\)/i,u=/\((c|tm|r|p)\)/gi,c={c:"\xa9",r:"\xae",p:"\xa7",tm:"\u2122"};e.exports=function(e){var t;if(e.md.options.typographer)for(t=e.tokens.length-1;t>=0;t--)"inline"===e.tokens[t].type&&(s.test(e.tokens[t].content)&&i(e.tokens[t].children),a.test(e.tokens[t].content)&&o(e.tokens[t].children))}},function(e,t,n){"use strict";function r(e,t,n){return e.substr(0,t)+n+e.substr(t+1)}function i(e,t){var n,i,u,p,f,d,h,m,g,y,v,b,x,C,E,D,w,S,k,A,_;for(k=[],n=0;n=0&&!(k[w].level<=h);w--);if(k.length=w+1,"text"===i.type){u=i.content,f=0,d=u.length;e:for(;f=0)g=u.charCodeAt(p.index-1);else for(w=n-1;w>=0;w--)if("text"===e[w].type){g=e[w].content.charCodeAt(e[w].content.length-1);break}if(y=32,f=48&&g<=57&&(D=E=!1),E&&D&&(E=!1,D=b),E||D){if(D)for(w=k.length-1;w>=0&&(m=k[w],!(k[w].level=0;t--)"inline"===e.tokens[t].type&&u.test(e.tokens[t].content)&&i(e.tokens[t].children,e)}},function(e,t,n){"use strict";function r(e,t,n){this.src=e,this.env=n,this.tokens=[],this.inlineMode=!1,this.md=t}var i=n(145);r.prototype.Token=i,e.exports=r},function(e,t,n){"use strict";function r(){this.ruler=new i;for(var e=0;e=n))&&!(e.sCount[a]=u){e.line=n;break}for(r=0;rn)return!1;if(p=t+1,e.sCount[p]=4)return!1;if((c=e.bMarks[p]+e.tShift[p])>=e.eMarks[p])return!1;if(124!==(s=e.src.charCodeAt(c++))&&45!==s&&58!==s)return!1;for(;c=4)return!1;if(f=i(u.replace(/^\||\|$/g,"")),(d=f.length)>m.length)return!1;if(a)return!0;for(h=e.push("table_open","table",1),h.map=y=[t,0],h=e.push("thead_open","thead",1),h.map=[t,t+1],h=e.push("tr_open","tr",1),h.map=[t,t+1],l=0;l=4);p++){for(f=i(u.replace(/^\||\|$/g,"")),h=e.push("tr_open","tr",1),l=0;l=4))break;r++,i=r}return e.line=i,o=e.push("code_block","code",0),o.content=e.getLines(t,i,4+e.blkIndent,!0),o.map=[t,e.line],!0}},function(e,t,n){"use strict";e.exports=function(e,t,n,r){var i,o,a,s,u,c,l,p=!1,f=e.bMarks[t]+e.tShift[t],d=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(f+3>d)return!1;if(126!==(i=e.src.charCodeAt(f))&&96!==i)return!1;if(u=f,f=e.skipChars(f,i),(o=f-u)<3)return!1;if(l=e.src.slice(u,f),a=e.src.slice(f,d),a.indexOf(String.fromCharCode(i))>=0)return!1;if(r)return!0;for(s=t;!(++s>=n)&&(f=u=e.bMarks[s]+e.tShift[s],d=e.eMarks[s],!(f=4)&&!((f=e.skipChars(f,i))-u=4)return!1;if(62!==e.src.charCodeAt(k++))return!1;if(i)return!0;for(u=d=e.sCount[t]+k-(e.bMarks[t]+e.tShift[t]),32===e.src.charCodeAt(k)?(k++,u++,d++,o=!1,x=!0):9===e.src.charCodeAt(k)?(x=!0,(e.bsCount[t]+d)%4===3?(k++,u++,d++,o=!1):o=!0):x=!1,h=[e.bMarks[t]],e.bMarks[t]=k;k=A,v=[e.sCount[t]],e.sCount[t]=d-u,b=[e.tShift[t]],e.tShift[t]=k-e.bMarks[t],E=e.md.block.ruler.getRules("blockquote"),y=e.parentType,e.parentType="blockquote",w=!1,f=t+1;f=A));f++)if(62!==e.src.charCodeAt(k++)||w){if(l)break;for(C=!1,s=0,c=E.length;s=A,m.push(e.bsCount[f]),e.bsCount[f]=e.sCount[f]+1+(x?1:0),v.push(e.sCount[f]),e.sCount[f]=d-u,b.push(e.tShift[f]),e.tShift[f]=k-e.bMarks[f]}for(g=e.blkIndent,e.blkIndent=0,D=e.push("blockquote_open","blockquote",1),D.markup=">",D.map=p=[t,0],e.md.block.tokenize(e,t,f),D=e.push("blockquote_close","blockquote",-1),D.markup=">",e.lineMax=S,e.parentType=y,p[1]=e.line,s=0;s=4)return!1;if(42!==(o=e.src.charCodeAt(c++))&&45!==o&&95!==o)return!1;for(a=1;c=o)return-1;if((n=e.src.charCodeAt(i++))<48||n>57)return-1;for(;;){if(i>=o)return-1;n=e.src.charCodeAt(i++);{if(!(n>=48&&n<=57)){if(41===n||46===n)break;return-1}if(i-r>=10)return-1}}return i=4)return!1;if(a&&"paragraph"===e.parentType&&e.tShift[t]>=e.blkIndent&&(P=!0),(T=i(e,t))>=0){if(d=!0,F=e.bMarks[t]+e.tShift[t],b=Number(e.src.substr(F,T-F-1)),P&&1!==b)return!1}else{if(!((T=r(e,t))>=0))return!1;d=!1}if(P&&e.skipSpaces(T)>=e.eMarks[t])return!1;if(v=e.src.charCodeAt(T-1),a)return!0;for(y=e.tokens.length,d?(L=e.push("ordered_list_open","ol",1),1!==b&&(L.attrs=[["start",b]])):L=e.push("bullet_list_open","ul",1),L.map=g=[t,0],L.markup=String.fromCharCode(v),C=t,O=!1,I=e.md.block.ruler.getRules("list"),S=e.parentType,e.parentType="list";C=x?1:E-f,p>4&&(p=1),l=f+p,L=e.push("list_item_open","li",1),L.markup=String.fromCharCode(v),L.map=h=[t,0],D=e.blkIndent,A=e.tight,k=e.tShift[t],w=e.sCount[t],e.blkIndent=l,e.tight=!0,e.tShift[t]=u-e.bMarks[t],e.sCount[t]=E,u>=x&&e.isEmpty(t+1)?e.line=Math.min(e.line+2,n):e.md.block.tokenize(e,t,n,!0),e.tight&&!O||(M=!1),O=e.line-t>1&&e.isEmpty(e.line-1),e.blkIndent=D,e.tShift[t]=k,e.sCount[t]=w,e.tight=A,L=e.push("list_item_close","li",-1),L.markup=String.fromCharCode(v),C=t=e.line,h[1]=C,u=e.bMarks[t],C>=n)break;if(e.sCount[C]=4)return!1;if(91!==e.src.charCodeAt(D))return!1;for(;++D3)&&!(e.sCount[S]<0)){for(b=!1,p=0,f=x.length;p=4)return!1;if(35!==(o=e.src.charCodeAt(c))||c>=l)return!1;for(a=1,o=e.src.charCodeAt(++c);35===o&&c6||cc&&r(e.src.charCodeAt(s-1))&&(l=s),e.line=t+1,u=e.push("heading_open","h"+String(a),1),u.markup="########".slice(0,a),u.map=[t,e.line],u=e.push("inline","",0),u.content=e.src.slice(c,l).trim(),u.map=[t,e.line],u.children=[],u=e.push("heading_close","h"+String(a),-1),u.markup="########".slice(0,a),!0))}},function(e,t,n){"use strict";e.exports=function(e,t,n){var r,i,o,a,s,u,c,l,p,f,d=t+1,h=e.md.block.ruler.getRules("paragraph");if(e.sCount[t]-e.blkIndent>=4)return!1;for(f=e.parentType,e.parentType="paragraph";d3)){if(e.sCount[d]>=e.blkIndent&&(u=e.bMarks[d]+e.tShift[d],c=e.eMarks[d],u=c))){l=61===p?1:2;break}if(!(e.sCount[d]<0)){for(i=!1,o=0,a=h.length;o|$))/i,/<\/(script|pre|style)>/i,!0],[/^/,!0],[/^<\?/,/\?>/,!0],[/^/,!0],[/^/,!0],[new RegExp("^|$))","i"),/^$/,!0],[new RegExp(i.source+"\\s*$"),/^$/,!1]];e.exports=function(e,t,n,r){var i,a,s,u,c=e.bMarks[t]+e.tShift[t],l=e.eMarks[t];if(e.sCount[t]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(c))return!1;for(u=e.src.slice(c,l),i=0;i3)&&!(e.sCount[u]<0)){for(r=!1,i=0,o=c.length;i0&&this.level++,this.tokens.push(r),r},r.prototype.isEmpty=function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]},r.prototype.skipEmptyLines=function(e){for(var t=this.lineMax;et;)if(!o(this.src.charCodeAt(--e)))return e+1;return e},r.prototype.skipChars=function(e,t){for(var n=this.src.length;en;)if(t!==this.src.charCodeAt(--e))return e+1;return e},r.prototype.getLines=function(e,t,n,r){var i,a,s,u,c,l,p,f=e;if(e>=t)return"";for(l=new Array(t-e),i=0;fn?new Array(a-n+1).join(" ")+this.src.slice(u,c):this.src.slice(u,c)}return l.join("")},r.prototype.Token=i,e.exports=r},function(e,t,n){"use strict";function r(){var e;for(this.ruler=new i,e=0;e=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},r.prototype.parse=function(e,t,n,r){var i,o,a,s=new this.State(e,t,n,r);for(this.tokenize(s),o=this.ruler2.getRules(""),a=o.length,i=0;i=0&&32===e.pending.charCodeAt(n)?n>=1&&32===e.pending.charCodeAt(n-1)?(e.pending=e.pending.replace(/ +$/,""),e.push("hardbreak","br",0)):(e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0)):e.push("softbreak","br",0)),o++;o?@[]^_`{|}~-".split("").forEach(function(e){i[e.charCodeAt(0)]=1}),e.exports=function(e,t){var n,o=e.pos,a=e.posMax;if(92!==e.src.charCodeAt(o))return!1;if(++o=g)return!1;for(y=c,l=e.md.helpers.parseLinkDestination(e.src,c,e.posMax),l.ok&&(h=e.md.normalizeLink(l.str),e.md.validateLink(h)?c=l.pos:h=""),y=c;c=g||41!==e.src.charCodeAt(c))&&(v=!0),c++}if(v){if("undefined"===typeof e.env.references)return!1;if(c=0?a=e.src.slice(y,c++):c=s+1):c=s+1,a||(a=e.src.slice(u,s)),!(p=e.env.references[r(a)]))return e.pos=m,!1;h=p.href,f=p.title}return t||(e.pos=u,e.posMax=s,d=e.push("link_open","a",1),d.attrs=n=[["href",h]],f&&n.push(["title",f]),e.md.inline.tokenize(e),d=e.push("link_close","a",-1)),e.pos=c,e.posMax=g,!0}},function(e,t,n){"use strict";var r=n(5).normalizeReference,i=n(5).isSpace;e.exports=function(e,t){var n,o,a,s,u,c,l,p,f,d,h,m,g,y="",v=e.pos,b=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(c=e.pos+2,(u=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((l=u+1)=b)return!1;for(g=l,f=e.md.helpers.parseLinkDestination(e.src,l,e.posMax),f.ok&&(y=e.md.normalizeLink(f.str),e.md.validateLink(y)?l=f.pos:y=""),g=l;l=b||41!==e.src.charCodeAt(l))return e.pos=v,!1;l++}else{if("undefined"===typeof e.env.references)return!1;if(l=0?s=e.src.slice(g,l++):l=u+1):l=u+1,s||(s=e.src.slice(c,u)),!(p=e.env.references[r(s)]))return e.pos=v,!1;y=p.href,d=p.title}return t||(a=e.src.slice(c,u),e.md.inline.parse(a,e.md,e.env,m=[]),h=e.push("image","img",0),h.attrs=n=[["src",y],["alt",""]],h.children=m,h.content=a,d&&n.push(["title",d])),e.pos=l,e.posMax=b,!0}},function(e,t,n){"use strict";var r=/^<([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)>/,i=/^<([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)>/;e.exports=function(e,t){var n,o,a,s,u,c,l=e.pos;return 60===e.src.charCodeAt(l)&&(n=e.src.slice(l),!(n.indexOf(">")<0)&&(i.test(n)?(o=n.match(i),s=o[0].slice(1,-1),u=e.md.normalizeLink(s),!!e.md.validateLink(u)&&(t||(c=e.push("link_open","a",1),c.attrs=[["href",u]],c.markup="autolink",c.info="auto",c=e.push("text","",0),c.content=e.md.normalizeLinkText(s),c=e.push("link_close","a",-1),c.markup="autolink",c.info="auto"),e.pos+=o[0].length,!0)):!!r.test(n)&&(a=n.match(r),s=a[0].slice(1,-1),u=e.md.normalizeLink("mailto:"+s),!!e.md.validateLink(u)&&(t||(c=e.push("link_open","a",1),c.attrs=[["href",u]],c.markup="autolink",c.info="auto",c=e.push("text","",0),c.content=e.md.normalizeLinkText(s),c=e.push("link_close","a",-1),c.markup="autolink",c.info="auto"),e.pos+=a[0].length,!0))))}},function(e,t,n){"use strict";function r(e){var t=32|e;return t>=97&&t<=122}var i=n(295).HTML_TAG_RE;e.exports=function(e,t){var n,o,a,s,u=e.pos;return!!e.md.options.html&&(a=e.posMax,!(60!==e.src.charCodeAt(u)||u+2>=a)&&(!(33!==(n=e.src.charCodeAt(u+1))&&63!==n&&47!==n&&!r(n))&&(!!(o=e.src.slice(u).match(i))&&(t||(s=e.push("html_inline","",0),s.content=e.src.slice(u,u+o[0].length)),e.pos+=o[0].length,!0))))}},function(e,t,n){"use strict";var r=n(294),i=n(5).has,o=n(5).isValidEntityCode,a=n(5).fromCodePoint,s=/^&#((?:x[a-f0-9]{1,8}|[0-9]{1,8}));/i,u=/^&([a-z][a-z0-9]{1,31});/i;e.exports=function(e,t){var n,c,l=e.pos,p=e.posMax;if(38!==e.src.charCodeAt(l))return!1;if(l+1=0;){if(i=o[n],i.open&&i.marker===r.marker&&i.end<0&&i.level===r.level){var s=(i.close||r.open)&&"undefined"!==typeof i.length&&"undefined"!==typeof r.length&&(i.length+r.length)%3===0;if(!s){r.jump=t-n,r.open=!1,i.end=t,i.jump=0;break}}n-=i.jump+1}}},function(e,t,n){"use strict";e.exports=function(e){var t,n,r=0,i=e.tokens,o=e.tokens.length;for(t=n=0;t0&&this.level++,this.pendingLevel=this.level,this.tokens.push(r),r},r.prototype.scanDelims=function(e,t){var n,r,i,u,c,l,p,f,d,h=e,m=!0,g=!0,y=this.posMax,v=this.src.charCodeAt(e);for(n=e>0?this.src.charCodeAt(e-1):32;h0&&o.createElement("br",null),c.map(function(e,t){return o.createElement("div",{key:e.name},o.createElement(v,null,"# Deprecated: ",e.deprecationReason),o.createElement(a.default,{type:e,x:s,y:t+u.length+r.length,collapsable:!0,lastActive:!1}))}),o.createElement(m,null,o.createElement(b,null,"}")))};var u,c,l,p,f,d,h=s.styled.div(u||(u=r(["\n font-size: 14px;\n overflow: auto;\n .doc-category-item {\n padding-left: 32px;\n }\n"],["\n font-size: 14px;\n overflow: auto;\n .doc-category-item {\n padding-left: 32px;\n }\n"]))),m=s.styled.div(c||(c=r(["\n padding: 6px 16px;\n white-space: nowrap;\n"],["\n padding: 6px 16px;\n white-space: nowrap;\n"]))),g=s.styled.span(l||(l=r(["\n color: #f25c54;\n"],["\n color: #f25c54;\n"]))),y=s.styled(a.default)(p||(p=r(["\n padding-left: 16px;\n .field-name {\n color: rgb(245, 160, 0);\n }\n .type-name {\n color: #f25c54;\n }\n"],["\n padding-left: 16px;\n .field-name {\n color: rgb(245, 160, 0);\n }\n .type-name {\n color: #f25c54;\n }\n"]))),v=s.styled.span(f||(f=r(["\n color: ",";\n padding-right: 16px;\n padding-left: 32px;\n"],["\n color: ",";\n padding-right: 16px;\n padding-left: 32px;\n"])),function(e){return e.theme.colours.black50}),b=s.styled.span(d||(d=r(["\n font-weight: 600;\n color: ",";\n"],["\n font-weight: 600;\n color: ",";\n"])),function(e){return e.theme.colours.darkBlue50})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(0),i=n(146),o=function(e){var t=e.type;return r.createElement(i.DocType,{className:"doc-type-schema"},r.createElement("span",{className:"field-name"},"scalar")," ",r.createElement("span",{className:"type-name"},t.name))};t.default=o},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(1),a=n(146),s=function(e){var t=e.type,n=e.sdlType,r=n?t._values:t.getValues(),o=r.filter(function(e){return e.isDeprecated});return i.createElement(a.DocType,{className:"doc-type-schema"},i.createElement("span",{className:"field-name"},"enum")," ",i.createElement("span",{className:"type-name"},t.name)," ",i.createElement("span",{className:"brace"},"{"),r.filter(function(e){return!e.isDeprecated}).map(function(e,t){return i.createElement(l,{key:e.name,first:0===t,value:e})}),o.length>0&&i.createElement("br",null),o.map(function(e,t){return i.createElement(l,{first:0===t,key:e.name,value:e,isDeprecated:!0})}),i.createElement("span",{className:"brace"},"}"))};t.default=s;var u,c,l=function(e){var t=e.value,n=e.isDeprecated,r=e.first;return i.createElement(p,{first:r},i.createElement("div",{className:"field-name"},t.name),t.description&&i.createElement(f,null,t.description),n&&i.createElement(f,null,"Deprecated: ",t.deprecationReason))},p=o.styled("div")(u||(u=r(["\n margin-top: ","px;\n .field-name {\n padding: 0 16px;\n color: red;\n }\n"],["\n margin-top: ","px;\n .field-name {\n padding: 0 16px;\n color: red;\n }\n"])),function(e){return e.first?0:6}),f=o.styled.div(c||(c=r(["\n padding: 0 16px;\n color: ",";\n"],["\n padding: 0 16px;\n color: ",";\n"])),function(e){return e.theme.colours.black50})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(51),i=n(0),o=n(146),a=function(e){var t=e.schema,n=e.type,a=e.level,s=e.sessionId,u=t.getPossibleTypes(n);return i.createElement(o.DocType,{className:"doc-type-schema"},i.createElement("span",{className:"field-name"},"union")," ",i.createElement("span",{className:"type-name"},n.name)," = ",u.map(function(e,t){return i.createElement(r.default,{key:e.name,type:e,x:a,y:t+1,collapsable:!0,sessionId:s,lastActive:!1})}))};t.default=a},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(299),s=n(697),u=n(698),c=n(300),l=n(1),p=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(){var e=this.props,t=e.searchValue,n=e.schema,r=e.width,i=e.sessionId,l=e.handleSearch;return o.createElement(a.default,{width:r,overflow:!1},o.createElement(c.default,{onSearch:l}),o.createElement(d,null,t&&o.createElement(s.default,{searchValue:t,schema:n,level:0,sessionId:i}),!t&&o.createElement(u.default,{schema:n,sessionId:i})))},t}(o.PureComponent);t.default=p;var f,d=l.styled.div(f||(f=i(["\n overflow: auto;\n"],["\n overflow: auto;\n"])))},function(e,t,n){"use strict";function r(e,t){try{var n=t.replace(/[^_0-9A-Za-z]/g,function(e){return"\\"+e});return-1!==e.search(new RegExp(n,"i"))}catch(n){return-1!==e.toLowerCase().indexOf(t.toLowerCase())}}var i=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),o=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),s=n(1),u=n(51),c=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return i(t,e),t.prototype.shouldComponentUpdate=function(e){return this.props.schema!==e.schema||this.props.searchValue!==e.searchValue},t.prototype.render=function(){var e=this.props.level,t=this.props.searchValue,n=this.props.withinType,i=this.props.schema,o=[],s=[],c=[],l=i.getTypeMap(),f=Object.keys(l);n&&(f=f.filter(function(e){return e!==n.name}),f.unshift(n.name));for(var d=0,h=0,m=f;h=100)return"break";var p=l[i];if(n!==p&&r(i,t)&&s.push(a.createElement("div",{className:"doc-category-item",key:i},a.createElement(u.default,{type:p,x:e,y:d++,lastActive:!1}))),p.getFields){var f=p.getFields();Object.keys(f).forEach(function(s){var l=f[s];l.parent=p;var h;if(!r(s,t)){if(!l.args||!l.args.length)return;if(h=l.args.filter(function(e){return r(e.name,t)}),0===h.length)return}var m=a.createElement("div",{className:"doc-category-item",key:i+"."+s},a.createElement(u.default,{key:"type",type:l,x:e,y:d++,showParentName:!0,lastActive:!1}));n===p?o.push(m):c.push(m)})}}(g))break}return o.length+s.length+c.length===0?a.createElement(p,null,"No results found."):n&&s.length+c.length>0?a.createElement("div",null,o,a.createElement("div",{className:"doc-category"},a.createElement("div",{className:"doc-category-title"},"other results"),s,c)):a.createElement("div",null,o,s,c)},t}(a.Component);t.default=c;var l,p=s.styled.span(l||(l=o(["\n display: block;\n margin-top: 16px;\n margin-left: 16px;\n"],["\n display: block;\n margin-top: 16px;\n margin-left: 16px;\n"])))},function(e,t,n){"use strict";function r(e){var t=e.name,n=e.fields,r=e.offset;return a.createElement("div",null,a.createElement(c.CategoryTitle,null,t),n.filter(function(e){return!e.isDeprecated}).map(function(e,t){return a.createElement(s.default,{key:e.name,type:e,x:0,y:r+t,collapsable:!0,lastActive:!1})}))}var i=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),o=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),s=n(51),u=n(66),c=n(298),l=n(1),p=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return i(t,e),t.prototype.render=function(){var e=this.props,t=e.schema,n=e.sessionId,i=u.serializeRoot(t);return a.createElement(d,{className:"doc-root"},a.createElement(r,{name:"Queries",fields:i.queries,offset:0,sessionId:n}),i.mutations.length>0&&a.createElement(r,{name:"Mutations",fields:i.mutations,offset:i.queries.length,sessionId:n}),i.subscriptions.length>0&&a.createElement(r,{name:"Subscriptions",fields:i.subscriptions,offset:i.queries.length+i.mutations.length,sessionId:n}))},t}(a.PureComponent);t.default=p;var f,d=l.styled.div(f||(f=o(["\n padding-left: 6px;\n\n .doc-category-item .field-name {\n color: #f25c54;\n }\n"],["\n padding-left: 6px;\n\n .doc-category-item .field-name {\n color: #f25c54;\n }\n"])))},function(e,t,n){"use strict";function r(e,t){var n=void 0;return function(){var r=this,i=arguments;clearTimeout(n),n=setTimeout(function(){n=null,t.apply(r,i)},e)}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=r},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(1),s=n(24),u=n(701),c=n(9),l=n(8),p=n(12),f=n(16),d=n(246),h=d.SortableElement(u.default),m=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.state={sorting:!1},t.onSortStart=function(e){e.index;t.setState({sorting:!0})},t.onSortEnd=function(e){var n=e.oldIndex,r=e.newIndex;t.props.reorderTabs(n,r),t.setState({sorting:!1})},t.getHelperDimensions=function(e){var t=e.node,n=t.getBoundingClientRect();return{width:n.width,height:n.height}},t}return r(t,e),t.prototype.render=function(){var e=this.props,t=e.sessions,n=e.isApp,r=e.selectedSessionId,i=e.onNewSession,a=this.state.sorting;return o.createElement(C,{onSortStart:this.onSortStart,onSortEnd:this.onSortEnd,getHelperDimensions:this.getHelperDimensions,axis:"x",lockAxis:"x",lockToContainerEdges:!0,distance:10,transitionDuration:200},o.createElement(E,{isApp:n},t.map(function(e,t){return o.createElement(h,{key:e.id,session:e,selectedSessionId:r,index:t})}),o.createElement(D,{onClick:i,sorting:a},o.createElement(s.AddIcon,{width:34,height:34,strokeWidth:4,title:"Opens a New Tab"}))))},t}(o.PureComponent),g=l.createStructuredSelector({sessions:p.getSessionsArray,selectedSessionId:p.getSelectedSessionIdFromRoot});t.default=c.connect(g,{reorderTabs:f.reorderTabs})(m);var y,v,b,x=a.styled.div(y||(y=i(["\n color: white;\n height: 57px;\n background: ",";\n overflow: hidden;\n -webkit-app-region: drag;\n &:hover {\n overflow-x: overlay;\n }\n"],["\n color: white;\n height: 57px;\n background: ",";\n overflow: hidden;\n -webkit-app-region: drag;\n &:hover {\n overflow-x: overlay;\n }\n"])),function(e){return e.theme.editorColours.background}),C=d.SortableContainer(x),E=a.styled("div")(v||(v=i(["\n display: flex;\n align-items: center;\n margin-top: 16px;\n padding-left: ",";\n"],["\n display: flex;\n align-items: center;\n margin-top: 16px;\n padding-left: ",";\n"])),function(e){return e.isApp?"43px":"0"}),D=a.styled("div")(b||(b=i(["\n box-sizing: border-box;\n display: flex;\n visibility: ","\n height: 43px;\n width: 43px;\n border-radius: 2px;\n border-bottom: 2px solid ",";\n background: ",";\n justify-content: center;\n align-items: center;\n svg {\n stroke: ",";\n }\n &:hover {\n background: ",";\n }\n"],["\n box-sizing: border-box;\n display: flex;\n visibility: ","\n height: 43px;\n width: 43px;\n border-radius: 2px;\n border-bottom: 2px solid ",";\n background: ",";\n justify-content: center;\n align-items: center;\n svg {\n stroke: ",";\n }\n &:hover {\n background: ",";\n }\n"])),function(e){return e.sorting?"hidden":"visible"},function(e){return e.theme.editorColours.navigationBar},function(e){return e.theme.editorColours.tabInactive},function(e){return e.theme.editorColours.icon},function(e){return e.theme.editorColours.tab})},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(24),s=n(9),u=n(16),c=n(1),l=n(702),p=function(e){function t(t){var n=e.call(this,t)||this;return n.startEditName=function(){n.setState({editingName:!0})},n.stopEditName=function(){n.setState({editingName:!1})},n.handleKeyDown=function(e){13===e.keyCode&&n.setState({editingName:!1})},n.handleMouseOverCross=function(){n.setState({overCross:!0})},n.handleMouseOutCross=function(){n.setState({overCross:!1})},n.handleSelectSession=function(){n.props.selectTab(n.props.session.id)},n.handleCloseSession=function(e){e.stopPropagation(),n.props.closeTab(n.props.session.id)},n.handleEditName=function(e){n.props.editName(e.target.value)},n.state={overCross:!1,editingName:!1},n}return r(t,e),t.prototype.render=function(){var e=this.props,t=e.session,n=e.selectedSessionId,r=t.queryTypes,i=t.id===n,s=t.name||t.operationName||r.firstOperationName||"New Tab";return o.createElement(w,{active:i,onMouseDown:this.handleSelectSession},o.createElement(A,{active:i},t.subscriptionActive&&o.createElement(I,null),o.createElement(_,null,r.query&&o.createElement(O,null,"Q"),(t.isSettingsTab||t.isConfigTab)&&o.createElement(O,null,o.createElement(a.SettingsIcon,{width:12,height:12,fill:"white"})),r.mutation&&o.createElement(F,null,"M"),r.subscription&&o.createElement(N,null,"S"))),this.state.editingName?o.createElement(k,{value:t.name||"",onChange:this.handleEditName,onBlur:this.stopEditName,onKeyDown:this.handleKeyDown,autoFocus:!0}):o.createElement(S,{active:i,onDoubleClick:this.startEditName},s),o.createElement(P,{className:"close",active:i,hasCircle:t.isFile&&t.changed&&!this.state.overCross,onClick:this.handleCloseSession,onMouseEnter:this.handleMouseOverCross,onMouseLeave:this.handleMouseOutCross},t.isFile&&t.changed&&!this.state.overCross?o.createElement(L,null,"\u2b24"):o.createElement(a.CrossIcon,{width:12,height:11,strokeWidth:7,title:"Close Tab"})))},t}(o.PureComponent);t.default=s.connect(null,{closeTab:u.closeTab,selectTab:u.selectTab,editName:u.editName})(p);var f,d,h,m,g,y,v,b,x,C,E,D,w=c.styled("div")(f||(f=i(["\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n height: 43px;\n padding: 10px;\n padding-top: 9px;\n margin-right: 10px;\n font-size: 14px;\n border-radius: 2px;\n border-bottom: 2px solid ",";\n box-sizing: border-box;\n cursor: pointer;\n user-select: none;\n background: ",";\n &:hover {\n background: ",";\n .close {\n opacity: 1;\n }\n }\n"],["\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n height: 43px;\n padding: 10px;\n padding-top: 9px;\n margin-right: 10px;\n font-size: 14px;\n border-radius: 2px;\n border-bottom: 2px solid ",";\n box-sizing: border-box;\n cursor: pointer;\n user-select: none;\n background: ",";\n &:hover {\n background: ",";\n .close {\n opacity: 1;\n }\n }\n"])),function(e){return e.theme.editorColours.navigationBar},function(e){return e.active?e.theme.editorColours.tab:e.theme.editorColours.tabInactive},function(e){return e.theme.editorColours.tab}),S=c.styled("div")(d||(d=i(["\n opacity: ",";\n background: transparent;\n color: ",";\n font-size: 14px;\n margin-left: 2px;\n display: inline;\n letter-spacing: 0.53px;\n"],["\n opacity: ",";\n background: transparent;\n color: ",";\n font-size: 14px;\n margin-left: 2px;\n display: inline;\n letter-spacing: 0.53px;\n"])),function(e){return e.active?1:.5},function(e){return e.theme.editorColours.tabText}),k=c.styled(l.default)(h||(h=i(["\n input {\n background: transparent;\n color: ",";\n font-size: 14px;\n margin-left: 2px;\n display: inline;\n letter-spacing: 0.53px;\n }\n"],["\n input {\n background: transparent;\n color: ",";\n font-size: 14px;\n margin-left: 2px;\n display: inline;\n letter-spacing: 0.53px;\n }\n"])),function(e){return e.theme.editorColours.tabText}),A=c.styled("div")(m||(m=i(["\n display: flex;\n align-items: center;\n opacity: ",";\n"],["\n display: flex;\n align-items: center;\n opacity: ",";\n"])),function(e){return e.active?1:.5}),_=c.styled.div(g||(g=i(["\n display: flex;\n color: white;\n"],["\n display: flex;\n color: white;\n"]))),T=c.styled.div(y||(y=i(["\n height: 22px;\n width: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 4px;\n font-size: 12px;\n font-weight: 700;\n border-radius: 2px;\n"],["\n height: 22px;\n width: 22px;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 4px;\n font-size: 12px;\n font-weight: 700;\n border-radius: 2px;\n"]))),O=c.styled(T)(v||(v=i(["\n background: ",";\n"],["\n background: ",";\n"])),function(e){return e.theme.colours.blue}),F=c.styled(T)(b||(b=i(["\n background: ",";\n"],["\n background: ",";\n"])),function(e){return e.theme.colours.orange}),N=c.styled(T)(x||(x=i(["\n background: ",";\n"],["\n background: ",";\n"])),function(e){return e.theme.colours.purple}),I=c.styled.div(C||(C=i(["\n width: 7px;\n height: 7px;\n background: rgba(242, 92, 84, 1);\n border-radius: 100%;\n margin-right: 10px;\n"],["\n width: 7px;\n height: 7px;\n background: rgba(242, 92, 84, 1);\n border-radius: 100%;\n margin-right: 10px;\n"]))),L=c.styled.div(E||(E=i(["\n position: relative;\n top: -2px;\n font-size: 9px;\n background: ",";\n"],["\n position: relative;\n top: -2px;\n font-size: 9px;\n background: ",";\n"])),function(e){return e.theme.editorColours.circle}),P=c.styled("div")(D||(D=i(["\n position: relative;\n display: flex;\n margin-left: 10px;\n top: 1px;\n height: 13px;\n width: 13px;\n opacity: ",";\n svg {\n stroke: ",";\n }\n"],["\n position: relative;\n display: flex;\n margin-left: 10px;\n top: 1px;\n height: 13px;\n width: 13px;\n opacity: ",";\n svg {\n stroke: ",";\n }\n"])),function(e){return e.active||e.hasCircle?1:0},function(e){return e.theme.editorColours.icon})},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n={};for(var r in e)t.indexOf(r)>=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t}function s(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var u=Object.assign||function(e){for(var t=1;t0)||e.query.toLowerCase().includes(t.toLowerCase())}),i=this.props.items.get(this.state.selectedItemIndex);return i=i&&i.toJS?i.toJS():void 0,o.createElement(a,{isOpen:this.props.isOpen,onRequestClose:this.props.closeHistory,contentLabel:"GraphiQL Session History",style:c.modalStyle},o.createElement(P,null,o.createElement(M,null,o.createElement(s.default,{onSelectFilter:this.handleSelectFilter,selectedFilter:this.state.selectedFilter,onSearch:this.handleSearch}),o.createElement(u.default,{items:r,selectedItemIndex:this.state.selectedItemIndex,searchTerm:this.state.searchTerm,onItemSelect:this.handleItemSelect,onItemStarToggled:this.props.toggleHistoryItemStarring})),Boolean(i)?o.createElement(j,null,o.createElement(R,null,o.createElement(U,null),o.createElement(z,{onClick:this.handleClickUse},o.createElement(G,null,"Use"),o.createElement(x.ArrowRight,{color:"white",width:13,height:13}))),o.createElement(V,null,o.createElement(q,null,o.createElement(b.Container,null,o.createElement(H,null,o.createElement(l.QueryEditor,{value:i.query})))))):o.createElement(j,null,o.createElement(B,null,o.createElement($,null,"No History yet")))))},t}(o.Component),E=d.createStructuredSelector({items:h.getHistory,isOpen:m.getHistoryOpen});t.default=f.connect(E,{closeHistory:g.closeHistory,openHistory:g.openHistory,duplicateSession:y.duplicateSession,toggleHistoryItemStarring:v.toggleHistoryItemStarring})(C);var D,w,S,k,A,_,T,O,F,N,I,L,P=p.styled.div(D||(D=i(["\n display: flex;\n min-height: 500px;\n"],["\n display: flex;\n min-height: 500px;\n"]))),M=p.styled.div(w||(w=i(["\n flex: 1;\n\n background: white;\n"],["\n flex: 1;\n\n background: white;\n"]))),j=p.styled.div(S||(S=i(["\n flex: 0 0 464px;\n z-index: 2;\n"],["\n flex: 0 0 464px;\n z-index: 2;\n"]))),R=p.styled.div(k||(k=i(["\n display: flex;\n justify-content: space-between;\n align-items: center;\n\n padding-left: ",";\n padding-right: ",";\n padding-top: 20px;\n padding-bottom: 20px;\n\n background: ",";\n"],["\n display: flex;\n justify-content: space-between;\n align-items: center;\n\n padding-left: ",";\n padding-right: ",";\n padding-top: 20px;\n padding-bottom: 20px;\n\n background: ",";\n"])),function(e){return e.theme.sizes.medium25},function(e){return e.theme.sizes.medium25},function(e){return e.theme.editorColours.resultBackground}),B=p.styled.div(A||(A=i(["\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n\n background: ",";\n"],["\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n\n background: ",";\n"])),function(e){return e.theme.editorColours.resultBackground}),$=p.styled.div(_||(_=i(["\n font-size: 16px;\n color: ",";\n"],["\n font-size: 16px;\n color: ",";\n"])),function(e){return e.theme.editorColours.text}),U=p.styled.div(T||(T=i(["\n font-size: ",";\n font-weight: ",";\n text-transform: uppercase;\n color: rgba(255, 255, 255, 0.4);\n"],["\n font-size: ",";\n font-weight: ",";\n text-transform: uppercase;\n color: rgba(255, 255, 255, 0.4);\n"])),function(e){return e.theme.sizes.fontSmall},function(e){return e.theme.sizes.fontSemiBold}),z=p.styled.div(O||(O=i(["\n display: flex;\n align-items: center;\n\n padding-top: ",";\n padding-bottom: ",";\n padding-left: ",";\n padding-right: ",";\n\n font-size: ",";\n font-weight: ",";\n\n border-radius: ",";\n background: ",";\n cursor: pointer;\n"],["\n display: flex;\n align-items: center;\n\n padding-top: ",";\n padding-bottom: ",";\n padding-left: ",";\n padding-right: ",";\n\n font-size: ",";\n font-weight: ",";\n\n border-radius: ",";\n background: ",";\n cursor: pointer;\n"])),function(e){return e.theme.sizes.small10},function(e){return e.theme.sizes.small10},function(e){return e.theme.sizes.small16},function(e){return e.theme.sizes.small16},function(e){return e.theme.sizes.fontSmall},function(e){return e.theme.sizes.fontSemiBold},function(e){return e.theme.sizes.smallRadius},function(e){return e.theme.colours.green}),G=p.styled.div(F||(F=i(["\n margin-right: ",";\n color: white;\n"],["\n margin-right: ",";\n color: white;\n"])),function(e){return e.theme.sizes.small6}),V=p.styled.div(N||(N=i(["\n height: calc(100% - 81px);\n display: flex;\n flex: 1 1 auto;\n"],["\n height: calc(100% - 81px);\n display: flex;\n flex: 1 1 auto;\n"]))),q=p.styled(V)(I||(I=i(["\n width: 100%;\n height: 100%;\n position: relative;\n display: flex;\n flex: 1 1 auto;\n"],["\n width: 100%;\n height: 100%;\n position: relative;\n display: flex;\n flex: 1 1 auto;\n"]))),H=p.styled.div(L||(L=i(["\n display: flex;\n flex-direction: column;\n flex: 1;\n"],["\n display: flex;\n flex-direction: column;\n flex: 1;\n"])))},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(705),a=n(1),s=n(300);t.default=function(e){return i.createElement(c,null,i.createElement(o.default,{onSelectFilter:e.onSelectFilter,selectedFilter:e.selectedFilter}),i.createElement(s.default,{placeholder:"Search the history...",onSearch:e.onSearch,clean:!0}))};var u,c=a.styled.div(u||(u=r(["\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px;\n background: ",";\n"],["\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 16px;\n background: ",";\n"])),function(e){return e.theme.colours.black02})},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(1),a=n(24),s=function(e){var t=e.selectedFilter,n=e.onSelectFilter,r=e.theme;return i.createElement(p,null,i.createElement(f,{active:"HISTORY"===t,onClick:function(){return n("HISTORY")}},i.createElement(a.History,{color:"HISTORY"===t?r.colours.white:r.colours.black30,strokeWidth:3,width:25,height:25}),i.createElement(d,null,"History")),i.createElement(f,{active:"STARRED"===t,onClick:function(){return n("STARRED")}},i.createElement(a.Star,{color:"STARRED"===t?r.colours.white:r.colours.black30,width:16,height:16}),i.createElement(d,null,"Starred")))};t.default=o.withTheme(s);var u,c,l,p=o.styled.div(u||(u=r(["\n display: flex;\n align-items: center;\n"],["\n display: flex;\n align-items: center;\n"]))),f=o.styled("div")(c||(c=r(["\n box-sizing: content-box;\n height: 24px;\n z-index: ",";\n display: flex;\n align-items: center;\n margin: 0 -2px;\n padding: ",";\n background: ",";\n\n color: ",";\n font-size: 14px;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: 2px;\n cursor: pointer;\n"],["\n box-sizing: content-box;\n height: 24px;\n z-index: ",";\n display: flex;\n align-items: center;\n margin: 0 -2px;\n padding: ",";\n background: ",";\n\n color: ",";\n font-size: 14px;\n font-weight: 600;\n text-transform: uppercase;\n border-radius: 2px;\n cursor: pointer;\n"])),function(e){return e.active?2:0},function(e){return e.active?"7px 9px 8px 9px":"5px 13px 6px 13px"},function(e){return e.active?e.theme.colours.green:e.theme.colours.black07},function(e){return e.active?e.theme.colours.white:e.theme.colours.black30}),d=o.styled.p(l||(l=r(["\n margin-left: 6px;\n"],["\n margin-left: 6px;\n"])))},function(e,t,n){"use strict";var r=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var i=n(0),o=n(24),a=n(1);t.default=a.withTheme(function(e){var t=e.items,n=e.onItemSelect,r=e.selectedItemIndex,a=e.onItemStarToggled;e.theme;return i.createElement(y,null,t.map(function(e,t){return i.createElement(v,{key:e.id,active:r===t,onClick:function(){return n(t)}},i.createElement(x,null,i.createElement(o.Star,{onClick:function(){return a(e.id)},stroke:e.starred?void 0:"rgb(221,171,0)",fill:e.starred?"rgb(221,171,0)":void 0,strokeWidth:.5,width:25,height:25}),i.createElement(b,null,i.createElement(C,null,e.operationName||e.queryTypes.firstOperationName||"New Session"),e.queryTypes.query&&i.createElement(D,null,"Q"),e.queryTypes.mutation&&i.createElement(w,null,"M"),e.queryTypes.subscription&&i.createElement(S,null,"S"))),i.createElement(x,null,e.date&&i.createElement(k,null,"function"===typeof e.date.getMonth&&e.date.getMonth()+1,"/",e.date.getDate(),"/",e.date.getFullYear().toString().slice(2,4))))}).toArray().map(function(e){return e[1]}))});var s,u,c,l,p,f,d,h,m,g,y=a.styled.div(s||(s=r(["\n overflow-y: scroll;\n max-height: calc(100vh - 121px);\n"],["\n overflow-y: scroll;\n max-height: calc(100vh - 121px);\n"]))),v=a.styled("div")(u||(u=r(["\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 25px 20px;\n cursor: pointer;\n border-bottom: 1px solid;\n border-color: ",";\n background: ",";\n"],["\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 25px 20px;\n cursor: pointer;\n border-bottom: 1px solid;\n border-color: ",";\n background: ",";\n"])),function(e){return e.theme.colours.black10},function(e){return e.active?e.theme.colours.black04:e.theme.colours.white}),b=a.styled.div(c||(c=r(["\n display: flex;\n align-items: center;\n margin-left: 20px;\n"],["\n display: flex;\n align-items: center;\n margin-left: 20px;\n"]))),x=a.styled.div(l||(l=r(["\n display: flex;\n align-items: center;\n"],["\n display: flex;\n align-items: center;\n"]))),C=a.styled.p(p||(p=r(["\n font-weight: 300;\n font-size: 20px;\n margin-right: 16px;\n"],["\n font-weight: 300;\n font-size: 20px;\n margin-right: 16px;\n"]))),E=a.styled.div(f||(f=r(["\n height: 21px;\n width: 21px;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-right: 4px;\n border-radius: 2px;\n font-weight: 700;\n font-size: 12px;\n color: ",";\n"],["\n height: 21px;\n width: 21px;\n display: flex;\n justify-content: center;\n align-items: center;\n margin-right: 4px;\n border-radius: 2px;\n font-weight: 700;\n font-size: 12px;\n color: ",";\n"])),function(e){return e.theme.colours.white}),D=a.styled(E)(d||(d=r(["\n background: ",";\n"],["\n background: ",";\n"])),function(e){return e.theme.colours.blue}),w=a.styled(E)(h||(h=r(["\n background: ",";\n"],["\n background: ",";\n"])),function(e){return e.theme.colours.orange}),S=a.styled(E)(m||(m=r(["\n background: ",";\n"],["\n background: ",";\n"])),function(e){return e.theme.colours.purple}),k=a.styled.time(g||(g=r(["\n color: ",";\n font-size: 14px;\n margin-left: 16px;\n"],["\n color: ",";\n font-size: 14px;\n margin-left: 16px;\n"])),function(e){return e.theme.colours.black40})},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(8),i=n(17);t.getHistory=r.createSelector([i.getSelectedWorkspace],function(e){return e.history})},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(24),s=n(1),u=n(16),c=n(9),l=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(){return o.createElement(d,null,o.createElement(h,null,o.createElement(a.SettingsIcon,{width:23,height:23,onClick:this.props.onClick,title:"Settings"})))},t}(o.Component);t.default=c.connect(null,{onClick:u.openSettingsTab})(l);var p,f,d=s.styled.div(p||(p=i(["\n position: absolute;\n z-index: 1005;\n right: 20px;\n top: 17px;\n"],["\n position: absolute;\n z-index: 1005;\n right: 20px;\n top: 17px;\n"]))),h=s.styled.div(f||(f=i(["\n position: relative;\n cursor: pointer;\n\n svg {\n fill: ",";\n transition: 0.1s linear fill;\n }\n\n &:hover {\n svg {\n fill: ",";\n }\n }\n"],["\n position: relative;\n cursor: pointer;\n\n svg {\n fill: ",";\n transition: 0.1s linear fill;\n }\n\n &:hover {\n svg {\n fill: ",";\n }\n }\n"])),function(e){return e.theme.editorColours.icon},function(e){return e.theme.editorColours.iconHover})},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(1),s=n(142),u=n(710),c=n(9),l=n(8),p=n(97),f=n(75),d=n(16),h=n(17),m=n(37),g=function(e){function t(){var t=null!==e&&e.apply(this,arguments)||this;return t.handleKeydown=function(e){"s"===e.key&&e.metaKey&&(e.preventDefault(),t.props.onSave())},t}return r(t,e),t.prototype.componentDidMount=function(){window.addEventListener("keydown",this.handleKeydown,!0)},t.prototype.render=function(){var e=this.props.isConfig;return o.createElement(m.Container,null,o.createElement(D,null,o.createElement(m.default,null,o.createElement(u.ConfigEditor,{value:this.props.value,onEdit:this.props.onChange,onRunQuery:this.props.onSave,isYaml:this.props.isYaml,readOnly:this.props.readOnly}),o.createElement(S,null,window.version)),!this.props.readOnly&&o.createElement(w,null,o.createElement(s.Button,{onClick:this.props.onSave},"Save ",e?"Config":"Settings"))))},t}(o.Component);t.SettingsEditor=g;var y=l.createStructuredSelector({value:h.getSettingsString}),v=function(e){function t(t){var n=e.call(this,t)||this;return n.handleChange=function(e){n.setState({value:e}),n.props.editSettings()},n.handleSave=function(){n.props.onSave(n.state.value),n.props.saveSettings()},n.state={value:t.value},n}return r(t,e),t.prototype.componentWillReceiveProps=function(e){e.value!==this.props.value&&this.setState({value:e.value})},t.prototype.render=function(){return o.createElement(g,{value:this.state.value,onChange:this.handleChange,onSave:this.handleSave})},t}(o.Component);t.PlaygroundSettingsEditor=c.connect(y,{onSave:f.setSettingsString,editSettings:d.editSettings,saveSettings:d.saveSettings})(v);var b=l.createStructuredSelector({value:p.getConfigString});t.GraphQLConfigEditor=c.connect(b,{onChange:f.setConfigString})(g);var x,C,E,D=a.styled.div(x||(x=i(["\n background: ",";\n position: relative;\n display: flex;\n flex-flow: column;\n flex: 1 1 0;\n\n .CodeMirror {\n background: ",";\n .CodeMirror-code {\n color: rgba(255, 255, 255, 0.7);\n }\n .cm-atom {\n color: rgba(42, 126, 210, 1);\n }\n }\n"],["\n background: ",";\n position: relative;\n display: flex;\n flex-flow: column;\n flex: 1 1 0;\n\n .CodeMirror {\n background: ",";\n .CodeMirror-code {\n color: rgba(255, 255, 255, 0.7);\n }\n .cm-atom {\n color: rgba(42, 126, 210, 1);\n }\n }\n"])),function(e){return e.theme.editorColours.resultBackground},function(e){return e.theme.editorColours.resultBackground}),w=a.styled.div(C||(C=i(["\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 2;\n"],["\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 2;\n"]))),S=a.styled.span(E||(E=i(["\n position: absolute;\n right: 20px;\n bottom: 17px;\n color: ",";\n font-weight: 700;\n margin-right: 14px;\n"],["\n position: absolute;\n right: 20px;\n bottom: 17px;\n color: ",";\n font-weight: 700;\n margin-right: 14px;\n"])),function(e){return e.theme.editorColours.textInactive})},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(37),s=n(1),u=function(e){function t(t){var n=e.call(this,t)||this;return n.setNode=function(e){n.node=e},n.onKeyUp=function(e,t){var r=t.keyCode;(r>=65&&r<=90||!t.shiftKey&&r>=48&&r<=57||t.shiftKey&&189===r||t.shiftKey&&222===r)&&n.editor.execCommand("autocomplete")},n.onEdit=function(){n.ignoreChangeEvent||(n.cachedValue=n.editor.getValue(),n.props.onEdit&&n.props.onEdit(n.cachedValue))},n.cachedValue=t.value||"",n}return r(t,e),t.prototype.componentDidMount=function(){var e=this,t=n(2);n(137),n(69),n(138),n(70),n(89),n(139),n(38),n(90),n(39),n(91),n(711),n(286),n(287),n(288),this.editor=t(this.node,{value:this.props.value||"",lineNumbers:!0,tabSize:2,mode:this.props.isYaml?"yaml":"graphql-variables",theme:this.props.editorTheme||"graphiql",keyMap:"sublime",autoCloseBrackets:!0,matchBrackets:!0,showCursorWhenSelecting:!0,readOnly:!!this.props.readOnly&&"nocursor",foldGutter:{minFoldSize:4},gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],extraKeys:{"Cmd-Space":function(){return e.editor.showHint({completeSingle:!1})},"Ctrl-Space":function(){return e.editor.showHint({completeSingle:!1})},"Alt-Space":function(){return e.editor.showHint({completeSingle:!1})},"Shift-Space":function(){return e.editor.showHint({completeSingle:!1})},"Cmd-Enter":function(){e.props.onRunQuery&&e.props.onRunQuery()},"Ctrl-Enter":function(){e.props.onRunQuery&&e.props.onRunQuery()},"Shift-Ctrl-P":function(){e.props.onPrettifyQuery&&e.props.onPrettifyQuery()},"Cmd-F":"findPersistent","Ctrl-F":"findPersistent","Ctrl-Left":"goSubwordLeft","Ctrl-Right":"goSubwordRight","Alt-Left":"goGroupLeft","Alt-Right":"goGroupRight"}}),this.editor.on("change",this.onEdit),this.editor.on("keyup",this.onKeyUp)},t.prototype.componentDidUpdate=function(e){this.ignoreChangeEvent=!0,this.props.value!==e.value&&this.props.value!==this.cachedValue&&(this.cachedValue=this.props.value,this.editor.setValue(this.props.value)),this.ignoreChangeEvent=!1},t.prototype.componentWillUnmount=function(){this.editor.off("change",this.onEdit),this.editor.off("keyup",this.onKeyUp),this.editor=null},t.prototype.render=function(){return o.createElement(a.default,null,o.createElement(l,{ref:this.setNode}))},t.prototype.getCodeMirror=function(){return this.editor},t.prototype.getClientHeight=function(){return this.node&&this.node.clientHeight},t}(o.Component);t.ConfigEditor=u;var c,l=s.styled.div(c||(c=i(["\n flex: 1;\n height: 100%;\n position: relative;\n .CodeMirror-linenumbers {\n background: ",";\n }\n"],["\n flex: 1;\n height: 100%;\n position: relative;\n .CodeMirror-linenumbers {\n background: ",";\n }\n"])),function(e){return e.theme.editorColours.resultBackground})},function(e,t,n){!function(e){e(n(2))}(function(e){"use strict";e.defineMode("yaml",function(){var e=["true","false","on","off","yes","no"],t=new RegExp("\\b(("+e.join(")|(")+"))$","i");return{token:function(e,n){var r=e.peek(),i=n.escaped;if(n.escaped=!1,"#"==r&&(0==e.pos||/\s/.test(e.string.charAt(e.pos-1))))return e.skipToEnd(),"comment";if(e.match(/^('([^']|\\.)*'?|"([^"]|\\.)*"?)/))return"string";if(n.literal&&e.indentation()>n.keyCol)return e.skipToEnd(),"string";if(n.literal&&(n.literal=!1),e.sol()){if(n.keyCol=0,n.pair=!1,n.pairStart=!1,e.match(/---/))return"def";if(e.match(/\.\.\./))return"def";if(e.match(/\s*-\s+/))return"meta"}if(e.match(/^(\{|\}|\[|\])/))return"{"==r?n.inlinePairs++:"}"==r?n.inlinePairs--:"["==r?n.inlineList++:n.inlineList--,"meta";if(n.inlineList>0&&!i&&","==r)return e.next(),"meta";if(n.inlinePairs>0&&!i&&","==r)return n.keyCol=0,n.pair=!1,n.pairStart=!1,e.next(),"meta";if(n.pairStart){if(e.match(/^\s*(\||\>)\s*/))return n.literal=!0,"meta";if(e.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i))return"variable-2";if(0==n.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?$/))return"number";if(n.inlinePairs>0&&e.match(/^\s*-?[0-9\.\,]+\s?(?=(,|}))/))return"number";if(e.match(t))return"keyword"}return!n.pair&&e.match(/^\s*(?:[,\[\]{}&*!|>'"%@`][^\s'":]|[^,\[\]{}#&*!|>'"%@`])[^#]*?(?=\s*:($|\s))/)?(n.pair=!0,n.keyCol=e.indentation(),"atom"):n.pair&&e.match(/^:\s*/)?(n.pairStart=!0,"meta"):(n.pairStart=!1,n.escaped="\\"==r,e.next(),null)},startState:function(){return{pair:!1,pairStart:!1,keyCol:0,inlinePairs:0,inlineList:0,literal:!1,escaped:!1}},lineComment:"#"}}),e.defineMIME("text/x-yaml","yaml"),e.defineMIME("text/yaml","yaml")})},function(e,t,n){"use strict";var r=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),i=function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(1),s=n(133),u=n(8),c=n(12),l=n(16),p=n(37),f=n(9),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return r(t,e),t.prototype.render=function(){return o.createElement(p.Container,null,o.createElement(y,null,o.createElement(p.default,null,o.createElement(v,null,o.createElement(s.QueryEditor,{value:this.props.value,onChange:this.props.onChange})))))},t}(o.Component),h=u.createStructuredSelector({value:c.getFile});t.default=f.connect(h,{onChange:l.editFile})(d);var m,g,y=a.styled.div(m||(m=i(["\n background: ",";\n position: relative;\n .variable-editor {\n height: 100% !important;\n }\n .CodeMirror {\n background: none !important;\n .CodeMirror-code {\n color: rgba(255, 255, 255, 0.7);\n }\n .cm-atom {\n color: rgba(42, 126, 210, 1);\n }\n }\n"],["\n background: ",";\n position: relative;\n .variable-editor {\n height: 100% !important;\n }\n .CodeMirror {\n background: none !important;\n .CodeMirror-code {\n color: rgba(255, 255, 255, 0.7);\n }\n .cm-atom {\n color: rgba(42, 126, 210, 1);\n }\n }\n"])),function(e){return e.theme.editorColours.resultBackground}),v=a.styled.div(g||(g=i(["\n display: flex;\n flex-direction: column;\n flex: 1;\n"],["\n display: flex;\n flex-direction: column;\n flex: 1;\n"])))},function(e,t){e.exports={name:"graphql-playground-react",version:"1.7.20",main:"./lib/lib.js",typings:"./lib/lib.d.ts",description:"GraphQL IDE for better development workflows (GraphQL Subscriptions, interactive docs & collaboration).",contributors:["Tim Suchanek ","Johannes Schickling ","Lukas Huvar "],repository:{type:"git",url:"http://github.com/graphcool/graphql-playground.git"},license:"MIT",scripts:{start:"node scripts/start.js","start:analyze":"ANALYZE_BUNDLE=true node scripts/start.js","start:graphql-bin":"ACTIVE_APP=graphqlbin node scripts/start.js",prepublishOnly:"yarn build",build:"rimraf dist build dist && yarn build-app && yarn build-package",tsc:"tsc -p tsconfig.build.json","build-package":"rimraf lib build/dist && npm run tsc && babel lib -d lib && cp -r ./src/assets/ ./lib/assets/ && cd lib && rimraf *.jsx;","build-app":"node scripts/build.js",test:"jest",bundlesize:"bundlesize",bump:"npm version patch --no-git-tag-version && git add package.json","graphql-faker":"graphql-faker ./tests/schema.faker.graphql",lint:'tslint "src/**/*.ts{,x}"',precommit:"lint-staged",prettier:"prettier --single-quote --no-semi --trailing-comma all --write *.{ts,tsx} 'src/**/*.{ts,tsx}'"},files:["build","lib","playground.css"],bundlesize:[{path:"build/static/js/index.js",maxSize:"674 kB"}],devDependencies:{"@types/deasync":"0.1.0","@types/jest":"22.2.3","@types/node":"10.1.4","@types/react":"16.3.14","@types/zen-observable":"^0.5.3","babel-cli":"6.26.0","babel-core":"6.26.3","babel-loader":"7.1.4","babel-plugin-styled-components":"^1.8.0","babel-preset-es2015":"6.24.1","babel-preset-es2016":"6.24.1","babel-preset-react":"6.24.1","babel-preset-stage-3":"6.24.1",bundlesize:"^0.17.0","case-sensitive-paths-webpack-plugin":"2.1.2",chalk:"2.4.1","connect-history-api-fallback":"1.5.0","cross-spawn":"6.0.5","css-loader":"0.28.11","detect-port":"1.2.3",dotenv:"5.0.1",enzyme:"^3.3.0","enzyme-adapter-react-16":"^1.1.1","enzyme-to-json":"^3.3.4","extract-text-webpack-plugin":"3.0.2","file-loader":"1.1.11",filesize:"3.6.1","fs-extra":"5.0.0","graphql-playground-html":"1.5.6","gzip-size":"4.1.0","html-webpack-plugin":"2.30.1","http-proxy-middleware":"0.17.4",husky:"0.14.3",jest:"22.1.4","jest-localstorage-mock":"^2.2.0","json-loader":"0.5.7","lint-staged":"6.1.0","node-noop":"1.0.0","object-assign":"4.1.1",promise:"8.0.1","raw-loader":"0.5.1","react-dev-utils":"5.0.1","recursive-readdir":"2.2.2",rimraf:"2.6.2","source-map-loader":"0.2.3","strip-ansi":"4.0.0","style-loader":"0.20.1","svg-inline-loader":"0.8.0","sw-precache-webpack-plugin":"0.11.5","ts-loader":"3.4.0",tslint:"5.10.0","tslint-graphcool-frontend":"0.0.3","tslint-loader":"3.6.0",typescript:"^3.0.1","typescript-styled-plugin":"^0.11.0","url-loader":"0.6.2",webpack:"3.10.0","webpack-dev-server":"2.11.1","webpack-manifest-plugin":"1.3.2","why-did-you-update":"0.1.1"},dependencies:{"@types/lru-cache":"^4.1.1","apollo-link":"^1.0.7","apollo-link-http":"^1.3.2","apollo-link-ws":"1.0.8","calculate-size":"^1.1.1",codemirror:"^5.38.0","codemirror-graphql":"timsuchanek/codemirror-graphql#details-fix","copy-to-clipboard":"^3.0.8",cryptiles:"4.1.2",cuid:"^1.3.8",graphiql:"^0.11.2",graphql:"^0.11.7",immutable:"^4.0.0-rc.9","isomorphic-fetch":"^2.2.1","js-yaml":"^3.10.0","json-stable-stringify":"^1.0.1",keycode:"^2.1.9",lodash:"^4.17.11","lodash.debounce":"^4.0.8","markdown-it":"^8.4.1",marked:"^0.3.19",prettier:"^1.13.0","prop-types":"^15.6.0","query-string":"5",react:"^16.3.1","react-addons-shallow-compare":"^15.6.2","react-codemirror":"^1.0.0","react-copy-to-clipboard":"^5.0.1","react-display-name":"^0.2.3","react-dom":"^16.3.1","react-helmet":"^5.2.0","react-input-autosize":"^2.2.1","react-modal":"^3.1.11","react-redux":"^5.0.6","react-router-dom":"^4.2.2","react-sortable-hoc":"^0.8.3","react-transition-group":"^2.2.1","react-virtualized":"^9.12.0",redux:"^3.7.2","redux-actions":"^2.2.1","redux-immutable":"^4.0.0","redux-localstorage":"rc","redux-localstorage-debounce":"^0.1.0","redux-localstorage-filter":"^0.1.1","redux-saga":"^0.16.0",reselect:"^3.0.1","seamless-immutable":"^7.0.1","styled-components":"^4.0.0","subscriptions-transport-ws":"^0.9.5","utility-types":"^1.0.0","webpack-bundle-analyzer":"^2.9.2","zen-observable":"^0.7.1"},"lint-staged":{"*.{ts,tsx}":["prettier --single-quote --no-semi --write","tslint","git add"],gitDir:"../../"},jest:{collectCoverageFrom:["src/**/*.{ts,tsx}"],setupFiles:["/config/polyfills.js"],testPathIgnorePatterns:["[/\\\\](build|docs|node_modules)[/\\\\]"],testEnvironment:"node",testURL:"http://localhost",transform:{"^.+\\.css$":"/config/jest/cssTransform.js","^.+\\.tsx?$":"/config/jest/typescriptTransform.js","^(?!.*\\.(css|json)$)":"/config/jest/fileTransform.js"},transformIgnorePatterns:["[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"],moduleNameMapper:{"^react-native$":"react-native-web"},moduleFileExtensions:["ts","tsx","js"],testRegex:"(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"}}},function(e,t,n){"use strict";var r=function(e,t,n,r){return new(n||(n=Promise))(function(i,o){function a(e){try{u(r.next(e))}catch(e){o(e)}}function s(e){try{u(r.throw(e))}catch(e){o(e)}}function u(e){e.done?i(e.value):new n(function(t){t(e.value)}).then(a,s)}u((r=r.apply(e,t||[])).next())})},i=function(e,t){function n(e){return function(t){return r([e,t])}}function r(n){if(i)throw new TypeError("Generator is already executing.");for(;u;)try{if(i=1,o&&(a=2&n[0]?o.return:n[0]?o.throw||((a=o.return)&&a.call(o),0):o.next)&&!(a=a.call(o,n[1])).done)return a;switch(o=0,a&&(n=[2&n[0],a.value]),n[0]){case 0:case 1:a=n;break;case 4:return u.label++,{value:n[1],done:!1};case 5:u.label++,o=n[1],n=[0];continue;case 7:n=u.ops.pop(),u.trys.pop();continue;default:if(a=u.trys,!(a=a.length>0&&a[a.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!a||n[1]>a[0]&&n[1]=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function a(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t}function s(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0,t.Helmet=void 0;var u=Object.assign||function(e){for(var t=1;t elements are self-closing and can not contain children. Refer to our API for more information.")},n.prototype.flattenArrayTypeChildren=function(e){var t,n=e.child,r=e.arrayTypeChildren,i=e.newChildProps,o=e.nestedChildren;return u({},r,(t={},t[n.type]=[].concat(r[n.type]||[],[u({},i,this.mapNestedChildrenToProps(n,o))]),t))},n.prototype.mapObjectTypeChildren=function(e){var t,n,r=e.child,i=e.newProps,o=e.newChildProps,a=e.nestedChildren;switch(r.type){case b.TAG_NAMES.TITLE:return u({},i,(t={},t[r.type]=a,t.titleAttributes=u({},o),t));case b.TAG_NAMES.BODY:return u({},i,{bodyAttributes:u({},o)});case b.TAG_NAMES.HTML:return u({},i,{htmlAttributes:u({},o)})}return u({},i,(n={},n[r.type]=u({},o),n))},n.prototype.mapArrayTypeChildrenToProps=function(e,t){var n=u({},t);return Object.keys(e).forEach(function(t){var r;n=u({},n,(r={},r[t]=e[t],r))}),n},n.prototype.warnOnInvalidChildren=function(e,t){return!0},n.prototype.mapChildrenToProps=function(e,t){var n=this,r={};return p.default.Children.forEach(e,function(e){if(e&&e.props){var o=e.props,a=o.children,s=i(o,["children"]),u=(0,v.convertReactPropstoHtmlAttributes)(s);switch(n.warnOnInvalidChildren(e,a),e.type){case b.TAG_NAMES.LINK:case b.TAG_NAMES.META:case b.TAG_NAMES.NOSCRIPT:case b.TAG_NAMES.SCRIPT:case b.TAG_NAMES.STYLE:r=n.flattenArrayTypeChildren({child:e,arrayTypeChildren:r,newChildProps:u,nestedChildren:a});break;default:t=n.mapObjectTypeChildren({child:e,newProps:t,newChildProps:u,nestedChildren:a})}}}),t=this.mapArrayTypeChildrenToProps(r,t)},n.prototype.render=function(){var t=this.props,n=t.children,r=i(t,["children"]),o=u({},r);return n&&(o=this.mapChildrenToProps(n,o)),p.default.createElement(e,o)},c(n,null,[{key:"canUseDOM",set:function(t){e.canUseDOM=t}}]),n}(p.default.Component),t.propTypes={base:d.default.object,bodyAttributes:d.default.object,children:d.default.oneOfType([d.default.arrayOf(d.default.node),d.default.node]),defaultTitle:d.default.string,defer:d.default.bool,encodeSpecialCharacters:d.default.bool,htmlAttributes:d.default.object,link:d.default.arrayOf(d.default.object),meta:d.default.arrayOf(d.default.object),noscript:d.default.arrayOf(d.default.object),onChangeClientState:d.default.func,script:d.default.arrayOf(d.default.object),style:d.default.arrayOf(d.default.object),title:d.default.string,titleAttributes:d.default.object,titleTemplate:d.default.string},t.defaultProps={defer:!0,encodeSpecialCharacters:!0},t.peek=e.peek,t.rewind=function(){var t=e.rewind();return t||(t=(0,v.mapStateOnServer)({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}})),t},n}(C);E.renderStatic=E.rewind,t.Helmet=E,t.default=E},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t}function a(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var s=n(0),u=r(s),c=n(258),l=r(c),p=n(717),f=r(p);e.exports=function(e,t,n){function r(e){return e.displayName||e.name||"Component"}if("function"!==typeof e)throw new Error("Expected reducePropsToState to be a function.");if("function"!==typeof t)throw new Error("Expected handleStateChangeOnClient to be a function.");if("undefined"!==typeof n&&"function"!==typeof n)throw new Error("Expected mapStateOnServer to either be undefined or a function.");return function(c){function p(){h=e(d.map(function(e){return e.props})),m.canUseDOM?t(h):n&&(h=n(h))}if("function"!==typeof c)throw new Error("Expected WrappedComponent to be a React component.");var d=[],h=void 0,m=function(e){function t(){return i(this,t),o(this,e.apply(this,arguments))}return a(t,e),t.peek=function(){return h},t.rewind=function(){if(t.canUseDOM)throw new Error("You may only call rewind() on the server. Call peek() to read the current state.");var e=h;return h=void 0,d=[],e},t.prototype.shouldComponentUpdate=function(e){return!(0,f.default)(e,this.props)},t.prototype.componentWillMount=function(){d.push(this),p()},t.prototype.componentDidUpdate=function(){p()},t.prototype.componentWillUnmount=function(){var e=d.indexOf(this);d.splice(e,1),p()},t.prototype.render=function(){return u.default.createElement(c,this.props)},t}(s.Component);return m.displayName="SideEffect("+r(c)+")",m.canUseDOM=l.default.canUseDOM,m}}},function(e,t){e.exports=function(e,t,n,r){var i=n?n.call(r,e,t):void 0;if(void 0!==i)return!!i;if(e===t)return!0;if("object"!==typeof e||!e||"object"!==typeof t||!t)return!1;var o=Object.keys(e),a=Object.keys(t);if(o.length!==a.length)return!1;for(var s=Object.prototype.hasOwnProperty.bind(t),u=0;u0&&"number"!==typeof e[0]))}function o(e,t,n){var o,l;if(r(e)||r(t))return!1;if(e.prototype!==t.prototype)return!1;if(u(e))return!!u(t)&&(e=a.call(e),t=a.call(t),c(e,t,n));if(i(e)){if(!i(t))return!1;if(e.length!==t.length)return!1;for(o=0;o=0;o--)if(p[o]!=f[o])return!1;for(o=p.length-1;o>=0;o--)if(l=p[o],!c(e[l],t[l],n))return!1;return typeof e===typeof t}var a=Array.prototype.slice,s=n(719),u=n(720),c=e.exports=function(e,t,n){return n||(n={}),e===t||(e instanceof Date&&t instanceof Date?e.getTime()===t.getTime():!e||!t||"object"!=typeof e&&"object"!=typeof t?n.strict?e===t:e==t:o(e,t,n))}},function(e,t){function n(e){var t=[];for(var n in e)t.push(n);return t}t=e.exports="function"===typeof Object.keys?Object.keys:n,t.shim=n},function(e,t){function n(e){return"[object Arguments]"==Object.prototype.toString.call(e)}function r(e){return e&&"object"==typeof e&&"number"==typeof e.length&&Object.prototype.hasOwnProperty.call(e,"callee")&&!Object.prototype.propertyIsEnumerable.call(e,"callee")||!1}var i="[object Arguments]"==function(){return Object.prototype.toString.call(arguments)}();t=e.exports=i?n:r,t.supported=n,t.unsupported=r},function(e,t,n){(function(e){function r(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0,t.warn=t.requestAnimationFrame=t.reducePropsToState=t.mapStateOnServer=t.handleClientStateChange=t.convertReactPropstoHtmlAttributes=void 0;var i="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o=Object.assign||function(e){for(var t=1;t1&&void 0!==arguments[1])||arguments[1])?String(e):String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")},f=function(e){var t=y(e,l.TAG_NAMES.TITLE),n=y(e,l.HELMET_PROPS.TITLE_TEMPLATE);if(n&&t)return n.replace(/%s/g,function(){return t});var r=y(e,l.HELMET_PROPS.DEFAULT_TITLE);return t||r||void 0},d=function(e){return y(e,l.HELMET_PROPS.ON_CHANGE_CLIENT_STATE)||function(){}},h=function(e,t){return t.filter(function(t){return"undefined"!==typeof t[e]}).map(function(t){return t[e]}).reduce(function(e,t){return o({},e,t)},{})},m=function(e,t){return t.filter(function(e){return"undefined"!==typeof e[l.TAG_NAMES.BASE]}).map(function(e){return e[l.TAG_NAMES.BASE]}).reverse().reduce(function(t,n){if(!t.length)for(var r=Object.keys(n),i=0;i=0;n--){var r=e[n];if(r.hasOwnProperty(t))return r[t]}return null},v=function(e){return{baseTag:m([l.TAG_PROPERTIES.HREF],e),bodyAttributes:h(l.ATTRIBUTE_NAMES.BODY,e),defer:y(e,l.HELMET_PROPS.DEFER),encode:y(e,l.HELMET_PROPS.ENCODE_SPECIAL_CHARACTERS),htmlAttributes:h(l.ATTRIBUTE_NAMES.HTML,e),linkTags:g(l.TAG_NAMES.LINK,[l.TAG_PROPERTIES.REL,l.TAG_PROPERTIES.HREF],e),metaTags:g(l.TAG_NAMES.META,[l.TAG_PROPERTIES.NAME,l.TAG_PROPERTIES.CHARSET,l.TAG_PROPERTIES.HTTPEQUIV,l.TAG_PROPERTIES.PROPERTY,l.TAG_PROPERTIES.ITEM_PROP],e),noscriptTags:g(l.TAG_NAMES.NOSCRIPT,[l.TAG_PROPERTIES.INNER_HTML],e),onChangeClientState:d(e),scriptTags:g(l.TAG_NAMES.SCRIPT,[l.TAG_PROPERTIES.SRC,l.TAG_PROPERTIES.INNER_HTML],e),styleTags:g(l.TAG_NAMES.STYLE,[l.TAG_PROPERTIES.CSS_TEXT],e),title:f(e),titleAttributes:h(l.ATTRIBUTE_NAMES.TITLE,e)}},b=function(){var e=Date.now();return function(t){var n=Date.now();n-e>16?(e=n,t(n)):setTimeout(function(){b(t)},0)}}(),x=function(e){return clearTimeout(e)},C="undefined"!==typeof window?window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||b:e.requestAnimationFrame||b,E="undefined"!==typeof window?window.cancelAnimationFrame||window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||x:e.cancelAnimationFrame||x,D=function(e){return console&&"function"===typeof console.warn&&console.warn(e)},w=null,S=function(e){w&&E(w),e.defer?w=C(function(){k(e,function(){w=null})}):(k(e),w=null)},k=function(e,t){var n=e.baseTag,r=e.bodyAttributes,i=e.htmlAttributes,o=e.linkTags,a=e.metaTags,s=e.noscriptTags,u=e.onChangeClientState,c=e.scriptTags,p=e.styleTags,f=e.title,d=e.titleAttributes;T(l.TAG_NAMES.BODY,r),T(l.TAG_NAMES.HTML,i),_(f,d);var h={baseTag:O(l.TAG_NAMES.BASE,n),linkTags:O(l.TAG_NAMES.LINK,o),metaTags:O(l.TAG_NAMES.META,a),noscriptTags:O(l.TAG_NAMES.NOSCRIPT,s),scriptTags:O(l.TAG_NAMES.SCRIPT,c),styleTags:O(l.TAG_NAMES.STYLE,p)},m={},g={};Object.keys(h).forEach(function(e){var t=h[e],n=t.newTags,r=t.oldTags;n.length&&(m[e]=n),r.length&&(g[e]=h[e].oldTags)}),t&&t(),u(e,m,g)},A=function(e){return Array.isArray(e)?e.join(""):e},_=function(e,t){"undefined"!==typeof e&&document.title!==e&&(document.title=A(e)),T(l.TAG_NAMES.TITLE,t)},T=function(e,t){var n=document.getElementsByTagName(e)[0];if(n){for(var r=n.getAttribute(l.HELMET_ATTRIBUTE),i=r?r.split(","):[],o=[].concat(i),a=Object.keys(t),s=0;s=0;f--)n.removeAttribute(o[f]);i.length===o.length?n.removeAttribute(l.HELMET_ATTRIBUTE):n.getAttribute(l.HELMET_ATTRIBUTE)!==a.join(",")&&n.setAttribute(l.HELMET_ATTRIBUTE,a.join(","))}},O=function(e,t){var n=document.head||document.querySelector(l.TAG_NAMES.HEAD),r=n.querySelectorAll(e+"["+l.HELMET_ATTRIBUTE+"]"),i=Array.prototype.slice.call(r),o=[],a=void 0;return t&&t.length&&t.forEach(function(t){var n=document.createElement(e);for(var r in t)if(t.hasOwnProperty(r))if(r===l.TAG_PROPERTIES.INNER_HTML)n.innerHTML=t.innerHTML;else if(r===l.TAG_PROPERTIES.CSS_TEXT)n.styleSheet?n.styleSheet.cssText=t.cssText:n.appendChild(document.createTextNode(t.cssText));else{var s="undefined"===typeof t[r]?"":t[r];n.setAttribute(r,s)}n.setAttribute(l.HELMET_ATTRIBUTE,"true"),i.some(function(e,t){return a=t,n.isEqualNode(e)})?i.splice(a,1):o.push(n)}),i.forEach(function(e){return e.parentNode.removeChild(e)}),o.forEach(function(e){return n.appendChild(e)}),{oldTags:i,newTags:o}},F=function(e){return Object.keys(e).reduce(function(t,n){var r="undefined"!==typeof e[n]?n+'="'+e[n]+'"':""+n;return t?t+" "+r:r},"")},N=function(e,t,n,r){var i=F(n),o=A(t);return i?"<"+e+" "+l.HELMET_ATTRIBUTE+'="true" '+i+">"+p(o,r)+"":"<"+e+" "+l.HELMET_ATTRIBUTE+'="true">'+p(o,r)+""},I=function(e,t,n){return t.reduce(function(t,r){var i=Object.keys(r).filter(function(e){return!(e===l.TAG_PROPERTIES.INNER_HTML||e===l.TAG_PROPERTIES.CSS_TEXT)}).reduce(function(e,t){var i="undefined"===typeof r[t]?t:t+'="'+p(r[t],n)+'"';return e?e+" "+i:i},""),o=r.innerHTML||r.cssText||"",a=-1===l.SELF_CLOSING_TAGS.indexOf(e);return t+"<"+e+" "+l.HELMET_ATTRIBUTE+'="true" '+i+(a?"/>":">"+o+"")},"")},L=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(e).reduce(function(t,n){return t[l.REACT_TAG_MAP[n]||n]=e[n],t},t)},P=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return Object.keys(e).reduce(function(t,n){return t[l.HTML_TAG_MAP[n]||n]=e[n],t},t)},M=function(e,t,n){var r,i=(r={key:t},r[l.HELMET_ATTRIBUTE]=!0,r),o=L(n,i);return[s.default.createElement(l.TAG_NAMES.TITLE,o,t)]},j=function(e,t){return t.map(function(t,n){var r,i=(r={key:n},r[l.HELMET_ATTRIBUTE]=!0,r);return Object.keys(t).forEach(function(e){var n=l.REACT_TAG_MAP[e]||e;if(n===l.TAG_PROPERTIES.INNER_HTML||n===l.TAG_PROPERTIES.CSS_TEXT){var r=t.innerHTML||t.cssText;i.dangerouslySetInnerHTML={__html:r}}else i[n]=t[e]}),s.default.createElement(e,i)})},R=function(e,t,n){switch(e){case l.TAG_NAMES.TITLE:return{toComponent:function(){return M(0,t.title,t.titleAttributes)},toString:function(){return N(e,t.title,t.titleAttributes,n)}};case l.ATTRIBUTE_NAMES.BODY:case l.ATTRIBUTE_NAMES.HTML:return{toComponent:function(){return L(t)},toString:function(){return F(t)}};default:return{toComponent:function(){return j(e,t)},toString:function(){return I(e,t,n)}}}},B=function(e){var t=e.baseTag,n=e.bodyAttributes,r=e.encode,i=e.htmlAttributes,o=e.linkTags,a=e.metaTags,s=e.noscriptTags,u=e.scriptTags,c=e.styleTags,p=e.title,f=void 0===p?"":p,d=e.titleAttributes;return{base:R(l.TAG_NAMES.BASE,t,r),bodyAttributes:R(l.ATTRIBUTE_NAMES.BODY,n,r),htmlAttributes:R(l.ATTRIBUTE_NAMES.HTML,i,r),link:R(l.TAG_NAMES.LINK,o,r),meta:R(l.TAG_NAMES.META,a,r),noscript:R(l.TAG_NAMES.NOSCRIPT,s,r),script:R(l.TAG_NAMES.SCRIPT,u,r),style:R(l.TAG_NAMES.STYLE,c,r),title:R(l.TAG_NAMES.TITLE,{title:f,titleAttributes:d},r)}};t.convertReactPropstoHtmlAttributes=P,t.handleClientStateChange=S,t.mapStateOnServer=B,t.reducePropsToState=v,t.requestAnimationFrame=C,t.warn=D}).call(t,n(11))},function(e,t,n){"use strict";var r=n(723);e.exports=r},function(e,t,n){"use strict";function r(e){return function(){throw new Error("Function "+e+" is deprecated and cannot be used.")}}var i=n(724),o=n(747);e.exports.Type=n(15),e.exports.Schema=n(53),e.exports.FAILSAFE_SCHEMA=n(148),e.exports.JSON_SCHEMA=n(304),e.exports.CORE_SCHEMA=n(303),e.exports.DEFAULT_SAFE_SCHEMA=n(73),e.exports.DEFAULT_FULL_SCHEMA=n(98),e.exports.load=i.load,e.exports.loadAll=i.loadAll,e.exports.safeLoad=i.safeLoad,e.exports.safeLoadAll=i.safeLoadAll,e.exports.dump=o.dump,e.exports.safeDump=o.safeDump,e.exports.YAMLException=n(72),e.exports.MINIMAL_SCHEMA=n(148),e.exports.SAFE_SCHEMA=n(73),e.exports.DEFAULT_SCHEMA=n(98),e.exports.scan=r("scan"),e.exports.parse=r("parse"),e.exports.compose=r("compose"),e.exports.addConstructor=r("addConstructor")},function(e,t,n){"use strict";function r(e){return 10===e||13===e}function i(e){return 9===e||32===e}function o(e){return 9===e||32===e||10===e||13===e}function a(e){return 44===e||91===e||93===e||123===e||125===e}function s(e){var t;return 48<=e&&e<=57?e-48:(t=32|e,97<=t&&t<=102?t-97+10:-1)}function u(e){return 120===e?2:117===e?4:85===e?8:0}function c(e){return 48<=e&&e<=57?e-48:-1}function l(e){return 48===e?"\0":97===e?"\x07":98===e?"\b":116===e?"\t":9===e?"\t":110===e?"\n":118===e?"\v":102===e?"\f":114===e?"\r":101===e?"\x1b":32===e?" ":34===e?'"':47===e?"/":92===e?"\\":78===e?"\x85":95===e?"\xa0":76===e?"\u2028":80===e?"\u2029":""}function p(e){return e<=65535?String.fromCharCode(e):String.fromCharCode(55296+(e-65536>>10),56320+(e-65536&1023))}function f(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||V,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.documents=[]}function d(e,t){return new U(t,new z(e.filename,e.input,e.position,e.line,e.position-e.lineStart))}function h(e,t){throw d(e,t)}function m(e,t){e.onWarning&&e.onWarning.call(null,d(e,t))}function g(e,t,n,r){var i,o,a,s;if(t1&&(e.result+=$.repeat("\n",t-1))}function D(e,t,n){var s,u,c,l,p,f,d,h,m,y=e.kind,v=e.result;if(m=e.input.charCodeAt(e.position),o(m)||a(m)||35===m||38===m||42===m||33===m||124===m||62===m||39===m||34===m||37===m||64===m||96===m)return!1;if((63===m||45===m)&&(u=e.input.charCodeAt(e.position+1),o(u)||n&&a(u)))return!1;for(e.kind="scalar",e.result="",c=l=e.position,p=!1;0!==m;){if(58===m){if(u=e.input.charCodeAt(e.position+1),o(u)||n&&a(u))break}else if(35===m){if(s=e.input.charCodeAt(e.position-1),o(s))break}else{if(e.position===e.lineStart&&C(e)||n&&a(m))break;if(r(m)){if(f=e.line,d=e.lineStart,h=e.lineIndent,x(e,!1,-1),e.lineIndent>=t){p=!0,m=e.input.charCodeAt(e.position);continue}e.position=l,e.line=f,e.lineStart=d,e.lineIndent=h;break}}p&&(g(e,c,l,!1),E(e,e.line-f),c=l=e.position,p=!1),i(m)||(l=e.position+1),m=e.input.charCodeAt(++e.position)}return g(e,c,l,!1),!!e.result||(e.kind=y,e.result=v,!1)}function w(e,t){var n,i,o;if(39!==(n=e.input.charCodeAt(e.position)))return!1;for(e.kind="scalar",e.result="",e.position++,i=o=e.position;0!==(n=e.input.charCodeAt(e.position));)if(39===n){if(g(e,i,e.position,!0),39!==(n=e.input.charCodeAt(++e.position)))return!0;i=e.position,e.position++,o=e.position}else r(n)?(g(e,i,o,!0),E(e,x(e,!1,t)),i=o=e.position):e.position===e.lineStart&&C(e)?h(e,"unexpected end of the document within a single quoted scalar"):(e.position++,o=e.position);h(e,"unexpected end of the stream within a single quoted scalar")}function S(e,t){var n,i,o,a,c,l;if(34!==(l=e.input.charCodeAt(e.position)))return!1;for(e.kind="scalar",e.result="",e.position++,n=i=e.position;0!==(l=e.input.charCodeAt(e.position));){if(34===l)return g(e,n,e.position,!0),e.position++,!0;if(92===l){if(g(e,n,e.position,!0),l=e.input.charCodeAt(++e.position),r(l))x(e,!1,t);else if(l<256&&ie[l])e.result+=oe[l],e.position++;else if((c=u(l))>0){for(o=c,a=0;o>0;o--)l=e.input.charCodeAt(++e.position),(c=s(l))>=0?a=(a<<4)+c:h(e,"expected hexadecimal character");e.result+=p(a),e.position++}else h(e,"unknown escape sequence");n=i=e.position}else r(l)?(g(e,n,i,!0),E(e,x(e,!1,t)),n=i=e.position):e.position===e.lineStart&&C(e)?h(e,"unexpected end of the document within a double quoted scalar"):(e.position++,i=e.position)}h(e,"unexpected end of the stream within a double quoted scalar")}function k(e,t){var n,r,i,a,s,u,c,l,p,f,d,m=!0,g=e.tag,y=e.anchor,b={};if(91===(d=e.input.charCodeAt(e.position)))a=93,c=!1,r=[];else{if(123!==d)return!1;a=125,c=!0,r={}}for(null!==e.anchor&&(e.anchorMap[e.anchor]=r),d=e.input.charCodeAt(++e.position);0!==d;){if(x(e,!0,t),(d=e.input.charCodeAt(e.position))===a)return e.position++,e.tag=g,e.anchor=y,e.kind=c?"mapping":"sequence",e.result=r,!0;m||h(e,"missed comma between flow collection entries"),p=l=f=null,s=u=!1,63===d&&(i=e.input.charCodeAt(e.position+1),o(i)&&(s=u=!0,e.position++,x(e,!0,t))),n=e.line,I(e,t,H,!1,!0),p=e.tag,l=e.result,x(e,!0,t),d=e.input.charCodeAt(e.position),!u&&e.line!==n||58!==d||(s=!0,d=e.input.charCodeAt(++e.position),x(e,!0,t),I(e,t,H,!1,!0),f=e.result),c?v(e,r,b,p,l,f):s?r.push(v(e,null,b,p,l,f)):r.push(l),x(e,!0,t),d=e.input.charCodeAt(e.position),44===d?(m=!0,d=e.input.charCodeAt(++e.position)):m=!1}h(e,"unexpected end of the stream within a flow collection")}function A(e,t){var n,o,a,s,u=J,l=!1,p=!1,f=t,d=0,m=!1;if(124===(s=e.input.charCodeAt(e.position)))o=!1;else{if(62!==s)return!1;o=!0}for(e.kind="scalar",e.result="";0!==s;)if(43===(s=e.input.charCodeAt(++e.position))||45===s)J===u?u=43===s?X:Y:h(e,"repeat of a chomping mode identifier");else{if(!((a=c(s))>=0))break;0===a?h(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):p?h(e,"repeat of an indentation width identifier"):(f=t+a-1,p=!0)}if(i(s)){do{s=e.input.charCodeAt(++e.position)}while(i(s));if(35===s)do{s=e.input.charCodeAt(++e.position)}while(!r(s)&&0!==s)}for(;0!==s;){for(b(e),e.lineIndent=0,s=e.input.charCodeAt(e.position);(!p||e.lineIndentf&&(f=e.lineIndent),r(s))d++;else{if(e.lineIndentt)&&0!==i)h(e,"bad indentation of a sequence entry");else if(e.lineIndentt)&&(I(e,t,K,!0,a)&&(b?g=e.result:y=e.result),b||(v(e,f,d,m,g,y,s,u),m=g=y=null),x(e,!0,-1),c=e.input.charCodeAt(e.position)),e.lineIndent>t&&0!==c)h(e,"bad indentation of a mapping entry");else if(e.lineIndentt?d=1:e.lineIndent===t?d=0:e.lineIndentt?d=1:e.lineIndent===t?d=0:e.lineIndent tag; it should be "'+l.kind+'", not "'+e.kind+'"'),l.resolve(e.result)?(e.result=l.construct(e.result),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):h(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")):h(e,"unknown tag !<"+e.tag+">");return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||g}function L(e){var t,n,a,s,u=e.position,c=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap={},e.anchorMap={};0!==(s=e.input.charCodeAt(e.position))&&(x(e,!0,-1),s=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==s));){for(c=!0,s=e.input.charCodeAt(++e.position),t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);for(n=e.input.slice(t,e.position),a=[],n.length<1&&h(e,"directive name must not be less than one character in length");0!==s;){for(;i(s);)s=e.input.charCodeAt(++e.position);if(35===s){do{s=e.input.charCodeAt(++e.position)}while(0!==s&&!r(s));break}if(r(s))break;for(t=e.position;0!==s&&!o(s);)s=e.input.charCodeAt(++e.position);a.push(e.input.slice(t,e.position))}0!==s&&b(e),q.call(se,n)?se[n](e,n,a):m(e,'unknown document directive "'+n+'"')}if(x(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,x(e,!0,-1)):c&&h(e,"directives end mark is expected"),I(e,e.lineIndent-1,K,!1,!0),x(e,!0,-1),e.checkLineBreaks&&ee.test(e.input.slice(u,e.position))&&m(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&C(e))return void(46===e.input.charCodeAt(e.position)&&(e.position+=3,x(e,!0,-1)));e.position0&&-1==="\0\r\n\x85\u2028\u2029".indexOf(this.buffer.charAt(r-1));)if(r-=1,this.position-r>t/2-1){n=" ... ",r+=5;break}for(o="",a=this.position;at/2-1){o=" ... ",a-=5;break}return s=this.buffer.slice(r,a),i.repeat(" ",e)+n+s+o+"\n"+i.repeat(" ",e+this.position-r+n.length)+"^"},r.prototype.toString=function(e){var t,n="";return this.name&&(n+='in "'+this.name+'" '),n+="at line "+(this.line+1)+", column "+(this.column+1),e||(t=this.getSnippet())&&(n+=":\n"+t),n},e.exports=r},function(e,t,n){"use strict";var r=n(15);e.exports=new r("tag:yaml.org,2002:str",{kind:"scalar",construct:function(e){return null!==e?e:""}})},function(e,t,n){"use strict";var r=n(15);e.exports=new r("tag:yaml.org,2002:seq",{kind:"sequence",construct:function(e){return null!==e?e:[]}})},function(e,t,n){"use strict";var r=n(15);e.exports=new r("tag:yaml.org,2002:map",{kind:"mapping",construct:function(e){return null!==e?e:{}}})},function(e,t,n){"use strict";function r(e){if(null===e)return!0;var t=e.length;return 1===t&&"~"===e||4===t&&("null"===e||"Null"===e||"NULL"===e)}function i(){return null}function o(e){return null===e}var a=n(15);e.exports=new a("tag:yaml.org,2002:null",{kind:"scalar",resolve:r,construct:i,predicate:o,represent:{canonical:function(){return"~"},lowercase:function(){return"null"},uppercase:function(){return"NULL"},camelcase:function(){return"Null"}},defaultStyle:"lowercase"})},function(e,t,n){"use strict";function r(e){if(null===e)return!1;var t=e.length;return 4===t&&("true"===e||"True"===e||"TRUE"===e)||5===t&&("false"===e||"False"===e||"FALSE"===e)}function i(e){return"true"===e||"True"===e||"TRUE"===e}function o(e){return"[object Boolean]"===Object.prototype.toString.call(e)}var a=n(15);e.exports=new a("tag:yaml.org,2002:bool",{kind:"scalar",resolve:r,construct:i,predicate:o,represent:{lowercase:function(e){return e?"true":"false"},uppercase:function(e){return e?"TRUE":"FALSE"},camelcase:function(e){return e?"True":"False"}},defaultStyle:"lowercase"})},function(e,t,n){"use strict";function r(e){return 48<=e&&e<=57||65<=e&&e<=70||97<=e&&e<=102}function i(e){return 48<=e&&e<=55}function o(e){return 48<=e&&e<=57}function a(e){if(null===e)return!1;var t,n=e.length,a=0,s=!1;if(!n)return!1;if(t=e[a],"-"!==t&&"+"!==t||(t=e[++a]),"0"===t){if(a+1===n)return!0;if("b"===(t=e[++a])){for(a++;a=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0"+e.toString(8):"-0"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}})},function(e,t,n){"use strict";function r(e){return null!==e&&!(!c.test(e)||"_"===e[e.length-1])}function i(e){var t,n,r,i;return t=e.replace(/_/g,"").toLowerCase(),n="-"===t[0]?-1:1,i=[],"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:t.indexOf(":")>=0?(t.split(":").forEach(function(e){i.unshift(parseFloat(e,10))}),t=0,r=1,i.forEach(function(e){t+=e*r,r*=60}),n*t):n*parseFloat(t,10)}function o(e,t){var n;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(s.isNegativeZero(e))return"-0.0";return n=e.toString(10),l.test(n)?n.replace("e",".e"):n}function a(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!==0||s.isNegativeZero(e))}var s=n(52),u=n(15),c=new RegExp("^(?:[-+]?(?:0|[1-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"),l=/^[-+]?[0-9]+e/;e.exports=new u("tag:yaml.org,2002:float",{kind:"scalar",resolve:r,construct:i,predicate:a,represent:o,defaultStyle:"lowercase"})},function(e,t,n){"use strict";function r(e){return null!==e&&(null!==s.exec(e)||null!==u.exec(e))}function i(e){var t,n,r,i,o,a,c,l,p,f,d=0,h=null;if(t=s.exec(e),null===t&&(t=u.exec(e)),null===t)throw new Error("Date resolve error");if(n=+t[1],r=+t[2]-1,i=+t[3],!t[4])return new Date(Date.UTC(n,r,i));if(o=+t[4],a=+t[5],c=+t[6],t[7]){for(d=t[7].slice(0,3);d.length<3;)d+="0";d=+d}return t[9]&&(l=+t[10],p=+(t[11]||0),h=6e4*(60*l+p),"-"===t[9]&&(h=-h)),f=new Date(Date.UTC(n,r,i,o,a,c,d)),h&&f.setTime(f.getTime()-h),f}function o(e){return e.toISOString()}var a=n(15),s=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),u=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");e.exports=new a("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:r,construct:i,instanceOf:Date,represent:o})},function(e,t,n){"use strict";function r(e){return"<<"===e||null===e}var i=n(15);e.exports=new i("tag:yaml.org,2002:merge",{kind:"scalar",resolve:r})},function(e,t,n){"use strict";function r(e){if(null===e)return!1;var t,n,r=0,i=e.length,o=c;for(n=0;n64)){if(t<0)return!1;r+=6}return r%8===0}function i(e){var t,n,r=e.replace(/[\r\n=]/g,""),i=r.length,o=c,a=0,u=[];for(t=0;t>16&255),u.push(a>>8&255),u.push(255&a)),a=a<<6|o.indexOf(r.charAt(t));return n=i%4*6,0===n?(u.push(a>>16&255),u.push(a>>8&255),u.push(255&a)):18===n?(u.push(a>>10&255),u.push(a>>2&255)):12===n&&u.push(a>>4&255),s?s.from?s.from(u):new s(u):u}function o(e){var t,n,r="",i=0,o=e.length,a=c;for(t=0;t>18&63],r+=a[i>>12&63],r+=a[i>>6&63],r+=a[63&i]),i=(i<<8)+e[t];return n=o%3,0===n?(r+=a[i>>18&63],r+=a[i>>12&63],r+=a[i>>6&63],r+=a[63&i]):2===n?(r+=a[i>>10&63],r+=a[i>>4&63],r+=a[i<<2&63],r+=a[64]):1===n&&(r+=a[i>>2&63],r+=a[i<<4&63],r+=a[64],r+=a[64]),r}function a(e){return s&&s.isBuffer(e)}var s;try{s=n(736).Buffer}catch(e){}var u=n(15),c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";e.exports=new u("tag:yaml.org,2002:binary",{kind:"scalar",resolve:r,construct:i,predicate:a,represent:o})},function(e,t,n){"use strict";(function(e){function r(){return o.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function i(e,t){if(r()=r())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+r().toString(16)+" bytes");return 0|e}function m(e){return+e!=e&&(e=0),o.alloc(+e)}function g(e,t){if(o.isBuffer(e))return e.length;if("undefined"!==typeof ArrayBuffer&&"function"===typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!==typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return V(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return W(e).length;default:if(r)return V(e).length;t=(""+t).toLowerCase(),r=!0}}function y(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if(n>>>=0,t>>>=0,n<=t)return"";for(e||(e="utf8");;)switch(e){case"hex":return N(this,t,n);case"utf8":case"utf-8":return _(this,t,n);case"ascii":return O(this,t,n);case"latin1":case"binary":return F(this,t,n);case"base64":return A(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function b(e,t,n,r,i){if(0===e.length)return-1;if("string"===typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=i?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(i)return-1;n=e.length-1}else if(n<0){if(!i)return-1;n=0}if("string"===typeof t&&(t=o.from(t,r)),o.isBuffer(t))return 0===t.length?-1:x(e,t,n,r,i);if("number"===typeof t)return t&=255,o.TYPED_ARRAY_SUPPORT&&"function"===typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):x(e,[t],n,r,i);throw new TypeError("val must be string, number or Buffer")}function x(e,t,n,r,i){function o(e,t){return 1===a?e[t]:e.readUInt16BE(t*a)}var a=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;a=2,s/=2,u/=2,n/=2}var c;if(i){var l=-1;for(c=n;cs&&(n=s-u),c=n;c>=0;c--){for(var p=!0,f=0;fi&&(r=i):r=i;var o=t.length;if(o%2!==0)throw new TypeError("Invalid hex string");r>o/2&&(r=o/2);for(var a=0;a239?4:o>223?3:o>191?2:1;if(i+s<=n){var u,c,l,p;switch(s){case 1:o<128&&(a=o);break;case 2:u=e[i+1],128===(192&u)&&(p=(31&o)<<6|63&u)>127&&(a=p);break;case 3:u=e[i+1],c=e[i+2],128===(192&u)&&128===(192&c)&&(p=(15&o)<<12|(63&u)<<6|63&c)>2047&&(p<55296||p>57343)&&(a=p);break;case 4:u=e[i+1],c=e[i+2],l=e[i+3],128===(192&u)&&128===(192&c)&&128===(192&l)&&(p=(15&o)<<18|(63&u)<<12|(63&c)<<6|63&l)>65535&&p<1114112&&(a=p)}}null===a?(a=65533,s=1):a>65535&&(a-=65536,r.push(a>>>10&1023|55296),a=56320|1023&a),r.push(a),i+=s}return T(r)}function T(e){var t=e.length;if(t<=Z)return String.fromCharCode.apply(String,e);for(var n="",r=0;rr)&&(n=r);for(var i="",o=t;on)throw new RangeError("Trying to access beyond buffer length")}function P(e,t,n,r,i,a){if(!o.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>i||te.length)throw new RangeError("Index out of range")}function M(e,t,n,r){t<0&&(t=65535+t+1);for(var i=0,o=Math.min(e.length-n,2);i>>8*(r?i:1-i)}function j(e,t,n,r){t<0&&(t=4294967295+t+1);for(var i=0,o=Math.min(e.length-n,4);i>>8*(r?i:3-i)&255}function R(e,t,n,r,i,o){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function B(e,t,n,r,i){return i||R(e,t,n,4,3.4028234663852886e38,-3.4028234663852886e38),Y.write(e,t,n,r,23,4),n+4}function $(e,t,n,r,i){return i||R(e,t,n,8,1.7976931348623157e308,-1.7976931348623157e308),Y.write(e,t,n,r,52,8),n+8}function U(e){if(e=z(e).replace(ee,""),e.length<2)return"";for(;e.length%4!==0;)e+="=";return e}function z(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function G(e){return e<16?"0"+e.toString(16):e.toString(16)}function V(e,t){t=t||1/0;for(var n,r=e.length,i=null,o=[],a=0;a55295&&n<57344){if(!i){if(n>56319){(t-=3)>-1&&o.push(239,191,189);continue}if(a+1===r){(t-=3)>-1&&o.push(239,191,189);continue}i=n;continue}if(n<56320){(t-=3)>-1&&o.push(239,191,189),i=n;continue}n=65536+(i-55296<<10|n-56320)}else i&&(t-=3)>-1&&o.push(239,191,189);if(i=null,n<128){if((t-=1)<0)break;o.push(n)}else if(n<2048){if((t-=2)<0)break;o.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;o.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;o.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return o}function q(e){for(var t=[],n=0;n>8,i=n%256,o.push(i),o.push(r);return o}function W(e){return J.toByteArray(U(e))}function Q(e,t,n,r){for(var i=0;i=t.length||i>=e.length);++i)t[i+n]=e[i];return i}function K(e){return e!==e}var J=n(737),Y=n(738),X=n(739);t.Buffer=o,t.SlowBuffer=m,t.INSPECT_MAX_BYTES=50,o.TYPED_ARRAY_SUPPORT=void 0!==e.TYPED_ARRAY_SUPPORT?e.TYPED_ARRAY_SUPPORT:function(){try{var e=new Uint8Array(1);return e.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===e.foo()&&"function"===typeof e.subarray&&0===e.subarray(1,1).byteLength}catch(e){return!1}}(),t.kMaxLength=r(),o.poolSize=8192,o._augment=function(e){return e.__proto__=o.prototype,e},o.from=function(e,t,n){return a(null,e,t,n)},o.TYPED_ARRAY_SUPPORT&&(o.prototype.__proto__=Uint8Array.prototype,o.__proto__=Uint8Array,"undefined"!==typeof Symbol&&Symbol.species&&o[Symbol.species]===o&&Object.defineProperty(o,Symbol.species,{value:null,configurable:!0})),o.alloc=function(e,t,n){return u(null,e,t,n)},o.allocUnsafe=function(e){return c(null,e)},o.allocUnsafeSlow=function(e){return c(null,e)},o.isBuffer=function(e){return!(null==e||!e._isBuffer)},o.compare=function(e,t){if(!o.isBuffer(e)||!o.isBuffer(t))throw new TypeError("Arguments must be Buffers");if(e===t)return 0;for(var n=e.length,r=t.length,i=0,a=Math.min(n,r);i0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},o.prototype.compare=function(e,t,n,r,i){if(!o.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===i&&(i=this.length),t<0||n>e.length||r<0||i>this.length)throw new RangeError("out of range index");if(r>=i&&t>=n)return 0;if(r>=i)return-1;if(t>=n)return 1;if(t>>>=0,n>>>=0,r>>>=0,i>>>=0,this===e)return 0;for(var a=i-r,s=n-t,u=Math.min(a,s),c=this.slice(r,i),l=e.slice(t,n),p=0;pi)&&(n=i),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var o=!1;;)switch(r){case"hex":return C(this,e,t,n);case"utf8":case"utf-8":return E(this,e,t,n);case"ascii":return D(this,e,t,n);case"latin1":case"binary":return w(this,e,t,n);case"base64":return S(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return k(this,e,t,n);default:if(o)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),o=!0}},o.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var Z=4096;o.prototype.slice=function(e,t){var n=this.length;e=~~e,t=void 0===t?n:~~t,e<0?(e+=n)<0&&(e=0):e>n&&(e=n),t<0?(t+=n)<0&&(t=0):t>n&&(t=n),t0&&(i*=256);)r+=this[e+--t]*i;return r},o.prototype.readUInt8=function(e,t){return t||L(e,1,this.length),this[e]},o.prototype.readUInt16LE=function(e,t){return t||L(e,2,this.length),this[e]|this[e+1]<<8},o.prototype.readUInt16BE=function(e,t){return t||L(e,2,this.length),this[e]<<8|this[e+1]},o.prototype.readUInt32LE=function(e,t){return t||L(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},o.prototype.readUInt32BE=function(e,t){return t||L(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},o.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||L(e,t,this.length);for(var r=this[e],i=1,o=0;++o=i&&(r-=Math.pow(2,8*t)),r},o.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||L(e,t,this.length);for(var r=t,i=1,o=this[e+--r];r>0&&(i*=256);)o+=this[e+--r]*i;return i*=128,o>=i&&(o-=Math.pow(2,8*t)),o},o.prototype.readInt8=function(e,t){return t||L(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},o.prototype.readInt16LE=function(e,t){t||L(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt16BE=function(e,t){t||L(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},o.prototype.readInt32LE=function(e,t){return t||L(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},o.prototype.readInt32BE=function(e,t){return t||L(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},o.prototype.readFloatLE=function(e,t){return t||L(e,4,this.length),Y.read(this,e,!0,23,4)},o.prototype.readFloatBE=function(e,t){return t||L(e,4,this.length),Y.read(this,e,!1,23,4)},o.prototype.readDoubleLE=function(e,t){return t||L(e,8,this.length),Y.read(this,e,!0,52,8)},o.prototype.readDoubleBE=function(e,t){return t||L(e,8,this.length),Y.read(this,e,!1,52,8)},o.prototype.writeUIntLE=function(e,t,n,r){if(e=+e,t|=0,n|=0,!r){P(this,e,t,n,Math.pow(2,8*n)-1,0)}var i=1,o=0;for(this[t]=255&e;++o=0&&(o*=256);)this[t+i]=e/o&255;return t+n},o.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,1,255,0),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},o.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):M(this,e,t,!0),t+2},o.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,65535,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):M(this,e,t,!1),t+2},o.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):j(this,e,t,!0),t+4},o.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,4294967295,0),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):j(this,e,t,!1),t+4},o.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);P(this,e,t,n,i-1,-i)}var o=0,a=1,s=0;for(this[t]=255&e;++o>0)-s&255;return t+n},o.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var i=Math.pow(2,8*n-1);P(this,e,t,n,i-1,-i)}var o=n-1,a=1,s=0;for(this[t+o]=255&e;--o>=0&&(a*=256);)e<0&&0===s&&0!==this[t+o+1]&&(s=1),this[t+o]=(e/a>>0)-s&255;return t+n},o.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,1,127,-128),o.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},o.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):M(this,e,t,!0),t+2},o.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,2,32767,-32768),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):M(this,e,t,!1),t+2},o.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,2147483647,-2147483648),o.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):j(this,e,t,!0),t+4},o.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||P(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),o.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):j(this,e,t,!1),t+4},o.prototype.writeFloatLE=function(e,t,n){return B(this,e,t,!0,n)},o.prototype.writeFloatBE=function(e,t,n){return B(this,e,t,!1,n)},o.prototype.writeDoubleLE=function(e,t,n){return $(this,e,t,!0,n)},o.prototype.writeDoubleBE=function(e,t,n){return $(this,e,t,!1,n)},o.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--i)e[i+t]=this[i+n];else if(a<1e3||!o.TYPED_ARRAY_SUPPORT)for(i=0;i>>=0,n=void 0===n?this.length:n>>>0,e||(e=0);var a;if("number"===typeof e)for(a=t;a0)throw new Error("Invalid string. Length must be a multiple of 4");var n=e.indexOf("=");return-1===n&&(n=t),[n,n===t?0:4-n%4]}function i(e){var t=r(e),n=t[0],i=t[1];return 3*(n+i)/4-i}function o(e,t,n){return 3*(t+n)/4-n}function a(e){for(var t,n=r(e),i=n[0],a=n[1],s=new f(o(e,i,a)),u=0,c=a>0?i-4:i,l=0;l>16&255,s[u++]=t>>8&255,s[u++]=255&t;return 2===a&&(t=p[e.charCodeAt(l)]<<2|p[e.charCodeAt(l+1)]>>4,s[u++]=255&t),1===a&&(t=p[e.charCodeAt(l)]<<10|p[e.charCodeAt(l+1)]<<4|p[e.charCodeAt(l+2)]>>2,s[u++]=t>>8&255,s[u++]=255&t),s}function s(e){return l[e>>18&63]+l[e>>12&63]+l[e>>6&63]+l[63&e]}function u(e,t,n){for(var r,i=[],o=t;oa?a:o+16383));return 1===r?(t=e[n-1],i.push(l[t>>2]+l[t<<4&63]+"==")):2===r&&(t=(e[n-2]<<8)+e[n-1],i.push(l[t>>10]+l[t>>4&63]+l[t<<2&63]+"=")),i.join("")}t.byteLength=i,t.toByteArray=a,t.fromByteArray=c;for(var l=[],p=[],f="undefined"!==typeof Uint8Array?Uint8Array:Array,d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",h=0,m=d.length;h>1,l=-7,p=n?i-1:0,f=n?-1:1,d=e[t+p];for(p+=f,o=d&(1<<-l)-1,d>>=-l,l+=s;l>0;o=256*o+e[t+p],p+=f,l-=8);for(a=o&(1<<-l)-1,o>>=-l,l+=r;l>0;a=256*a+e[t+p],p+=f,l-=8);if(0===o)o=1-c;else{if(o===u)return a?NaN:1/0*(d?-1:1);a+=Math.pow(2,r),o-=c}return(d?-1:1)*a*Math.pow(2,o-r)},t.write=function(e,t,n,r,i,o){var a,s,u,c=8*o-i-1,l=(1<>1,f=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,d=r?0:o-1,h=r?1:-1,m=t<0||0===t&&1/t<0?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(s=isNaN(t)?1:0,a=l):(a=Math.floor(Math.log(t)/Math.LN2),t*(u=Math.pow(2,-a))<1&&(a--,u*=2),t+=a+p>=1?f/u:f*Math.pow(2,1-p),t*u>=2&&(a++,u/=2),a+p>=l?(s=0,a=l):a+p>=1?(s=(t*u-1)*Math.pow(2,i),a+=p):(s=t*Math.pow(2,p-1)*Math.pow(2,i),a=0));i>=8;e[n+d]=255&s,d+=h,s/=256,i-=8);for(a=a<0;e[n+d]=255&a,d+=h,a/=256,c-=8);e[n+d-h]|=128*m}},function(e,t){var n={}.toString;e.exports=Array.isArray||function(e){return"[object Array]"==n.call(e)}},function(e,t,n){"use strict";function r(e){if(null===e)return!0;var t,n,r,i,o,u=[],c=e;for(t=0,n=c.length;t3)return!1;if("/"!==t[t.length-r.length-1])return!1}return!0}function i(e){var t=e,n=/\/([gim]*)$/.exec(e),r="";return"/"===t[0]&&(n&&(r=n[1]),t=t.slice(1,t.length-r.length-1)),new RegExp(t,r)}function o(e){var t="/"+e.source+"/";return e.global&&(t+="g"),e.multiline&&(t+="m"),e.ignoreCase&&(t+="i"),t}function a(e){return"[object RegExp]"===Object.prototype.toString.call(e)}var s=n(15);e.exports=new s("tag:yaml.org,2002:js/regexp",{kind:"scalar",resolve:r,construct:i,predicate:a,represent:o})},function(e,t,n){"use strict";function r(e){if(null===e)return!1;try{var t="("+e+")",n=s.parse(t,{range:!0});return"Program"===n.type&&1===n.body.length&&"ExpressionStatement"===n.body[0].type&&("ArrowFunctionExpression"===n.body[0].expression.type||"FunctionExpression"===n.body[0].expression.type)}catch(e){return!1}}function i(e){var t,n="("+e+")",r=s.parse(n,{range:!0}),i=[];if("Program"!==r.type||1!==r.body.length||"ExpressionStatement"!==r.body[0].type||"ArrowFunctionExpression"!==r.body[0].expression.type&&"FunctionExpression"!==r.body[0].expression.type)throw new Error("Failed to resolve function");return r.body[0].expression.params.forEach(function(e){i.push(e.name)}),t=r.body[0].expression.body.range,new Function(i,n.slice(t[0]+1,t[1]-1))}function o(e){return e.toString()}function a(e){return"[object Function]"===Object.prototype.toString.call(e)}var s;try{s=n(746)}catch(e){"undefined"!==typeof window&&(s=window.esprima)}var u=n(15);e.exports=new u("tag:yaml.org,2002:js/function",{kind:"scalar",resolve:r,construct:i,predicate:a,represent:o})},function(e,t,n){!function(t,n){e.exports=n()}(0,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e,t,n){var r=null,i=function(e,t){n&&n(e,t),r&&r.visit(e,t)},o="function"===typeof n?i:null,a=!1;if(t){a="boolean"===typeof t.comment&&t.comment;var l="boolean"===typeof t.attachComment&&t.attachComment;(a||l)&&(r=new s.CommentHandler,r.attach=l,t.comment=!0,o=i)}var p=!1;t&&"string"===typeof t.sourceType&&(p="module"===t.sourceType);var f;f=t&&"boolean"===typeof t.jsx&&t.jsx?new u.JSXParser(e,t,o):new c.Parser(e,t,o);var d=p?f.parseModule():f.parseScript(),h=d;return a&&r&&(h.comments=r.comments),f.config.tokens&&(h.tokens=f.tokens),f.config.tolerant&&(h.errors=f.errorHandler.errors),h}function i(e,t,n){var i=t||{};return i.sourceType="module",r(e,i,n)}function o(e,t,n){var i=t||{};return i.sourceType="script",r(e,i,n)}function a(e,t,n){var r,i=new l.Tokenizer(e,t);r=[];try{for(;;){var o=i.getNextToken();if(!o)break;n&&(o=n(o)),r.push(o)}}catch(e){i.errorHandler.tolerate(e)}return i.errorHandler.tolerant&&(r.errors=i.errors()),r}Object.defineProperty(t,"__esModule",{value:!0});var s=n(1),u=n(3),c=n(8),l=n(15);t.parse=r,t.parseModule=i,t.parseScript=o,t.tokenize=a;var p=n(2);t.Syntax=p.Syntax,t.version="4.0.0"},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(){function e(){this.attach=!1,this.comments=[],this.stack=[],this.leading=[],this.trailing=[]}return e.prototype.insertInnerComments=function(e,t){if(e.type===r.Syntax.BlockStatement&&0===e.body.length){for(var n=[],i=this.leading.length-1;i>=0;--i){var o=this.leading[i];t.end.offset>=o.start&&(n.unshift(o.comment),this.leading.splice(i,1),this.trailing.splice(i,1))}n.length&&(e.innerComments=n)}},e.prototype.findTrailingComments=function(e){var t=[];if(this.trailing.length>0){for(var n=this.trailing.length-1;n>=0;--n){var r=this.trailing[n];r.start>=e.end.offset&&t.unshift(r.comment)}return this.trailing.length=0,t}var i=this.stack[this.stack.length-1];if(i&&i.node.trailingComments){var o=i.node.trailingComments[0];o&&o.range[0]>=e.end.offset&&(t=i.node.trailingComments,delete i.node.trailingComments)}return t},e.prototype.findLeadingComments=function(e){for(var t,n=[];this.stack.length>0;){var r=this.stack[this.stack.length-1];if(!(r&&r.start>=e.start.offset))break;t=r.node,this.stack.pop()}if(t){for(var i=t.leadingComments?t.leadingComments.length:0,o=i-1;o>=0;--o){var a=t.leadingComments[o];a.range[1]<=e.start.offset&&(n.unshift(a),t.leadingComments.splice(o,1))}return t.leadingComments&&0===t.leadingComments.length&&delete t.leadingComments,n}for(var o=this.leading.length-1;o>=0;--o){var r=this.leading[o];r.start<=e.start.offset&&(n.unshift(r.comment),this.leading.splice(o,1))}return n},e.prototype.visitNode=function(e,t){if(!(e.type===r.Syntax.Program&&e.body.length>0)){this.insertInnerComments(e,t);var n=this.findTrailingComments(t),i=this.findLeadingComments(t);i.length>0&&(e.leadingComments=i),n.length>0&&(e.trailingComments=n),this.stack.push({node:e,start:t.start.offset})}},e.prototype.visitComment=function(e,t){var n="L"===e.type[0]?"Line":"Block",r={type:n,value:e.value};if(e.range&&(r.range=e.range),e.loc&&(r.loc=e.loc),this.comments.push(r),this.attach){var i={comment:{type:n,value:e.value,range:[t.start.offset,t.end.offset]},start:t.start.offset};e.loc&&(i.comment.loc=e.loc),e.type=n,this.leading.push(i),this.trailing.push(i)}},e.prototype.visit=function(e,t){"LineComment"===e.type?this.visitComment(e,t):"BlockComment"===e.type?this.visitComment(e,t):this.attach&&this.visitNode(e,t)},e}();t.CommentHandler=i},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Syntax={AssignmentExpression:"AssignmentExpression",AssignmentPattern:"AssignmentPattern",ArrayExpression:"ArrayExpression",ArrayPattern:"ArrayPattern",ArrowFunctionExpression:"ArrowFunctionExpression",AwaitExpression:"AwaitExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ClassBody:"ClassBody",ClassDeclaration:"ClassDeclaration",ClassExpression:"ClassExpression",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExportAllDeclaration:"ExportAllDeclaration",ExportDefaultDeclaration:"ExportDefaultDeclaration",ExportNamedDeclaration:"ExportNamedDeclaration",ExportSpecifier:"ExportSpecifier",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForOfStatement:"ForOfStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",ImportDeclaration:"ImportDeclaration",ImportDefaultSpecifier:"ImportDefaultSpecifier",ImportNamespaceSpecifier:"ImportNamespaceSpecifier",ImportSpecifier:"ImportSpecifier",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",MetaProperty:"MetaProperty",MethodDefinition:"MethodDefinition",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",ObjectPattern:"ObjectPattern",Program:"Program",Property:"Property",RestElement:"RestElement",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SpreadElement:"SpreadElement",Super:"Super",SwitchCase:"SwitchCase",SwitchStatement:"SwitchStatement",TaggedTemplateExpression:"TaggedTemplateExpression",TemplateElement:"TemplateElement",TemplateLiteral:"TemplateLiteral",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement",YieldExpression:"YieldExpression"}},function(e,t,n){"use strict";function r(e){var t;switch(e.type){case s.JSXSyntax.JSXIdentifier:t=e.name;break;case s.JSXSyntax.JSXNamespacedName:var n=e;t=r(n.namespace)+":"+r(n.name);break;case s.JSXSyntax.JSXMemberExpression:var i=e;t=r(i.object)+"."+r(i.property)}return t}var i=this&&this.__extends||function(){var e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}();Object.defineProperty(t,"__esModule",{value:!0});var o=n(4),a=n(5),s=n(6),u=n(7),c=n(8),l=n(13),p=n(14);l.TokenName[100]="JSXIdentifier",l.TokenName[101]="JSXText";var f=function(e){function t(t,n,r){return e.call(this,t,n,r)||this}return i(t,e),t.prototype.parsePrimaryExpression=function(){return this.match("<")?this.parseJSXRoot():e.prototype.parsePrimaryExpression.call(this)},t.prototype.startJSX=function(){this.scanner.index=this.startMarker.index,this.scanner.lineNumber=this.startMarker.line,this.scanner.lineStart=this.startMarker.index-this.startMarker.column},t.prototype.finishJSX=function(){this.nextToken()},t.prototype.reenterJSX=function(){this.startJSX(),this.expectJSX("}"),this.config.tokens&&this.tokens.pop()},t.prototype.createJSXNode=function(){return this.collectComments(),{index:this.scanner.index,line:this.scanner.lineNumber,column:this.scanner.index-this.scanner.lineStart}},t.prototype.createJSXChildNode=function(){return{index:this.scanner.index,line:this.scanner.lineNumber,column:this.scanner.index-this.scanner.lineStart}},t.prototype.scanXHTMLEntity=function(e){for(var t="&",n=!0,r=!1,i=!1,a=!1;!this.scanner.eof()&&n&&!r;){var s=this.scanner.source[this.scanner.index];if(s===e)break;if(r=";"===s,t+=s,++this.scanner.index,!r)switch(t.length){case 2:i="#"===s;break;case 3:i&&(a="x"===s,n=a||o.Character.isDecimalDigit(s.charCodeAt(0)),i=i&&!a);break;default:n=n&&!(i&&!o.Character.isDecimalDigit(s.charCodeAt(0))),n=n&&!(a&&!o.Character.isHexDigit(s.charCodeAt(0)))}}if(n&&r&&t.length>2){var u=t.substr(1,t.length-2);i&&u.length>1?t=String.fromCharCode(parseInt(u.substr(1),10)):a&&u.length>2?t=String.fromCharCode(parseInt("0"+u.substr(1),16)):i||a||!p.XHTMLEntities[u]||(t=p.XHTMLEntities[u])}return t},t.prototype.lexJSX=function(){var e=this.scanner.source.charCodeAt(this.scanner.index);if(60===e||62===e||47===e||58===e||61===e||123===e||125===e){var t=this.scanner.source[this.scanner.index++];return{type:7,value:t,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:this.scanner.index-1,end:this.scanner.index}}if(34===e||39===e){for(var n=this.scanner.index,r=this.scanner.source[this.scanner.index++],i="";!this.scanner.eof();){var a=this.scanner.source[this.scanner.index++];if(a===r)break;i+="&"===a?this.scanXHTMLEntity(r):a}return{type:8,value:i,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:n,end:this.scanner.index}}if(46===e){var s=this.scanner.source.charCodeAt(this.scanner.index+1),u=this.scanner.source.charCodeAt(this.scanner.index+2),t=46===s&&46===u?"...":".",n=this.scanner.index;return this.scanner.index+=t.length,{type:7,value:t,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:n,end:this.scanner.index}}if(96===e)return{type:10,value:"",lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:this.scanner.index,end:this.scanner.index};if(o.Character.isIdentifierStart(e)&&92!==e){var n=this.scanner.index;for(++this.scanner.index;!this.scanner.eof();){var a=this.scanner.source.charCodeAt(this.scanner.index);if(o.Character.isIdentifierPart(a)&&92!==a)++this.scanner.index;else{if(45!==a)break;++this.scanner.index}}return{type:100,value:this.scanner.source.slice(n,this.scanner.index),lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:n,end:this.scanner.index}}return this.scanner.lex()},t.prototype.nextJSXToken=function(){this.collectComments(),this.startMarker.index=this.scanner.index,this.startMarker.line=this.scanner.lineNumber,this.startMarker.column=this.scanner.index-this.scanner.lineStart;var e=this.lexJSX();return this.lastMarker.index=this.scanner.index,this.lastMarker.line=this.scanner.lineNumber,this.lastMarker.column=this.scanner.index-this.scanner.lineStart,this.config.tokens&&this.tokens.push(this.convertToken(e)),e},t.prototype.nextJSXText=function(){this.startMarker.index=this.scanner.index,this.startMarker.line=this.scanner.lineNumber,this.startMarker.column=this.scanner.index-this.scanner.lineStart;for(var e=this.scanner.index,t="";!this.scanner.eof();){var n=this.scanner.source[this.scanner.index];if("{"===n||"<"===n)break;++this.scanner.index,t+=n,o.Character.isLineTerminator(n.charCodeAt(0))&&(++this.scanner.lineNumber,"\r"===n&&"\n"===this.scanner.source[this.scanner.index]&&++this.scanner.index,this.scanner.lineStart=this.scanner.index)}this.lastMarker.index=this.scanner.index,this.lastMarker.line=this.scanner.lineNumber,this.lastMarker.column=this.scanner.index-this.scanner.lineStart;var r={type:101,value:t,lineNumber:this.scanner.lineNumber,lineStart:this.scanner.lineStart,start:e,end:this.scanner.index};return t.length>0&&this.config.tokens&&this.tokens.push(this.convertToken(r)),r},t.prototype.peekJSXToken=function(){var e=this.scanner.saveState();this.scanner.scanComments();var t=this.lexJSX();return this.scanner.restoreState(e),t},t.prototype.expectJSX=function(e){var t=this.nextJSXToken();7===t.type&&t.value===e||this.throwUnexpectedToken(t)},t.prototype.matchJSX=function(e){var t=this.peekJSXToken();return 7===t.type&&t.value===e},t.prototype.parseJSXIdentifier=function(){var e=this.createJSXNode(),t=this.nextJSXToken();return 100!==t.type&&this.throwUnexpectedToken(t),this.finalize(e,new a.JSXIdentifier(t.value))},t.prototype.parseJSXElementName=function(){var e=this.createJSXNode(),t=this.parseJSXIdentifier();if(this.matchJSX(":")){var n=t;this.expectJSX(":");var r=this.parseJSXIdentifier();t=this.finalize(e,new a.JSXNamespacedName(n,r))}else if(this.matchJSX("."))for(;this.matchJSX(".");){var i=t;this.expectJSX(".");var o=this.parseJSXIdentifier();t=this.finalize(e,new a.JSXMemberExpression(i,o))}return t},t.prototype.parseJSXAttributeName=function(){var e,t=this.createJSXNode(),n=this.parseJSXIdentifier();if(this.matchJSX(":")){var r=n;this.expectJSX(":");var i=this.parseJSXIdentifier();e=this.finalize(t,new a.JSXNamespacedName(r,i))}else e=n;return e},t.prototype.parseJSXStringLiteralAttribute=function(){var e=this.createJSXNode(),t=this.nextJSXToken();8!==t.type&&this.throwUnexpectedToken(t);var n=this.getTokenRaw(t);return this.finalize(e,new u.Literal(t.value,n))},t.prototype.parseJSXExpressionAttribute=function(){var e=this.createJSXNode();this.expectJSX("{"),this.finishJSX(),this.match("}")&&this.tolerateError("JSX attributes must only be assigned a non-empty expression");var t=this.parseAssignmentExpression();return this.reenterJSX(),this.finalize(e,new a.JSXExpressionContainer(t))},t.prototype.parseJSXAttributeValue=function(){return this.matchJSX("{")?this.parseJSXExpressionAttribute():this.matchJSX("<")?this.parseJSXElement():this.parseJSXStringLiteralAttribute()},t.prototype.parseJSXNameValueAttribute=function(){var e=this.createJSXNode(),t=this.parseJSXAttributeName(),n=null;return this.matchJSX("=")&&(this.expectJSX("="),n=this.parseJSXAttributeValue()),this.finalize(e,new a.JSXAttribute(t,n))},t.prototype.parseJSXSpreadAttribute=function(){var e=this.createJSXNode();this.expectJSX("{"),this.expectJSX("..."),this.finishJSX();var t=this.parseAssignmentExpression();return this.reenterJSX(),this.finalize(e,new a.JSXSpreadAttribute(t))},t.prototype.parseJSXAttributes=function(){for(var e=[];!this.matchJSX("/")&&!this.matchJSX(">");){var t=this.matchJSX("{")?this.parseJSXSpreadAttribute():this.parseJSXNameValueAttribute();e.push(t)}return e},t.prototype.parseJSXOpeningElement=function(){var e=this.createJSXNode();this.expectJSX("<");var t=this.parseJSXElementName(),n=this.parseJSXAttributes(),r=this.matchJSX("/");return r&&this.expectJSX("/"),this.expectJSX(">"),this.finalize(e,new a.JSXOpeningElement(t,r,n))},t.prototype.parseJSXBoundaryElement=function(){var e=this.createJSXNode();if(this.expectJSX("<"),this.matchJSX("/")){this.expectJSX("/");var t=this.parseJSXElementName();return this.expectJSX(">"),this.finalize(e,new a.JSXClosingElement(t))}var n=this.parseJSXElementName(),r=this.parseJSXAttributes(),i=this.matchJSX("/");return i&&this.expectJSX("/"),this.expectJSX(">"),this.finalize(e,new a.JSXOpeningElement(n,i,r))},t.prototype.parseJSXEmptyExpression=function(){var e=this.createJSXChildNode();return this.collectComments(),this.lastMarker.index=this.scanner.index,this.lastMarker.line=this.scanner.lineNumber,this.lastMarker.column=this.scanner.index-this.scanner.lineStart,this.finalize(e,new a.JSXEmptyExpression)},t.prototype.parseJSXExpressionContainer=function(){var e=this.createJSXNode();this.expectJSX("{");var t;return this.matchJSX("}")?(t=this.parseJSXEmptyExpression(),this.expectJSX("}")):(this.finishJSX(),t=this.parseAssignmentExpression(),this.reenterJSX()),this.finalize(e,new a.JSXExpressionContainer(t))},t.prototype.parseJSXChildren=function(){for(var e=[];!this.scanner.eof();){var t=this.createJSXChildNode(),n=this.nextJSXText();if(n.start0))break;var u=this.finalize(e.node,new a.JSXElement(e.opening,e.children,e.closing));e=t[t.length-1],e.children.push(u),t.pop()}}return e},t.prototype.parseJSXElement=function(){var e=this.createJSXNode(),t=this.parseJSXOpeningElement(),n=[],r=null;if(!t.selfClosing){var i=this.parseComplexJSXElement({node:e,opening:t,closing:r,children:n});n=i.children,r=i.closing}return this.finalize(e,new a.JSXElement(t,n,r))},t.prototype.parseJSXRoot=function(){this.config.tokens&&this.tokens.pop(),this.startJSX();var e=this.parseJSXElement();return this.finishJSX(),e},t.prototype.isStartOfExpression=function(){return e.prototype.isStartOfExpression.call(this)||this.match("<")},t}(c.Parser);t.JSXParser=f},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n={NonAsciiIdentifierStart:/[\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/,NonAsciiIdentifierPart:/[\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/};t.Character={fromCodePoint:function(e){return e<65536?String.fromCharCode(e):String.fromCharCode(55296+(e-65536>>10))+String.fromCharCode(56320+(e-65536&1023))},isWhiteSpace:function(e){return 32===e||9===e||11===e||12===e||160===e||e>=5760&&[5760,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8239,8287,12288,65279].indexOf(e)>=0},isLineTerminator:function(e){return 10===e||13===e||8232===e||8233===e},isIdentifierStart:function(e){return 36===e||95===e||e>=65&&e<=90||e>=97&&e<=122||92===e||e>=128&&n.NonAsciiIdentifierStart.test(t.Character.fromCodePoint(e))},isIdentifierPart:function(e){return 36===e||95===e||e>=65&&e<=90||e>=97&&e<=122||e>=48&&e<=57||92===e||e>=128&&n.NonAsciiIdentifierPart.test(t.Character.fromCodePoint(e))},isDecimalDigit:function(e){return e>=48&&e<=57},isHexDigit:function(e){return e>=48&&e<=57||e>=65&&e<=70||e>=97&&e<=102},isOctalDigit:function(e){return e>=48&&e<=55}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(6),i=function(){function e(e){this.type=r.JSXSyntax.JSXClosingElement,this.name=e}return e}();t.JSXClosingElement=i;var o=function(){function e(e,t,n){this.type=r.JSXSyntax.JSXElement,this.openingElement=e,this.children=t,this.closingElement=n}return e}();t.JSXElement=o;var a=function(){function e(){this.type=r.JSXSyntax.JSXEmptyExpression}return e}();t.JSXEmptyExpression=a;var s=function(){function e(e){this.type=r.JSXSyntax.JSXExpressionContainer,this.expression=e}return e}();t.JSXExpressionContainer=s;var u=function(){function e(e){this.type=r.JSXSyntax.JSXIdentifier,this.name=e}return e}();t.JSXIdentifier=u;var c=function(){function e(e,t){this.type=r.JSXSyntax.JSXMemberExpression,this.object=e,this.property=t}return e}();t.JSXMemberExpression=c;var l=function(){function e(e,t){this.type=r.JSXSyntax.JSXAttribute,this.name=e,this.value=t}return e}();t.JSXAttribute=l;var p=function(){function e(e,t){this.type=r.JSXSyntax.JSXNamespacedName,this.namespace=e,this.name=t}return e}();t.JSXNamespacedName=p;var f=function(){function e(e,t,n){this.type=r.JSXSyntax.JSXOpeningElement,this.name=e,this.selfClosing=t,this.attributes=n}return e}();t.JSXOpeningElement=f;var d=function(){function e(e){this.type=r.JSXSyntax.JSXSpreadAttribute,this.argument=e}return e}();t.JSXSpreadAttribute=d;var h=function(){function e(e,t){this.type=r.JSXSyntax.JSXText,this.value=e,this.raw=t}return e}();t.JSXText=h},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.JSXSyntax={JSXAttribute:"JSXAttribute",JSXClosingElement:"JSXClosingElement",JSXElement:"JSXElement",JSXEmptyExpression:"JSXEmptyExpression",JSXExpressionContainer:"JSXExpressionContainer",JSXIdentifier:"JSXIdentifier",JSXMemberExpression:"JSXMemberExpression",JSXNamespacedName:"JSXNamespacedName",JSXOpeningElement:"JSXOpeningElement",JSXSpreadAttribute:"JSXSpreadAttribute",JSXText:"JSXText"}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(2),i=function(){function e(e){this.type=r.Syntax.ArrayExpression,this.elements=e}return e}();t.ArrayExpression=i;var o=function(){function e(e){this.type=r.Syntax.ArrayPattern,this.elements=e}return e}();t.ArrayPattern=o;var a=function(){function e(e,t,n){this.type=r.Syntax.ArrowFunctionExpression,this.id=null,this.params=e,this.body=t,this.generator=!1,this.expression=n,this.async=!1}return e}();t.ArrowFunctionExpression=a;var s=function(){function e(e,t,n){this.type=r.Syntax.AssignmentExpression,this.operator=e,this.left=t,this.right=n}return e}();t.AssignmentExpression=s;var u=function(){function e(e,t){this.type=r.Syntax.AssignmentPattern,this.left=e,this.right=t}return e}();t.AssignmentPattern=u;var c=function(){function e(e,t,n){this.type=r.Syntax.ArrowFunctionExpression,this.id=null,this.params=e,this.body=t,this.generator=!1,this.expression=n,this.async=!0}return e}();t.AsyncArrowFunctionExpression=c;var l=function(){function e(e,t,n){this.type=r.Syntax.FunctionDeclaration,this.id=e,this.params=t,this.body=n,this.generator=!1,this.expression=!1,this.async=!0}return e}();t.AsyncFunctionDeclaration=l;var p=function(){function e(e,t,n){this.type=r.Syntax.FunctionExpression,this.id=e,this.params=t,this.body=n,this.generator=!1,this.expression=!1,this.async=!0}return e}();t.AsyncFunctionExpression=p;var f=function(){function e(e){this.type=r.Syntax.AwaitExpression,this.argument=e}return e}();t.AwaitExpression=f;var d=function(){function e(e,t,n){var i="||"===e||"&&"===e;this.type=i?r.Syntax.LogicalExpression:r.Syntax.BinaryExpression,this.operator=e,this.left=t,this.right=n}return e}();t.BinaryExpression=d;var h=function(){function e(e){this.type=r.Syntax.BlockStatement,this.body=e}return e}();t.BlockStatement=h;var m=function(){function e(e){this.type=r.Syntax.BreakStatement,this.label=e}return e}();t.BreakStatement=m;var g=function(){function e(e,t){this.type=r.Syntax.CallExpression,this.callee=e,this.arguments=t}return e}();t.CallExpression=g;var y=function(){function e(e,t){this.type=r.Syntax.CatchClause,this.param=e,this.body=t}return e}();t.CatchClause=y;var v=function(){function e(e){this.type=r.Syntax.ClassBody,this.body=e}return e}();t.ClassBody=v;var b=function(){function e(e,t,n){this.type=r.Syntax.ClassDeclaration,this.id=e,this.superClass=t,this.body=n}return e}();t.ClassDeclaration=b;var x=function(){function e(e,t,n){this.type=r.Syntax.ClassExpression,this.id=e,this.superClass=t,this.body=n}return e}();t.ClassExpression=x;var C=function(){function e(e,t){this.type=r.Syntax.MemberExpression,this.computed=!0,this.object=e,this.property=t}return e}();t.ComputedMemberExpression=C;var E=function(){function e(e,t,n){this.type=r.Syntax.ConditionalExpression,this.test=e,this.consequent=t,this.alternate=n}return e}();t.ConditionalExpression=E;var D=function(){function e(e){this.type=r.Syntax.ContinueStatement,this.label=e}return e}();t.ContinueStatement=D;var w=function(){function e(){this.type=r.Syntax.DebuggerStatement}return e}();t.DebuggerStatement=w;var S=function(){function e(e,t){this.type=r.Syntax.ExpressionStatement,this.expression=e,this.directive=t}return e}();t.Directive=S;var k=function(){function e(e,t){this.type=r.Syntax.DoWhileStatement,this.body=e,this.test=t}return e}();t.DoWhileStatement=k;var A=function(){function e(){this.type=r.Syntax.EmptyStatement}return e}();t.EmptyStatement=A;var _=function(){function e(e){this.type=r.Syntax.ExportAllDeclaration,this.source=e}return e}();t.ExportAllDeclaration=_;var T=function(){function e(e){this.type=r.Syntax.ExportDefaultDeclaration,this.declaration=e}return e}();t.ExportDefaultDeclaration=T;var O=function(){function e(e,t,n){this.type=r.Syntax.ExportNamedDeclaration,this.declaration=e,this.specifiers=t,this.source=n}return e}();t.ExportNamedDeclaration=O;var F=function(){function e(e,t){this.type=r.Syntax.ExportSpecifier,this.exported=t,this.local=e}return e}();t.ExportSpecifier=F;var N=function(){function e(e){this.type=r.Syntax.ExpressionStatement,this.expression=e}return e}();t.ExpressionStatement=N;var I=function(){function e(e,t,n){this.type=r.Syntax.ForInStatement,this.left=e,this.right=t,this.body=n,this.each=!1}return e}();t.ForInStatement=I;var L=function(){function e(e,t,n){this.type=r.Syntax.ForOfStatement,this.left=e,this.right=t,this.body=n}return e}();t.ForOfStatement=L;var P=function(){function e(e,t,n,i){this.type=r.Syntax.ForStatement,this.init=e,this.test=t,this.update=n,this.body=i}return e}();t.ForStatement=P;var M=function(){function e(e,t,n,i){this.type=r.Syntax.FunctionDeclaration,this.id=e,this.params=t,this.body=n,this.generator=i,this.expression=!1,this.async=!1}return e}();t.FunctionDeclaration=M;var j=function(){function e(e,t,n,i){this.type=r.Syntax.FunctionExpression,this.id=e,this.params=t,this.body=n,this.generator=i,this.expression=!1,this.async=!1}return e}();t.FunctionExpression=j;var R=function(){function e(e){this.type=r.Syntax.Identifier,this.name=e}return e}();t.Identifier=R;var B=function(){function e(e,t,n){this.type=r.Syntax.IfStatement,this.test=e,this.consequent=t,this.alternate=n}return e}();t.IfStatement=B;var $=function(){function e(e,t){this.type=r.Syntax.ImportDeclaration,this.specifiers=e,this.source=t}return e}();t.ImportDeclaration=$;var U=function(){function e(e){this.type=r.Syntax.ImportDefaultSpecifier,this.local=e}return e}();t.ImportDefaultSpecifier=U;var z=function(){function e(e){this.type=r.Syntax.ImportNamespaceSpecifier,this.local=e}return e}();t.ImportNamespaceSpecifier=z;var G=function(){function e(e,t){this.type=r.Syntax.ImportSpecifier,this.local=e,this.imported=t}return e}();t.ImportSpecifier=G;var V=function(){function e(e,t){this.type=r.Syntax.LabeledStatement,this.label=e,this.body=t}return e}();t.LabeledStatement=V;var q=function(){function e(e,t){this.type=r.Syntax.Literal,this.value=e,this.raw=t}return e}();t.Literal=q;var H=function(){function e(e,t){this.type=r.Syntax.MetaProperty,this.meta=e,this.property=t}return e}();t.MetaProperty=H;var W=function(){function e(e,t,n,i,o){this.type=r.Syntax.MethodDefinition,this.key=e,this.computed=t,this.value=n,this.kind=i,this.static=o}return e}();t.MethodDefinition=W;var Q=function(){function e(e){this.type=r.Syntax.Program,this.body=e,this.sourceType="module"}return e}();t.Module=Q;var K=function(){function e(e,t){this.type=r.Syntax.NewExpression,this.callee=e,this.arguments=t}return e}();t.NewExpression=K;var J=function(){function e(e){this.type=r.Syntax.ObjectExpression,this.properties=e}return e}();t.ObjectExpression=J;var Y=function(){function e(e){this.type=r.Syntax.ObjectPattern,this.properties=e}return e}();t.ObjectPattern=Y;var X=function(){function e(e,t,n,i,o,a){this.type=r.Syntax.Property,this.key=t,this.computed=n,this.value=i,this.kind=e,this.method=o,this.shorthand=a}return e}();t.Property=X;var Z=function(){function e(e,t,n,i){this.type=r.Syntax.Literal,this.value=e,this.raw=t,this.regex={pattern:n,flags:i}}return e}();t.RegexLiteral=Z;var ee=function(){function e(e){this.type=r.Syntax.RestElement,this.argument=e}return e}();t.RestElement=ee;var te=function(){function e(e){this.type=r.Syntax.ReturnStatement,this.argument=e}return e}();t.ReturnStatement=te;var ne=function(){function e(e){this.type=r.Syntax.Program,this.body=e,this.sourceType="script"}return e}();t.Script=ne;var re=function(){function e(e){this.type=r.Syntax.SequenceExpression,this.expressions=e}return e}();t.SequenceExpression=re;var ie=function(){function e(e){this.type=r.Syntax.SpreadElement,this.argument=e}return e}();t.SpreadElement=ie;var oe=function(){function e(e,t){this.type=r.Syntax.MemberExpression,this.computed=!1,this.object=e,this.property=t}return e}();t.StaticMemberExpression=oe;var ae=function(){function e(){this.type=r.Syntax.Super}return e}();t.Super=ae;var se=function(){function e(e,t){this.type=r.Syntax.SwitchCase,this.test=e,this.consequent=t}return e}();t.SwitchCase=se;var ue=function(){function e(e,t){this.type=r.Syntax.SwitchStatement,this.discriminant=e,this.cases=t}return e}();t.SwitchStatement=ue;var ce=function(){function e(e,t){this.type=r.Syntax.TaggedTemplateExpression,this.tag=e,this.quasi=t}return e}();t.TaggedTemplateExpression=ce;var le=function(){function e(e,t){this.type=r.Syntax.TemplateElement,this.value=e,this.tail=t}return e}();t.TemplateElement=le;var pe=function(){function e(e,t){this.type=r.Syntax.TemplateLiteral,this.quasis=e,this.expressions=t}return e}();t.TemplateLiteral=pe;var fe=function(){function e(){this.type=r.Syntax.ThisExpression}return e}();t.ThisExpression=fe;var de=function(){function e(e){this.type=r.Syntax.ThrowStatement,this.argument=e}return e}();t.ThrowStatement=de;var he=function(){function e(e,t,n){this.type=r.Syntax.TryStatement,this.block=e,this.handler=t,this.finalizer=n}return e}();t.TryStatement=he;var me=function(){function e(e,t){this.type=r.Syntax.UnaryExpression,this.operator=e,this.argument=t,this.prefix=!0}return e}();t.UnaryExpression=me;var ge=function(){function e(e,t,n){this.type=r.Syntax.UpdateExpression,this.operator=e,this.argument=t,this.prefix=n}return e}();t.UpdateExpression=ge;var ye=function(){function e(e,t){this.type=r.Syntax.VariableDeclaration,this.declarations=e,this.kind=t}return e}();t.VariableDeclaration=ye;var ve=function(){function e(e,t){this.type=r.Syntax.VariableDeclarator,this.id=e,this.init=t}return e}();t.VariableDeclarator=ve;var be=function(){function e(e,t){this.type=r.Syntax.WhileStatement,this.test=e,this.body=t}return e}();t.WhileStatement=be;var xe=function(){function e(e,t){this.type=r.Syntax.WithStatement,this.object=e,this.body=t}return e}();t.WithStatement=xe;var Ce=function(){function e(e,t){this.type=r.Syntax.YieldExpression,this.argument=e,this.delegate=t}return e}();t.YieldExpression=Ce},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(9),i=n(10),o=n(11),a=n(7),s=n(12),u=n(2),c=n(13),l=function(){function e(e,t,n){void 0===t&&(t={}),this.config={range:"boolean"===typeof t.range&&t.range,loc:"boolean"===typeof t.loc&&t.loc,source:null,tokens:"boolean"===typeof t.tokens&&t.tokens,comment:"boolean"===typeof t.comment&&t.comment,tolerant:"boolean"===typeof t.tolerant&&t.tolerant},this.config.loc&&t.source&&null!==t.source&&(this.config.source=String(t.source)),this.delegate=n,this.errorHandler=new i.ErrorHandler,this.errorHandler.tolerant=this.config.tolerant,this.scanner=new s.Scanner(e,this.errorHandler),this.scanner.trackComment=this.config.comment,this.operatorPrecedence={")":0,";":0,",":0,"=":0,"]":0,"||":1,"&&":2,"|":3,"^":4,"&":5,"==":6,"!=":6,"===":6,"!==":6,"<":7,">":7,"<=":7,">=":7,"<<":8,">>":8,">>>":8,"+":9,"-":9,"*":11,"/":11,"%":11},this.lookahead={type:2,value:"",lineNumber:this.scanner.lineNumber,lineStart:0,start:0,end:0},this.hasLineTerminator=!1,this.context={isModule:!1,await:!1,allowIn:!0,allowStrictDirective:!0,allowYield:!0,firstCoverInitializedNameError:null,isAssignmentTarget:!1,isBindingElement:!1,inFunctionBody:!1,inIteration:!1,inSwitch:!1,labelSet:{},strict:!1},this.tokens=[],this.startMarker={index:0,line:this.scanner.lineNumber,column:0},this.lastMarker={index:0,line:this.scanner.lineNumber,column:0},this.nextToken(),this.lastMarker={index:this.scanner.index,line:this.scanner.lineNumber,column:this.scanner.index-this.scanner.lineStart}}return e.prototype.throwError=function(e){for(var t=[],n=1;n0&&this.delegate)for(var t=0;t>="===e||">>>="===e||"&="===e||"^="===e||"|="===e},e.prototype.isolateCoverGrammar=function(e){var t=this.context.isBindingElement,n=this.context.isAssignmentTarget,r=this.context.firstCoverInitializedNameError;this.context.isBindingElement=!0,this.context.isAssignmentTarget=!0,this.context.firstCoverInitializedNameError=null;var i=e.call(this);return null!==this.context.firstCoverInitializedNameError&&this.throwUnexpectedToken(this.context.firstCoverInitializedNameError),this.context.isBindingElement=t,this.context.isAssignmentTarget=n,this.context.firstCoverInitializedNameError=r,i},e.prototype.inheritCoverGrammar=function(e){var t=this.context.isBindingElement,n=this.context.isAssignmentTarget,r=this.context.firstCoverInitializedNameError;this.context.isBindingElement=!0,this.context.isAssignmentTarget=!0,this.context.firstCoverInitializedNameError=null;var i=e.call(this);return this.context.isBindingElement=this.context.isBindingElement&&t,this.context.isAssignmentTarget=this.context.isAssignmentTarget&&n,this.context.firstCoverInitializedNameError=r||this.context.firstCoverInitializedNameError,i},e.prototype.consumeSemicolon=function(){this.match(";")?this.nextToken():this.hasLineTerminator||(2===this.lookahead.type||this.match("}")||this.throwUnexpectedToken(this.lookahead),this.lastMarker.index=this.startMarker.index,this.lastMarker.line=this.startMarker.line,this.lastMarker.column=this.startMarker.column)},e.prototype.parsePrimaryExpression=function(){var e,t,n,r=this.createNode();switch(this.lookahead.type){case 3:(this.context.isModule||this.context.await)&&"await"===this.lookahead.value&&this.tolerateUnexpectedToken(this.lookahead),e=this.matchAsyncFunction()?this.parseFunctionExpression():this.finalize(r,new a.Identifier(this.nextToken().value));break;case 6:case 8:this.context.strict&&this.lookahead.octal&&this.tolerateUnexpectedToken(this.lookahead,o.Messages.StrictOctalLiteral),this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,t=this.nextToken(),n=this.getTokenRaw(t),e=this.finalize(r,new a.Literal(t.value,n));break;case 1:this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,t=this.nextToken(),n=this.getTokenRaw(t),e=this.finalize(r,new a.Literal("true"===t.value,n));break;case 5:this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,t=this.nextToken(),n=this.getTokenRaw(t),e=this.finalize(r,new a.Literal(null,n));break;case 10:e=this.parseTemplateLiteral();break;case 7:switch(this.lookahead.value){case"(":this.context.isBindingElement=!1,e=this.inheritCoverGrammar(this.parseGroupExpression);break;case"[":e=this.inheritCoverGrammar(this.parseArrayInitializer);break;case"{":e=this.inheritCoverGrammar(this.parseObjectInitializer);break;case"/":case"/=":this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,this.scanner.index=this.startMarker.index,t=this.nextRegexToken(),n=this.getTokenRaw(t),e=this.finalize(r,new a.RegexLiteral(t.regex,n,t.pattern,t.flags));break;default:e=this.throwUnexpectedToken(this.nextToken())}break;case 4:!this.context.strict&&this.context.allowYield&&this.matchKeyword("yield")?e=this.parseIdentifierName():!this.context.strict&&this.matchKeyword("let")?e=this.finalize(r,new a.Identifier(this.nextToken().value)):(this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,this.matchKeyword("function")?e=this.parseFunctionExpression():this.matchKeyword("this")?(this.nextToken(),e=this.finalize(r,new a.ThisExpression)):e=this.matchKeyword("class")?this.parseClassExpression():this.throwUnexpectedToken(this.nextToken()));break;default:e=this.throwUnexpectedToken(this.nextToken())}return e},e.prototype.parseSpreadElement=function(){var e=this.createNode();this.expect("...");var t=this.inheritCoverGrammar(this.parseAssignmentExpression);return this.finalize(e,new a.SpreadElement(t))},e.prototype.parseArrayInitializer=function(){var e=this.createNode(),t=[];for(this.expect("[");!this.match("]");)if(this.match(","))this.nextToken(),t.push(null);else if(this.match("...")){var n=this.parseSpreadElement();this.match("]")||(this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1,this.expect(",")),t.push(n)}else t.push(this.inheritCoverGrammar(this.parseAssignmentExpression)),this.match("]")||this.expect(",");return this.expect("]"),this.finalize(e,new a.ArrayExpression(t))},e.prototype.parsePropertyMethod=function(e){this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1;var t=this.context.strict,n=this.context.allowStrictDirective;this.context.allowStrictDirective=e.simple;var r=this.isolateCoverGrammar(this.parseFunctionSourceElements);return this.context.strict&&e.firstRestricted&&this.tolerateUnexpectedToken(e.firstRestricted,e.message),this.context.strict&&e.stricted&&this.tolerateUnexpectedToken(e.stricted,e.message),this.context.strict=t,this.context.allowStrictDirective=n,r},e.prototype.parsePropertyMethodFunction=function(){var e=this.createNode(),t=this.context.allowYield;this.context.allowYield=!1;var n=this.parseFormalParameters(),r=this.parsePropertyMethod(n);return this.context.allowYield=t,this.finalize(e,new a.FunctionExpression(null,n.params,r,!1))},e.prototype.parsePropertyMethodAsyncFunction=function(){var e=this.createNode(),t=this.context.allowYield,n=this.context.await;this.context.allowYield=!1,this.context.await=!0;var r=this.parseFormalParameters(),i=this.parsePropertyMethod(r);return this.context.allowYield=t,this.context.await=n,this.finalize(e,new a.AsyncFunctionExpression(null,r.params,i))},e.prototype.parseObjectPropertyKey=function(){var e,t=this.createNode(),n=this.nextToken();switch(n.type){case 8:case 6:this.context.strict&&n.octal&&this.tolerateUnexpectedToken(n,o.Messages.StrictOctalLiteral);var r=this.getTokenRaw(n);e=this.finalize(t,new a.Literal(n.value,r));break;case 3:case 1:case 5:case 4:e=this.finalize(t,new a.Identifier(n.value));break;case 7:"["===n.value?(e=this.isolateCoverGrammar(this.parseAssignmentExpression),this.expect("]")):e=this.throwUnexpectedToken(n);break;default:e=this.throwUnexpectedToken(n)}return e},e.prototype.isPropertyKey=function(e,t){return e.type===u.Syntax.Identifier&&e.name===t||e.type===u.Syntax.Literal&&e.value===t},e.prototype.parseObjectProperty=function(e){var t,n=this.createNode(),r=this.lookahead,i=null,s=null,u=!1,c=!1,l=!1,p=!1;if(3===r.type){var f=r.value;this.nextToken(),u=this.match("["),p=!this.hasLineTerminator&&"async"===f&&!this.match(":")&&!this.match("(")&&!this.match("*"),i=p?this.parseObjectPropertyKey():this.finalize(n,new a.Identifier(f))}else this.match("*")?this.nextToken():(u=this.match("["),i=this.parseObjectPropertyKey());var d=this.qualifiedPropertyName(this.lookahead);if(3===r.type&&!p&&"get"===r.value&&d)t="get",u=this.match("["),i=this.parseObjectPropertyKey(),this.context.allowYield=!1,s=this.parseGetterMethod();else if(3===r.type&&!p&&"set"===r.value&&d)t="set",u=this.match("["),i=this.parseObjectPropertyKey(),s=this.parseSetterMethod();else if(7===r.type&&"*"===r.value&&d)t="init",u=this.match("["),i=this.parseObjectPropertyKey(),s=this.parseGeneratorMethod(),c=!0;else if(i||this.throwUnexpectedToken(this.lookahead),t="init",this.match(":")&&!p)!u&&this.isPropertyKey(i,"__proto__")&&(e.value&&this.tolerateError(o.Messages.DuplicateProtoProperty),e.value=!0),this.nextToken(),s=this.inheritCoverGrammar(this.parseAssignmentExpression);else if(this.match("("))s=p?this.parsePropertyMethodAsyncFunction():this.parsePropertyMethodFunction(),c=!0;else if(3===r.type){var f=this.finalize(n,new a.Identifier(r.value));if(this.match("=")){this.context.firstCoverInitializedNameError=this.lookahead,this.nextToken(),l=!0;var h=this.isolateCoverGrammar(this.parseAssignmentExpression);s=this.finalize(n,new a.AssignmentPattern(f,h))}else l=!0,s=f}else this.throwUnexpectedToken(this.nextToken());return this.finalize(n,new a.Property(t,i,u,s,c,l))},e.prototype.parseObjectInitializer=function(){var e=this.createNode();this.expect("{");for(var t=[],n={value:!1};!this.match("}");)t.push(this.parseObjectProperty(n)),this.match("}")||this.expectCommaSeparator();return this.expect("}"),this.finalize(e,new a.ObjectExpression(t))},e.prototype.parseTemplateHead=function(){r.assert(this.lookahead.head,"Template literal must start with a template head");var e=this.createNode(),t=this.nextToken(),n=t.value,i=t.cooked;return this.finalize(e,new a.TemplateElement({raw:n,cooked:i},t.tail))},e.prototype.parseTemplateElement=function(){10!==this.lookahead.type&&this.throwUnexpectedToken();var e=this.createNode(),t=this.nextToken(),n=t.value,r=t.cooked;return this.finalize(e,new a.TemplateElement({raw:n,cooked:r},t.tail))},e.prototype.parseTemplateLiteral=function(){var e=this.createNode(),t=[],n=[],r=this.parseTemplateHead();for(n.push(r);!r.tail;)t.push(this.parseExpression()),r=this.parseTemplateElement(),n.push(r);return this.finalize(e,new a.TemplateLiteral(n,t))},e.prototype.reinterpretExpressionAsPattern=function(e){switch(e.type){case u.Syntax.Identifier:case u.Syntax.MemberExpression:case u.Syntax.RestElement:case u.Syntax.AssignmentPattern:break;case u.Syntax.SpreadElement:e.type=u.Syntax.RestElement,this.reinterpretExpressionAsPattern(e.argument);break;case u.Syntax.ArrayExpression:e.type=u.Syntax.ArrayPattern;for(var t=0;t")||this.expect("=>"),e={type:"ArrowParameterPlaceHolder",params:[],async:!1};else{var t=this.lookahead,n=[];if(this.match("..."))e=this.parseRestElement(n),this.expect(")"),this.match("=>")||this.expect("=>"),e={type:"ArrowParameterPlaceHolder",params:[e],async:!1};else{var r=!1;if(this.context.isBindingElement=!0,e=this.inheritCoverGrammar(this.parseAssignmentExpression),this.match(",")){var i=[];for(this.context.isAssignmentTarget=!1,i.push(e);2!==this.lookahead.type&&this.match(",");){if(this.nextToken(),this.match(")")){this.nextToken();for(var o=0;o")||this.expect("=>"),this.context.isBindingElement=!1;for(var o=0;o")&&(e.type===u.Syntax.Identifier&&"yield"===e.name&&(r=!0,e={type:"ArrowParameterPlaceHolder",params:[e],async:!1}),!r)){if(this.context.isBindingElement||this.throwUnexpectedToken(this.lookahead),e.type===u.Syntax.SequenceExpression)for(var o=0;o")){for(var u=0;u0){this.nextToken(),this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1;for(var i=[e,this.lookahead],o=t,s=this.isolateCoverGrammar(this.parseExponentiationExpression),u=[o,n.value,s],c=[r];;){if((r=this.binaryPrecedence(this.lookahead))<=0)break;for(;u.length>2&&r<=c[c.length-1];){s=u.pop();var l=u.pop();c.pop(),o=u.pop(),i.pop();var p=this.startNode(i[i.length-1]);u.push(this.finalize(p,new a.BinaryExpression(l,o,s)))}u.push(this.nextToken().value),c.push(r),i.push(this.lookahead),u.push(this.isolateCoverGrammar(this.parseExponentiationExpression))}var f=u.length-1;for(t=u[f],i.pop();f>1;){var p=this.startNode(i.pop()),l=u[f-1];t=this.finalize(p,new a.BinaryExpression(l,u[f-2],t)),f-=2}}return t},e.prototype.parseConditionalExpression=function(){var e=this.lookahead,t=this.inheritCoverGrammar(this.parseBinaryExpression);if(this.match("?")){this.nextToken();var n=this.context.allowIn;this.context.allowIn=!0;var r=this.isolateCoverGrammar(this.parseAssignmentExpression);this.context.allowIn=n,this.expect(":");var i=this.isolateCoverGrammar(this.parseAssignmentExpression);t=this.finalize(this.startNode(e),new a.ConditionalExpression(t,r,i)),this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1}return t},e.prototype.checkPatternParam=function(e,t){switch(t.type){case u.Syntax.Identifier:this.validateParam(e,t,t.name);break;case u.Syntax.RestElement:this.checkPatternParam(e,t.argument);break;case u.Syntax.AssignmentPattern:this.checkPatternParam(e,t.left);break;case u.Syntax.ArrayPattern:for(var n=0;n")){this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1;var i=e.async,s=this.reinterpretAsCoverFormalsList(e);if(s){this.hasLineTerminator&&this.tolerateUnexpectedToken(this.lookahead),this.context.firstCoverInitializedNameError=null;var c=this.context.strict,l=this.context.allowStrictDirective;this.context.allowStrictDirective=s.simple;var p=this.context.allowYield,f=this.context.await;this.context.allowYield=!0,this.context.await=i;var d=this.startNode(t);this.expect("=>");var h=void 0;if(this.match("{")){var m=this.context.allowIn;this.context.allowIn=!0,h=this.parseFunctionSourceElements(),this.context.allowIn=m}else h=this.isolateCoverGrammar(this.parseAssignmentExpression);var g=h.type!==u.Syntax.BlockStatement;this.context.strict&&s.firstRestricted&&this.throwUnexpectedToken(s.firstRestricted,s.message),this.context.strict&&s.stricted&&this.tolerateUnexpectedToken(s.stricted,s.message),e=i?this.finalize(d,new a.AsyncArrowFunctionExpression(s.params,h,g)):this.finalize(d,new a.ArrowFunctionExpression(s.params,h,g)),this.context.strict=c,this.context.allowStrictDirective=l,this.context.allowYield=p,this.context.await=f}}else if(this.matchAssign()){if(this.context.isAssignmentTarget||this.tolerateError(o.Messages.InvalidLHSInAssignment),this.context.strict&&e.type===u.Syntax.Identifier){var y=e;this.scanner.isRestrictedWord(y.name)&&this.tolerateUnexpectedToken(n,o.Messages.StrictLHSAssignment),this.scanner.isStrictModeReservedWord(y.name)&&this.tolerateUnexpectedToken(n,o.Messages.StrictReservedWord)}this.match("=")?this.reinterpretExpressionAsPattern(e):(this.context.isAssignmentTarget=!1,this.context.isBindingElement=!1),n=this.nextToken();var v=n.value,b=this.isolateCoverGrammar(this.parseAssignmentExpression);e=this.finalize(this.startNode(t),new a.AssignmentExpression(v,e,b)),this.context.firstCoverInitializedNameError=null}}return e},e.prototype.parseExpression=function(){var e=this.lookahead,t=this.isolateCoverGrammar(this.parseAssignmentExpression);if(this.match(",")){var n=[];for(n.push(t);2!==this.lookahead.type&&this.match(",");)this.nextToken(),n.push(this.isolateCoverGrammar(this.parseAssignmentExpression));t=this.finalize(this.startNode(e),new a.SequenceExpression(n))}return t},e.prototype.parseStatementListItem=function(){var e;if(this.context.isAssignmentTarget=!0,this.context.isBindingElement=!0,4===this.lookahead.type)switch(this.lookahead.value){case"export":this.context.isModule||this.tolerateUnexpectedToken(this.lookahead,o.Messages.IllegalExportDeclaration),e=this.parseExportDeclaration();break;case"import":this.context.isModule||this.tolerateUnexpectedToken(this.lookahead,o.Messages.IllegalImportDeclaration),e=this.parseImportDeclaration();break;case"const":e=this.parseLexicalDeclaration({inFor:!1});break;case"function":e=this.parseFunctionDeclaration();break;case"class":e=this.parseClassDeclaration();break;case"let":e=this.isLexicalDeclaration()?this.parseLexicalDeclaration({inFor:!1}):this.parseStatement();break;default:e=this.parseStatement()}else e=this.parseStatement();return e},e.prototype.parseBlock=function(){var e=this.createNode();this.expect("{");for(var t=[];;){if(this.match("}"))break;t.push(this.parseStatementListItem())}return this.expect("}"),this.finalize(e,new a.BlockStatement(t))},e.prototype.parseLexicalBinding=function(e,t){var n=this.createNode(),r=[],i=this.parsePattern(r,e);this.context.strict&&i.type===u.Syntax.Identifier&&this.scanner.isRestrictedWord(i.name)&&this.tolerateError(o.Messages.StrictVarName);var s=null;return"const"===e?this.matchKeyword("in")||this.matchContextualKeyword("of")||(this.match("=")?(this.nextToken(),s=this.isolateCoverGrammar(this.parseAssignmentExpression)):this.throwError(o.Messages.DeclarationMissingInitializer,"const")):(!t.inFor&&i.type!==u.Syntax.Identifier||this.match("="))&&(this.expect("="),s=this.isolateCoverGrammar(this.parseAssignmentExpression)),this.finalize(n,new a.VariableDeclarator(i,s))},e.prototype.parseBindingList=function(e,t){for(var n=[this.parseLexicalBinding(e,t)];this.match(",");)this.nextToken(),n.push(this.parseLexicalBinding(e,t));return n},e.prototype.isLexicalDeclaration=function(){var e=this.scanner.saveState();this.scanner.scanComments();var t=this.scanner.lex();return this.scanner.restoreState(e),3===t.type||7===t.type&&"["===t.value||7===t.type&&"{"===t.value||4===t.type&&"let"===t.value||4===t.type&&"yield"===t.value},e.prototype.parseLexicalDeclaration=function(e){var t=this.createNode(),n=this.nextToken().value;r.assert("let"===n||"const"===n,"Lexical declaration must be either let or const");var i=this.parseBindingList(n,e);return this.consumeSemicolon(),this.finalize(t,new a.VariableDeclaration(i,n))},e.prototype.parseBindingRestElement=function(e,t){var n=this.createNode();this.expect("...");var r=this.parsePattern(e,t);return this.finalize(n,new a.RestElement(r))},e.prototype.parseArrayPattern=function(e,t){var n=this.createNode();this.expect("[");for(var r=[];!this.match("]");)if(this.match(","))this.nextToken(),r.push(null);else{if(this.match("...")){r.push(this.parseBindingRestElement(e,t));break}r.push(this.parsePatternWithDefault(e,t)),this.match("]")||this.expect(",")}return this.expect("]"),this.finalize(n,new a.ArrayPattern(r))},e.prototype.parsePropertyPattern=function(e,t){var n,r,i=this.createNode(),o=!1,s=!1;if(3===this.lookahead.type){var u=this.lookahead;n=this.parseVariableIdentifier();var c=this.finalize(i,new a.Identifier(u.value));if(this.match("=")){e.push(u),s=!0,this.nextToken();var l=this.parseAssignmentExpression();r=this.finalize(this.startNode(u),new a.AssignmentPattern(c,l))}else this.match(":")?(this.expect(":"),r=this.parsePatternWithDefault(e,t)):(e.push(u),s=!0,r=c)}else o=this.match("["),n=this.parseObjectPropertyKey(),this.expect(":"),r=this.parsePatternWithDefault(e,t);return this.finalize(i,new a.Property("init",n,o,r,!1,s))},e.prototype.parseObjectPattern=function(e,t){var n=this.createNode(),r=[];for(this.expect("{");!this.match("}");)r.push(this.parsePropertyPattern(e,t)),this.match("}")||this.expect(",");return this.expect("}"),this.finalize(n,new a.ObjectPattern(r))},e.prototype.parsePattern=function(e,t){var n;return this.match("[")?n=this.parseArrayPattern(e,t):this.match("{")?n=this.parseObjectPattern(e,t):(!this.matchKeyword("let")||"const"!==t&&"let"!==t||this.tolerateUnexpectedToken(this.lookahead,o.Messages.LetInLexicalBinding),e.push(this.lookahead),n=this.parseVariableIdentifier(t)),n},e.prototype.parsePatternWithDefault=function(e,t){var n=this.lookahead,r=this.parsePattern(e,t);if(this.match("=")){this.nextToken();var i=this.context.allowYield;this.context.allowYield=!0;var o=this.isolateCoverGrammar(this.parseAssignmentExpression);this.context.allowYield=i,r=this.finalize(this.startNode(n),new a.AssignmentPattern(r,o))}return r},e.prototype.parseVariableIdentifier=function(e){var t=this.createNode(),n=this.nextToken();return 4===n.type&&"yield"===n.value?this.context.strict?this.tolerateUnexpectedToken(n,o.Messages.StrictReservedWord):this.context.allowYield||this.throwUnexpectedToken(n):3!==n.type?this.context.strict&&4===n.type&&this.scanner.isStrictModeReservedWord(n.value)?this.tolerateUnexpectedToken(n,o.Messages.StrictReservedWord):(this.context.strict||"let"!==n.value||"var"!==e)&&this.throwUnexpectedToken(n):(this.context.isModule||this.context.await)&&3===n.type&&"await"===n.value&&this.tolerateUnexpectedToken(n),this.finalize(t,new a.Identifier(n.value))},e.prototype.parseVariableDeclaration=function(e){var t=this.createNode(),n=[],r=this.parsePattern(n,"var");this.context.strict&&r.type===u.Syntax.Identifier&&this.scanner.isRestrictedWord(r.name)&&this.tolerateError(o.Messages.StrictVarName);var i=null;return this.match("=")?(this.nextToken(),i=this.isolateCoverGrammar(this.parseAssignmentExpression)):r.type===u.Syntax.Identifier||e.inFor||this.expect("="),this.finalize(t,new a.VariableDeclarator(r,i))},e.prototype.parseVariableDeclarationList=function(e){var t={inFor:e.inFor},n=[];for(n.push(this.parseVariableDeclaration(t));this.match(",");)this.nextToken(),n.push(this.parseVariableDeclaration(t));return n},e.prototype.parseVariableStatement=function(){var e=this.createNode();this.expectKeyword("var");var t=this.parseVariableDeclarationList({inFor:!1});return this.consumeSemicolon(),this.finalize(e,new a.VariableDeclaration(t,"var"))},e.prototype.parseEmptyStatement=function(){var e=this.createNode();return this.expect(";"),this.finalize(e,new a.EmptyStatement)},e.prototype.parseExpressionStatement=function(){var e=this.createNode(),t=this.parseExpression();return this.consumeSemicolon(),this.finalize(e,new a.ExpressionStatement(t))},e.prototype.parseIfClause=function(){return this.context.strict&&this.matchKeyword("function")&&this.tolerateError(o.Messages.StrictFunction),this.parseStatement()},e.prototype.parseIfStatement=function(){var e,t=this.createNode(),n=null;this.expectKeyword("if"),this.expect("(");var r=this.parseExpression();return!this.match(")")&&this.config.tolerant?(this.tolerateUnexpectedToken(this.nextToken()),e=this.finalize(this.createNode(),new a.EmptyStatement)):(this.expect(")"),e=this.parseIfClause(),this.matchKeyword("else")&&(this.nextToken(),n=this.parseIfClause())),this.finalize(t,new a.IfStatement(r,e,n))},e.prototype.parseDoWhileStatement=function(){var e=this.createNode();this.expectKeyword("do");var t=this.context.inIteration;this.context.inIteration=!0;var n=this.parseStatement();this.context.inIteration=t,this.expectKeyword("while"),this.expect("(");var r=this.parseExpression();return!this.match(")")&&this.config.tolerant?this.tolerateUnexpectedToken(this.nextToken()):(this.expect(")"),this.match(";")&&this.nextToken()),this.finalize(e,new a.DoWhileStatement(n,r))},e.prototype.parseWhileStatement=function(){var e,t=this.createNode();this.expectKeyword("while"),this.expect("(");var n=this.parseExpression();if(!this.match(")")&&this.config.tolerant)this.tolerateUnexpectedToken(this.nextToken()),e=this.finalize(this.createNode(),new a.EmptyStatement);else{this.expect(")");var r=this.context.inIteration;this.context.inIteration=!0,e=this.parseStatement(),this.context.inIteration=r}return this.finalize(t,new a.WhileStatement(n,e))},e.prototype.parseForStatement=function(){var e,t,n=null,r=null,i=null,s=!0,c=this.createNode();if(this.expectKeyword("for"),this.expect("("),this.match(";"))this.nextToken();else if(this.matchKeyword("var")){n=this.createNode(),this.nextToken();var l=this.context.allowIn;this.context.allowIn=!1;var p=this.parseVariableDeclarationList({inFor:!0});if(this.context.allowIn=l,1===p.length&&this.matchKeyword("in")){var f=p[0];f.init&&(f.id.type===u.Syntax.ArrayPattern||f.id.type===u.Syntax.ObjectPattern||this.context.strict)&&this.tolerateError(o.Messages.ForInOfLoopInitializer,"for-in"),n=this.finalize(n,new a.VariableDeclaration(p,"var")),this.nextToken(),e=n,t=this.parseExpression(),n=null}else 1===p.length&&null===p[0].init&&this.matchContextualKeyword("of")?(n=this.finalize(n,new a.VariableDeclaration(p,"var")),this.nextToken(),e=n,t=this.parseAssignmentExpression(),n=null,s=!1):(n=this.finalize(n,new a.VariableDeclaration(p,"var")),this.expect(";"))}else if(this.matchKeyword("const")||this.matchKeyword("let")){n=this.createNode();var d=this.nextToken().value;if(this.context.strict||"in"!==this.lookahead.value){var l=this.context.allowIn;this.context.allowIn=!1;var p=this.parseBindingList(d,{inFor:!0});this.context.allowIn=l,1===p.length&&null===p[0].init&&this.matchKeyword("in")?(n=this.finalize(n,new a.VariableDeclaration(p,d)),this.nextToken(),e=n,t=this.parseExpression(),n=null):1===p.length&&null===p[0].init&&this.matchContextualKeyword("of")?(n=this.finalize(n,new a.VariableDeclaration(p,d)),this.nextToken(),e=n,t=this.parseAssignmentExpression(),n=null,s=!1):(this.consumeSemicolon(),n=this.finalize(n,new a.VariableDeclaration(p,d)))}else n=this.finalize(n,new a.Identifier(d)),this.nextToken(),e=n,t=this.parseExpression(),n=null}else{var h=this.lookahead,l=this.context.allowIn;if(this.context.allowIn=!1,n=this.inheritCoverGrammar(this.parseAssignmentExpression),this.context.allowIn=l,this.matchKeyword("in"))this.context.isAssignmentTarget&&n.type!==u.Syntax.AssignmentExpression||this.tolerateError(o.Messages.InvalidLHSInForIn),this.nextToken(),this.reinterpretExpressionAsPattern(n),e=n,t=this.parseExpression(),n=null;else if(this.matchContextualKeyword("of"))this.context.isAssignmentTarget&&n.type!==u.Syntax.AssignmentExpression||this.tolerateError(o.Messages.InvalidLHSInForLoop),this.nextToken(),this.reinterpretExpressionAsPattern(n),e=n,t=this.parseAssignmentExpression(),n=null,s=!1;else{if(this.match(",")){for(var m=[n];this.match(",");)this.nextToken(),m.push(this.isolateCoverGrammar(this.parseAssignmentExpression));n=this.finalize(this.startNode(h),new a.SequenceExpression(m))}this.expect(";")}}"undefined"===typeof e&&(this.match(";")||(r=this.parseExpression()),this.expect(";"),this.match(")")||(i=this.parseExpression()));var g;if(!this.match(")")&&this.config.tolerant)this.tolerateUnexpectedToken(this.nextToken()),g=this.finalize(this.createNode(),new a.EmptyStatement);else{this.expect(")");var y=this.context.inIteration;this.context.inIteration=!0,g=this.isolateCoverGrammar(this.parseStatement),this.context.inIteration=y}return"undefined"===typeof e?this.finalize(c,new a.ForStatement(n,r,i,g)):s?this.finalize(c,new a.ForInStatement(e,t,g)):this.finalize(c,new a.ForOfStatement(e,t,g))},e.prototype.parseContinueStatement=function(){var e=this.createNode();this.expectKeyword("continue");var t=null;if(3===this.lookahead.type&&!this.hasLineTerminator){var n=this.parseVariableIdentifier();t=n;var r="$"+n.name;Object.prototype.hasOwnProperty.call(this.context.labelSet,r)||this.throwError(o.Messages.UnknownLabel,n.name)}return this.consumeSemicolon(),null!==t||this.context.inIteration||this.throwError(o.Messages.IllegalContinue),this.finalize(e,new a.ContinueStatement(t))},e.prototype.parseBreakStatement=function(){var e=this.createNode();this.expectKeyword("break");var t=null;if(3===this.lookahead.type&&!this.hasLineTerminator){var n=this.parseVariableIdentifier(),r="$"+n.name;Object.prototype.hasOwnProperty.call(this.context.labelSet,r)||this.throwError(o.Messages.UnknownLabel,n.name),t=n}return this.consumeSemicolon(),null!==t||this.context.inIteration||this.context.inSwitch||this.throwError(o.Messages.IllegalBreak),this.finalize(e,new a.BreakStatement(t))},e.prototype.parseReturnStatement=function(){this.context.inFunctionBody||this.tolerateError(o.Messages.IllegalReturn);var e=this.createNode();this.expectKeyword("return");var t=!this.match(";")&&!this.match("}")&&!this.hasLineTerminator&&2!==this.lookahead.type,n=t?this.parseExpression():null;return this.consumeSemicolon(),this.finalize(e,new a.ReturnStatement(n))},e.prototype.parseWithStatement=function(){this.context.strict&&this.tolerateError(o.Messages.StrictModeWith);var e,t=this.createNode();this.expectKeyword("with"),this.expect("(");var n=this.parseExpression();return!this.match(")")&&this.config.tolerant?(this.tolerateUnexpectedToken(this.nextToken()),e=this.finalize(this.createNode(),new a.EmptyStatement)):(this.expect(")"),e=this.parseStatement()),this.finalize(t,new a.WithStatement(n,e))},e.prototype.parseSwitchCase=function(){var e,t=this.createNode();this.matchKeyword("default")?(this.nextToken(),e=null):(this.expectKeyword("case"),e=this.parseExpression()),this.expect(":");for(var n=[];;){if(this.match("}")||this.matchKeyword("default")||this.matchKeyword("case"))break;n.push(this.parseStatementListItem())}return this.finalize(t,new a.SwitchCase(e,n))},e.prototype.parseSwitchStatement=function(){var e=this.createNode();this.expectKeyword("switch"),this.expect("(");var t=this.parseExpression();this.expect(")");var n=this.context.inSwitch;this.context.inSwitch=!0;var r=[],i=!1;for(this.expect("{");;){if(this.match("}"))break;var s=this.parseSwitchCase();null===s.test&&(i&&this.throwError(o.Messages.MultipleDefaultsInSwitch),i=!0),r.push(s)}return this.expect("}"),this.context.inSwitch=n,this.finalize(e,new a.SwitchStatement(t,r))},e.prototype.parseLabelledStatement=function(){var e,t=this.createNode(),n=this.parseExpression();if(n.type===u.Syntax.Identifier&&this.match(":")){this.nextToken();var r=n,i="$"+r.name;Object.prototype.hasOwnProperty.call(this.context.labelSet,i)&&this.throwError(o.Messages.Redeclaration,"Label",r.name),this.context.labelSet[i]=!0;var s=void 0;if(this.matchKeyword("class"))this.tolerateUnexpectedToken(this.lookahead),s=this.parseClassDeclaration();else if(this.matchKeyword("function")){var c=this.lookahead,l=this.parseFunctionDeclaration();this.context.strict?this.tolerateUnexpectedToken(c,o.Messages.StrictFunction):l.generator&&this.tolerateUnexpectedToken(c,o.Messages.GeneratorInLegacyContext),s=l}else s=this.parseStatement();delete this.context.labelSet[i],e=new a.LabeledStatement(r,s)}else this.consumeSemicolon(),e=new a.ExpressionStatement(n);return this.finalize(t,e)},e.prototype.parseThrowStatement=function(){var e=this.createNode();this.expectKeyword("throw"),this.hasLineTerminator&&this.throwError(o.Messages.NewlineAfterThrow);var t=this.parseExpression();return this.consumeSemicolon(),this.finalize(e,new a.ThrowStatement(t))},e.prototype.parseCatchClause=function(){var e=this.createNode();this.expectKeyword("catch"),this.expect("("),this.match(")")&&this.throwUnexpectedToken(this.lookahead);for(var t=[],n=this.parsePattern(t),r={},i=0;i0&&this.tolerateError(o.Messages.BadGetterArity);var r=this.parsePropertyMethod(n);return this.context.allowYield=t,this.finalize(e,new a.FunctionExpression(null,n.params,r,!1))},e.prototype.parseSetterMethod=function(){var e=this.createNode(),t=this.context.allowYield;this.context.allowYield=!1;var n=this.parseFormalParameters();1!==n.params.length?this.tolerateError(o.Messages.BadSetterArity):n.params[0]instanceof a.RestElement&&this.tolerateError(o.Messages.BadSetterRestParameter);var r=this.parsePropertyMethod(n);return this.context.allowYield=t,this.finalize(e,new a.FunctionExpression(null,n.params,r,!1))},e.prototype.parseGeneratorMethod=function(){var e=this.createNode(),t=this.context.allowYield;this.context.allowYield=!0;var n=this.parseFormalParameters();this.context.allowYield=!1;var r=this.parsePropertyMethod(n);return this.context.allowYield=t,this.finalize(e,new a.FunctionExpression(null,n.params,r,!0))},e.prototype.isStartOfExpression=function(){var e=!0,t=this.lookahead.value;switch(this.lookahead.type){case 7:e="["===t||"("===t||"{"===t||"+"===t||"-"===t||"!"===t||"~"===t||"++"===t||"--"===t||"/"===t||"/="===t;break;case 4:e="class"===t||"delete"===t||"function"===t||"let"===t||"new"===t||"super"===t||"this"===t||"typeof"===t||"void"===t||"yield"===t}return e},e.prototype.parseYieldExpression=function(){var e=this.createNode();this.expectKeyword("yield");var t=null,n=!1;if(!this.hasLineTerminator){var r=this.context.allowYield;this.context.allowYield=!1,n=this.match("*"),n?(this.nextToken(),t=this.parseAssignmentExpression()):this.isStartOfExpression()&&(t=this.parseAssignmentExpression()),this.context.allowYield=r}return this.finalize(e,new a.YieldExpression(t,n))},e.prototype.parseClassElement=function(e){var t=this.lookahead,n=this.createNode(),r="",i=null,s=null,u=!1,c=!1,l=!1,p=!1;if(this.match("*"))this.nextToken();else{u=this.match("["),i=this.parseObjectPropertyKey();if("static"===i.name&&(this.qualifiedPropertyName(this.lookahead)||this.match("*"))&&(t=this.lookahead,l=!0,u=this.match("["),this.match("*")?this.nextToken():i=this.parseObjectPropertyKey()),3===t.type&&!this.hasLineTerminator&&"async"===t.value){var f=this.lookahead.value;":"!==f&&"("!==f&&"*"!==f&&(p=!0,t=this.lookahead,i=this.parseObjectPropertyKey(),3===t.type&&("get"===t.value||"set"===t.value?this.tolerateUnexpectedToken(t):"constructor"===t.value&&this.tolerateUnexpectedToken(t,o.Messages.ConstructorIsAsync)))}}var d=this.qualifiedPropertyName(this.lookahead);return 3===t.type?"get"===t.value&&d?(r="get",u=this.match("["),i=this.parseObjectPropertyKey(),this.context.allowYield=!1,s=this.parseGetterMethod()):"set"===t.value&&d&&(r="set",u=this.match("["),i=this.parseObjectPropertyKey(),s=this.parseSetterMethod()):7===t.type&&"*"===t.value&&d&&(r="init",u=this.match("["),i=this.parseObjectPropertyKey(),s=this.parseGeneratorMethod(),c=!0),!r&&i&&this.match("(")&&(r="init",s=p?this.parsePropertyMethodAsyncFunction():this.parsePropertyMethodFunction(),c=!0),r||this.throwUnexpectedToken(this.lookahead),"init"===r&&(r="method"),u||(l&&this.isPropertyKey(i,"prototype")&&this.throwUnexpectedToken(t,o.Messages.StaticPrototype),!l&&this.isPropertyKey(i,"constructor")&&(("method"!==r||!c||s&&s.generator)&&this.throwUnexpectedToken(t,o.Messages.ConstructorSpecialMethod),e.value?this.throwUnexpectedToken(t,o.Messages.DuplicateConstructor):e.value=!0,r="constructor")),this.finalize(n,new a.MethodDefinition(i,u,s,r,l))},e.prototype.parseClassElementList=function(){var e=[],t={value:!1};for(this.expect("{");!this.match("}");)this.match(";")?this.nextToken():e.push(this.parseClassElement(t));return this.expect("}"),e},e.prototype.parseClassBody=function(){var e=this.createNode(),t=this.parseClassElementList();return this.finalize(e,new a.ClassBody(t))},e.prototype.parseClassDeclaration=function(e){var t=this.createNode(),n=this.context.strict;this.context.strict=!0,this.expectKeyword("class");var r=e&&3!==this.lookahead.type?null:this.parseVariableIdentifier(),i=null;this.matchKeyword("extends")&&(this.nextToken(),i=this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall));var o=this.parseClassBody();return this.context.strict=n,this.finalize(t,new a.ClassDeclaration(r,i,o))},e.prototype.parseClassExpression=function(){var e=this.createNode(),t=this.context.strict;this.context.strict=!0,this.expectKeyword("class");var n=3===this.lookahead.type?this.parseVariableIdentifier():null,r=null;this.matchKeyword("extends")&&(this.nextToken(),r=this.isolateCoverGrammar(this.parseLeftHandSideExpressionAllowCall));var i=this.parseClassBody();return this.context.strict=t,this.finalize(e,new a.ClassExpression(n,r,i))},e.prototype.parseModule=function(){this.context.strict=!0,this.context.isModule=!0;for(var e=this.createNode(),t=this.parseDirectivePrologues();2!==this.lookahead.type;)t.push(this.parseStatementListItem());return this.finalize(e,new a.Module(t))},e.prototype.parseScript=function(){for(var e=this.createNode(),t=this.parseDirectivePrologues();2!==this.lookahead.type;)t.push(this.parseStatementListItem());return this.finalize(e,new a.Script(t))},e.prototype.parseModuleSpecifier=function(){var e=this.createNode();8!==this.lookahead.type&&this.throwError(o.Messages.InvalidModuleSpecifier);var t=this.nextToken(),n=this.getTokenRaw(t);return this.finalize(e,new a.Literal(t.value,n))},e.prototype.parseImportSpecifier=function(){var e,t,n=this.createNode();return 3===this.lookahead.type?(e=this.parseVariableIdentifier(),t=e,this.matchContextualKeyword("as")&&(this.nextToken(),t=this.parseVariableIdentifier())):(e=this.parseIdentifierName(),t=e,this.matchContextualKeyword("as")?(this.nextToken(),t=this.parseVariableIdentifier()):this.throwUnexpectedToken(this.nextToken())),this.finalize(n,new a.ImportSpecifier(t,e))},e.prototype.parseNamedImports=function(){this.expect("{");for(var e=[];!this.match("}");)e.push(this.parseImportSpecifier()),this.match("}")||this.expect(",");return this.expect("}"),e},e.prototype.parseImportDefaultSpecifier=function(){var e=this.createNode(),t=this.parseIdentifierName();return this.finalize(e,new a.ImportDefaultSpecifier(t))},e.prototype.parseImportNamespaceSpecifier=function(){var e=this.createNode();this.expect("*"),this.matchContextualKeyword("as")||this.throwError(o.Messages.NoAsAfterImportNamespace),this.nextToken();var t=this.parseIdentifierName();return this.finalize(e,new a.ImportNamespaceSpecifier(t))},e.prototype.parseImportDeclaration=function(){this.context.inFunctionBody&&this.throwError(o.Messages.IllegalImportDeclaration);var e=this.createNode();this.expectKeyword("import");var t,n=[];if(8===this.lookahead.type)t=this.parseModuleSpecifier();else{if(this.match("{")?n=n.concat(this.parseNamedImports()):this.match("*")?n.push(this.parseImportNamespaceSpecifier()):this.isIdentifierName(this.lookahead)&&!this.matchKeyword("default")?(n.push(this.parseImportDefaultSpecifier()),this.match(",")&&(this.nextToken(),this.match("*")?n.push(this.parseImportNamespaceSpecifier()):this.match("{")?n=n.concat(this.parseNamedImports()):this.throwUnexpectedToken(this.lookahead))):this.throwUnexpectedToken(this.nextToken()),!this.matchContextualKeyword("from")){var r=this.lookahead.value?o.Messages.UnexpectedToken:o.Messages.MissingFromClause;this.throwError(r,this.lookahead.value)}this.nextToken(),t=this.parseModuleSpecifier()}return this.consumeSemicolon(),this.finalize(e,new a.ImportDeclaration(n,t))},e.prototype.parseExportSpecifier=function(){var e=this.createNode(),t=this.parseIdentifierName(),n=t;return this.matchContextualKeyword("as")&&(this.nextToken(),n=this.parseIdentifierName()),this.finalize(e,new a.ExportSpecifier(t,n))},e.prototype.parseExportDeclaration=function(){this.context.inFunctionBody&&this.throwError(o.Messages.IllegalExportDeclaration);var e=this.createNode();this.expectKeyword("export");var t;if(this.matchKeyword("default"))if(this.nextToken(),this.matchKeyword("function")){var n=this.parseFunctionDeclaration(!0);t=this.finalize(e,new a.ExportDefaultDeclaration(n))}else if(this.matchKeyword("class")){var n=this.parseClassDeclaration(!0);t=this.finalize(e,new a.ExportDefaultDeclaration(n))}else if(this.matchContextualKeyword("async")){var n=this.matchAsyncFunction()?this.parseFunctionDeclaration(!0):this.parseAssignmentExpression();t=this.finalize(e,new a.ExportDefaultDeclaration(n))}else{this.matchContextualKeyword("from")&&this.throwError(o.Messages.UnexpectedToken,this.lookahead.value);var n=this.match("{")?this.parseObjectInitializer():this.match("[")?this.parseArrayInitializer():this.parseAssignmentExpression();this.consumeSemicolon(),t=this.finalize(e,new a.ExportDefaultDeclaration(n))}else if(this.match("*")){if(this.nextToken(),!this.matchContextualKeyword("from")){var r=this.lookahead.value?o.Messages.UnexpectedToken:o.Messages.MissingFromClause;this.throwError(r,this.lookahead.value)}this.nextToken();var i=this.parseModuleSpecifier();this.consumeSemicolon(),t=this.finalize(e,new a.ExportAllDeclaration(i))}else if(4===this.lookahead.type){var n=void 0;switch(this.lookahead.value){case"let":case"const":n=this.parseLexicalDeclaration({inFor:!1});break;case"var":case"class":case"function":n=this.parseStatementListItem();break;default:this.throwUnexpectedToken(this.lookahead)}t=this.finalize(e,new a.ExportNamedDeclaration(n,[],null))}else if(this.matchAsyncFunction()){var n=this.parseFunctionDeclaration();t=this.finalize(e,new a.ExportNamedDeclaration(n,[],null))}else{var s=[],u=null,c=!1;for(this.expect("{");!this.match("}");)c=c||this.matchKeyword("default"),s.push(this.parseExportSpecifier()),this.match("}")||this.expect(",");if(this.expect("}"),this.matchContextualKeyword("from"))this.nextToken(),u=this.parseModuleSpecifier(),this.consumeSemicolon();else if(c){var r=this.lookahead.value?o.Messages.UnexpectedToken:o.Messages.MissingFromClause;this.throwError(r,this.lookahead.value)}else this.consumeSemicolon();t=this.finalize(e,new a.ExportNamedDeclaration(null,s,u))}return t},e}();t.Parser=l},function(e,t){"use strict";function n(e,t){if(!e)throw new Error("ASSERT: "+t)}Object.defineProperty(t,"__esModule",{value:!0}),t.assert=n},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=function(){function e(){this.errors=[],this.tolerant=!1}return e.prototype.recordError=function(e){this.errors.push(e)},e.prototype.tolerate=function(e){if(!this.tolerant)throw e;this.recordError(e)},e.prototype.constructError=function(e,t){var n=new Error(e);try{throw n}catch(e){Object.create&&Object.defineProperty&&(n=Object.create(e),Object.defineProperty(n,"column",{value:t}))}return n},e.prototype.createError=function(e,t,n,r){var i="Line "+t+": "+r,o=this.constructError(i,n);return o.index=e,o.lineNumber=t,o.description=r,o},e.prototype.throwError=function(e,t,n,r){throw this.createError(e,t,n,r)},e.prototype.tolerateError=function(e,t,n,r){var i=this.createError(e,t,n,r);if(!this.tolerant)throw i;this.recordError(i)},e}();t.ErrorHandler=n},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Messages={BadGetterArity:"Getter must not have any formal parameters",BadSetterArity:"Setter must have exactly one formal parameter",BadSetterRestParameter:"Setter function argument must not be a rest parameter",ConstructorIsAsync:"Class constructor may not be an async method",ConstructorSpecialMethod:"Class constructor may not be an accessor",DeclarationMissingInitializer:"Missing initializer in %0 declaration",DefaultRestParameter:"Unexpected token =",DuplicateBinding:"Duplicate binding %0",DuplicateConstructor:"A class may only have one constructor",DuplicateProtoProperty:"Duplicate __proto__ fields are not allowed in object literals",ForInOfLoopInitializer:"%0 loop variable declaration may not have an initializer",GeneratorInLegacyContext:"Generator declarations are not allowed in legacy contexts",IllegalBreak:"Illegal break statement",IllegalContinue:"Illegal continue statement",IllegalExportDeclaration:"Unexpected token",IllegalImportDeclaration:"Unexpected token",IllegalLanguageModeDirective:"Illegal 'use strict' directive in function with non-simple parameter list",IllegalReturn:"Illegal return statement",InvalidEscapedReservedWord:"Keyword must not contain escaped characters",InvalidHexEscapeSequence:"Invalid hexadecimal escape sequence",InvalidLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",InvalidLHSInForLoop:"Invalid left-hand side in for-loop",InvalidModuleSpecifier:"Unexpected token",InvalidRegExp:"Invalid regular expression",LetInLexicalBinding:"let is disallowed as a lexically bound name",MissingFromClause:"Unexpected token",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NewlineAfterThrow:"Illegal newline after throw",NoAsAfterImportNamespace:"Unexpected token",NoCatchOrFinally:"Missing catch or finally after try",ParameterAfterRestParameter:"Rest parameter must be last formal parameter",Redeclaration:"%0 '%1' has already been declared",StaticPrototype:"Classes may not have static property named prototype",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictDelete:"Delete of an unqualified identifier in strict mode.",StrictFunction:"In strict mode code, functions can only be declared at top level or inside a block",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictModeWith:"Strict mode code may not include a with statement",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictReservedWord:"Use of future reserved word in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",TemplateOctalLiteral:"Octal literals are not allowed in template strings.",UnexpectedEOS:"Unexpected end of input",UnexpectedIdentifier:"Unexpected identifier",UnexpectedNumber:"Unexpected number",UnexpectedReserved:"Unexpected reserved word",UnexpectedString:"Unexpected string",UnexpectedTemplate:"Unexpected quasi %0",UnexpectedToken:"Unexpected token %0",UnexpectedTokenIllegal:"Unexpected token ILLEGAL",UnknownLabel:"Undefined label '%0'",UnterminatedRegExp:"Invalid regular expression: missing /"}},function(e,t,n){"use strict";function r(e){return"0123456789abcdef".indexOf(e.toLowerCase())}function i(e){return"01234567".indexOf(e)}Object.defineProperty(t,"__esModule",{value:!0});var o=n(9),a=n(4),s=n(11),u=function(){function e(e,t){this.source=e,this.errorHandler=t,this.trackComment=!1,this.length=e.length,this.index=0,this.lineNumber=e.length>0?1:0,this.lineStart=0,this.curlyStack=[]}return e.prototype.saveState=function(){return{index:this.index,lineNumber:this.lineNumber,lineStart:this.lineStart}},e.prototype.restoreState=function(e){this.index=e.index,this.lineNumber=e.lineNumber,this.lineStart=e.lineStart},e.prototype.eof=function(){return this.index>=this.length},e.prototype.throwUnexpectedToken=function(e){return void 0===e&&(e=s.Messages.UnexpectedTokenIllegal),this.errorHandler.throwError(this.index,this.lineNumber,this.index-this.lineStart+1,e)},e.prototype.tolerateUnexpectedToken=function(e){void 0===e&&(e=s.Messages.UnexpectedTokenIllegal),this.errorHandler.tolerateError(this.index,this.lineNumber,this.index-this.lineStart+1,e)},e.prototype.skipSingleLineComment=function(e){var t,n,r=[];for(this.trackComment&&(r=[],t=this.index-e,n={start:{line:this.lineNumber,column:this.index-this.lineStart-e},end:{}});!this.eof();){var i=this.source.charCodeAt(this.index);if(++this.index,a.Character.isLineTerminator(i)){if(this.trackComment){n.end={line:this.lineNumber,column:this.index-this.lineStart-1};var o={multiLine:!1,slice:[t+e,this.index-1],range:[t,this.index-1],loc:n};r.push(o)}return 13===i&&10===this.source.charCodeAt(this.index)&&++this.index,++this.lineNumber,this.lineStart=this.index,r}}if(this.trackComment){n.end={line:this.lineNumber,column:this.index-this.lineStart};var o={multiLine:!1,slice:[t+e,this.index],range:[t,this.index],loc:n};r.push(o)}return r},e.prototype.skipMultiLineComment=function(){var e,t,n=[];for(this.trackComment&&(n=[],e=this.index-2,t={start:{line:this.lineNumber,column:this.index-this.lineStart-2},end:{}});!this.eof();){var r=this.source.charCodeAt(this.index);if(a.Character.isLineTerminator(r))13===r&&10===this.source.charCodeAt(this.index+1)&&++this.index,++this.lineNumber,++this.index,this.lineStart=this.index;else if(42===r){if(47===this.source.charCodeAt(this.index+1)){if(this.index+=2,this.trackComment){t.end={line:this.lineNumber,column:this.index-this.lineStart};var i={multiLine:!0,slice:[e+2,this.index-2],range:[e,this.index],loc:t};n.push(i)}return n}++this.index}else++this.index}if(this.trackComment){t.end={line:this.lineNumber,column:this.index-this.lineStart};var i={multiLine:!0,slice:[e+2,this.index],range:[e,this.index],loc:t};n.push(i)}return this.tolerateUnexpectedToken(),n},e.prototype.scanComments=function(){var e;this.trackComment&&(e=[]);for(var t=0===this.index;!this.eof();){var n=this.source.charCodeAt(this.index);if(a.Character.isWhiteSpace(n))++this.index;else if(a.Character.isLineTerminator(n))++this.index,13===n&&10===this.source.charCodeAt(this.index)&&++this.index,++this.lineNumber,this.lineStart=this.index,t=!0;else if(47===n)if(47===(n=this.source.charCodeAt(this.index+1))){this.index+=2;var r=this.skipSingleLineComment(2);this.trackComment&&(e=e.concat(r)),t=!0}else{if(42!==n)break;this.index+=2;var r=this.skipMultiLineComment();this.trackComment&&(e=e.concat(r))}else if(t&&45===n){if(45!==this.source.charCodeAt(this.index+1)||62!==this.source.charCodeAt(this.index+2))break;this.index+=3;var r=this.skipSingleLineComment(3);this.trackComment&&(e=e.concat(r))}else{if(60!==n)break;if("!--"!==this.source.slice(this.index+1,this.index+4))break;this.index+=4;var r=this.skipSingleLineComment(4);this.trackComment&&(e=e.concat(r))}}return e},e.prototype.isFutureReservedWord=function(e){switch(e){case"enum":case"export":case"import":case"super":return!0;default:return!1}},e.prototype.isStrictModeReservedWord=function(e){switch(e){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"yield":case"let":return!0;default:return!1}},e.prototype.isRestrictedWord=function(e){return"eval"===e||"arguments"===e},e.prototype.isKeyword=function(e){switch(e.length){case 2:return"if"===e||"in"===e||"do"===e;case 3:return"var"===e||"for"===e||"new"===e||"try"===e||"let"===e;case 4:return"this"===e||"else"===e||"case"===e||"void"===e||"with"===e||"enum"===e;case 5:return"while"===e||"break"===e||"catch"===e||"throw"===e||"const"===e||"yield"===e||"class"===e||"super"===e;case 6:return"return"===e||"typeof"===e||"delete"===e||"switch"===e||"export"===e||"import"===e;case 7:return"default"===e||"finally"===e||"extends"===e;case 8:return"function"===e||"continue"===e||"debugger"===e;case 10:return"instanceof"===e;default:return!1}},e.prototype.codePointAt=function(e){var t=this.source.charCodeAt(e);if(t>=55296&&t<=56319){var n=this.source.charCodeAt(e+1);if(n>=56320&&n<=57343){t=1024*(t-55296)+n-56320+65536}}return t},e.prototype.scanHexEscape=function(e){for(var t="u"===e?4:2,n=0,i=0;i1114111||"}"!==e)&&this.throwUnexpectedToken(),a.Character.fromCodePoint(t)},e.prototype.getIdentifier=function(){for(var e=this.index++;!this.eof();){var t=this.source.charCodeAt(this.index);if(92===t)return this.index=e,this.getComplexIdentifier();if(t>=55296&&t<57343)return this.index=e,this.getComplexIdentifier();if(!a.Character.isIdentifierPart(t))break;++this.index}return this.source.slice(e,this.index)},e.prototype.getComplexIdentifier=function(){var e=this.codePointAt(this.index),t=a.Character.fromCodePoint(e);this.index+=t.length;var n;for(92===e&&(117!==this.source.charCodeAt(this.index)&&this.throwUnexpectedToken(),++this.index,"{"===this.source[this.index]?(++this.index,n=this.scanUnicodeCodePointEscape()):null!==(n=this.scanHexEscape("u"))&&"\\"!==n&&a.Character.isIdentifierStart(n.charCodeAt(0))||this.throwUnexpectedToken(),t=n);!this.eof()&&(e=this.codePointAt(this.index),a.Character.isIdentifierPart(e));)n=a.Character.fromCodePoint(e),t+=n,this.index+=n.length,92===e&&(t=t.substr(0,t.length-1),117!==this.source.charCodeAt(this.index)&&this.throwUnexpectedToken(),++this.index,"{"===this.source[this.index]?(++this.index,n=this.scanUnicodeCodePointEscape()):null!==(n=this.scanHexEscape("u"))&&"\\"!==n&&a.Character.isIdentifierPart(n.charCodeAt(0))||this.throwUnexpectedToken(),t+=n);return t},e.prototype.octalToDecimal=function(e){var t="0"!==e,n=i(e);return!this.eof()&&a.Character.isOctalDigit(this.source.charCodeAt(this.index))&&(t=!0,n=8*n+i(this.source[this.index++]),"0123".indexOf(e)>=0&&!this.eof()&&a.Character.isOctalDigit(this.source.charCodeAt(this.index))&&(n=8*n+i(this.source[this.index++]))),{code:n,octal:t}},e.prototype.scanIdentifier=function(){var e,t=this.index,n=92===this.source.charCodeAt(t)?this.getComplexIdentifier():this.getIdentifier();if(3!==(e=1===n.length?3:this.isKeyword(n)?4:"null"===n?5:"true"===n||"false"===n?1:3)&&t+n.length!==this.index){var r=this.index;this.index=t,this.tolerateUnexpectedToken(s.Messages.InvalidEscapedReservedWord),this.index=r}return{type:e,value:n,lineNumber:this.lineNumber,lineStart:this.lineStart,start:t,end:this.index}},e.prototype.scanPunctuator=function(){var e=this.index,t=this.source[this.index];switch(t){case"(":case"{":"{"===t&&this.curlyStack.push("{"),++this.index;break;case".":++this.index,"."===this.source[this.index]&&"."===this.source[this.index+1]&&(this.index+=2,t="...");break;case"}":++this.index,this.curlyStack.pop();break;case")":case";":case",":case"[":case"]":case":":case"?":case"~":++this.index;break;default:t=this.source.substr(this.index,4),">>>="===t?this.index+=4:(t=t.substr(0,3),"==="===t||"!=="===t||">>>"===t||"<<="===t||">>="===t||"**="===t?this.index+=3:(t=t.substr(0,2),"&&"===t||"||"===t||"=="===t||"!="===t||"+="===t||"-="===t||"*="===t||"/="===t||"++"===t||"--"===t||"<<"===t||">>"===t||"&="===t||"|="===t||"^="===t||"%="===t||"<="===t||">="===t||"=>"===t||"**"===t?this.index+=2:(t=this.source[this.index],"<>=!+-*%&|^/".indexOf(t)>=0&&++this.index)))}return this.index===e&&this.throwUnexpectedToken(),{type:7,value:t,lineNumber:this.lineNumber,lineStart:this.lineStart,start:e,end:this.index}},e.prototype.scanHexLiteral=function(e){for(var t="";!this.eof()&&a.Character.isHexDigit(this.source.charCodeAt(this.index));)t+=this.source[this.index++];return 0===t.length&&this.throwUnexpectedToken(),a.Character.isIdentifierStart(this.source.charCodeAt(this.index))&&this.throwUnexpectedToken(),{type:6,value:parseInt("0x"+t,16),lineNumber:this.lineNumber,lineStart:this.lineStart,start:e,end:this.index}},e.prototype.scanBinaryLiteral=function(e){for(var t,n="";!this.eof()&&("0"===(t=this.source[this.index])||"1"===t);)n+=this.source[this.index++];return 0===n.length&&this.throwUnexpectedToken(),this.eof()||(t=this.source.charCodeAt(this.index),(a.Character.isIdentifierStart(t)||a.Character.isDecimalDigit(t))&&this.throwUnexpectedToken()),{type:6,value:parseInt(n,2),lineNumber:this.lineNumber,lineStart:this.lineStart,start:e,end:this.index}},e.prototype.scanOctalLiteral=function(e,t){var n="",r=!1;for(a.Character.isOctalDigit(e.charCodeAt(0))?(r=!0,n="0"+this.source[this.index++]):++this.index;!this.eof()&&a.Character.isOctalDigit(this.source.charCodeAt(this.index));)n+=this.source[this.index++];return r||0!==n.length||this.throwUnexpectedToken(),(a.Character.isIdentifierStart(this.source.charCodeAt(this.index))||a.Character.isDecimalDigit(this.source.charCodeAt(this.index)))&&this.throwUnexpectedToken(),{type:6,value:parseInt(n,8),octal:r,lineNumber:this.lineNumber,lineStart:this.lineStart,start:t,end:this.index}},e.prototype.isImplicitOctalLiteral=function(){for(var e=this.index+1;e=0&&(n=n.replace(/\\u\{([0-9a-fA-F]+)\}|\\u([a-fA-F0-9]{4})/g,function(e,t,n){var i=parseInt(t||n,16);return i>1114111&&r.throwUnexpectedToken(s.Messages.InvalidRegExp),i<=65535?String.fromCharCode(i):"\uffff"}).replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g,"\uffff"));try{RegExp(n)}catch(e){this.throwUnexpectedToken(s.Messages.InvalidRegExp)}try{return new RegExp(e,t)}catch(e){return null}},e.prototype.scanRegExpBody=function(){var e=this.source[this.index];o.assert("/"===e,"Regular expression literal must start with a slash");for(var t=this.source[this.index++],n=!1,r=!1;!this.eof();)if(e=this.source[this.index++],t+=e,"\\"===e)e=this.source[this.index++],a.Character.isLineTerminator(e.charCodeAt(0))&&this.throwUnexpectedToken(s.Messages.UnterminatedRegExp),t+=e;else if(a.Character.isLineTerminator(e.charCodeAt(0)))this.throwUnexpectedToken(s.Messages.UnterminatedRegExp);else if(n)"]"===e&&(n=!1);else{if("/"===e){r=!0;break}"["===e&&(n=!0)}return r||this.throwUnexpectedToken(s.Messages.UnterminatedRegExp),t.substr(1,t.length-2)},e.prototype.scanRegExpFlags=function(){for(var e="",t="";!this.eof();){var n=this.source[this.index];if(!a.Character.isIdentifierPart(n.charCodeAt(0)))break;if(++this.index,"\\"!==n||this.eof())t+=n,e+=n;else if("u"===(n=this.source[this.index])){++this.index;var r=this.index,i=this.scanHexEscape("u");if(null!==i)for(t+=i,e+="\\u";r=55296&&e<57343&&a.Character.isIdentifierStart(this.codePointAt(this.index))?this.scanIdentifier():this.scanPunctuator()},e}();t.Scanner=u},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.TokenName={},t.TokenName[1]="Boolean",t.TokenName[2]="",t.TokenName[3]="Identifier",t.TokenName[4]="Keyword",t.TokenName[5]="Null",t.TokenName[6]="Numeric",t.TokenName[7]="Punctuator",t.TokenName[8]="String",t.TokenName[9]="RegularExpression",t.TokenName[10]="Template"},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.XHTMLEntities={quot:'"',amp:"&",apos:"'",gt:">",nbsp:"\xa0",iexcl:"\xa1",cent:"\xa2",pound:"\xa3",curren:"\xa4",yen:"\xa5",brvbar:"\xa6",sect:"\xa7",uml:"\xa8",copy:"\xa9",ordf:"\xaa",laquo:"\xab",not:"\xac",shy:"\xad",reg:"\xae",macr:"\xaf",deg:"\xb0",plusmn:"\xb1",sup2:"\xb2",sup3:"\xb3",acute:"\xb4",micro:"\xb5",para:"\xb6",middot:"\xb7",cedil:"\xb8",sup1:"\xb9",ordm:"\xba",raquo:"\xbb",frac14:"\xbc",frac12:"\xbd",frac34:"\xbe",iquest:"\xbf",Agrave:"\xc0",Aacute:"\xc1",Acirc:"\xc2",Atilde:"\xc3",Auml:"\xc4",Aring:"\xc5",AElig:"\xc6",Ccedil:"\xc7",Egrave:"\xc8",Eacute:"\xc9",Ecirc:"\xca",Euml:"\xcb",Igrave:"\xcc",Iacute:"\xcd",Icirc:"\xce",Iuml:"\xcf",ETH:"\xd0",Ntilde:"\xd1",Ograve:"\xd2",Oacute:"\xd3",Ocirc:"\xd4",Otilde:"\xd5",Ouml:"\xd6",times:"\xd7",Oslash:"\xd8",Ugrave:"\xd9",Uacute:"\xda",Ucirc:"\xdb",Uuml:"\xdc",Yacute:"\xdd",THORN:"\xde",szlig:"\xdf",agrave:"\xe0",aacute:"\xe1",acirc:"\xe2",atilde:"\xe3",auml:"\xe4",aring:"\xe5",aelig:"\xe6",ccedil:"\xe7",egrave:"\xe8",eacute:"\xe9",ecirc:"\xea",euml:"\xeb",igrave:"\xec",iacute:"\xed",icirc:"\xee",iuml:"\xef",eth:"\xf0",ntilde:"\xf1",ograve:"\xf2",oacute:"\xf3",ocirc:"\xf4",otilde:"\xf5",ouml:"\xf6",divide:"\xf7",oslash:"\xf8",ugrave:"\xf9",uacute:"\xfa",ucirc:"\xfb",uuml:"\xfc",yacute:"\xfd",thorn:"\xfe",yuml:"\xff",OElig:"\u0152",oelig:"\u0153",Scaron:"\u0160",scaron:"\u0161",Yuml:"\u0178",fnof:"\u0192",circ:"\u02c6",tilde:"\u02dc",Alpha:"\u0391",Beta:"\u0392",Gamma:"\u0393",Delta:"\u0394",Epsilon:"\u0395",Zeta:"\u0396",Eta:"\u0397",Theta:"\u0398",Iota:"\u0399",Kappa:"\u039a",Lambda:"\u039b",Mu:"\u039c",Nu:"\u039d",Xi:"\u039e",Omicron:"\u039f",Pi:"\u03a0",Rho:"\u03a1",Sigma:"\u03a3",Tau:"\u03a4",Upsilon:"\u03a5",Phi:"\u03a6",Chi:"\u03a7",Psi:"\u03a8",Omega:"\u03a9",alpha:"\u03b1",beta:"\u03b2",gamma:"\u03b3",delta:"\u03b4",epsilon:"\u03b5",zeta:"\u03b6",eta:"\u03b7",theta:"\u03b8",iota:"\u03b9",kappa:"\u03ba",lambda:"\u03bb",mu:"\u03bc",nu:"\u03bd",xi:"\u03be",omicron:"\u03bf",pi:"\u03c0",rho:"\u03c1",sigmaf:"\u03c2",sigma:"\u03c3",tau:"\u03c4",upsilon:"\u03c5",phi:"\u03c6",chi:"\u03c7",psi:"\u03c8",omega:"\u03c9",thetasym:"\u03d1",upsih:"\u03d2",piv:"\u03d6",ensp:"\u2002",emsp:"\u2003",thinsp:"\u2009",zwnj:"\u200c",zwj:"\u200d",lrm:"\u200e",rlm:"\u200f",ndash:"\u2013",mdash:"\u2014",lsquo:"\u2018",rsquo:"\u2019",sbquo:"\u201a",ldquo:"\u201c",rdquo:"\u201d",bdquo:"\u201e",dagger:"\u2020",Dagger:"\u2021",bull:"\u2022",hellip:"\u2026",permil:"\u2030",prime:"\u2032",Prime:"\u2033",lsaquo:"\u2039",rsaquo:"\u203a",oline:"\u203e",frasl:"\u2044",euro:"\u20ac",image:"\u2111",weierp:"\u2118",real:"\u211c",trade:"\u2122",alefsym:"\u2135",larr:"\u2190",uarr:"\u2191",rarr:"\u2192",darr:"\u2193",harr:"\u2194",crarr:"\u21b5",lArr:"\u21d0",uArr:"\u21d1",rArr:"\u21d2",dArr:"\u21d3",hArr:"\u21d4",forall:"\u2200",part:"\u2202",exist:"\u2203",empty:"\u2205",nabla:"\u2207",isin:"\u2208",notin:"\u2209",ni:"\u220b",prod:"\u220f",sum:"\u2211",minus:"\u2212",lowast:"\u2217",radic:"\u221a",prop:"\u221d",infin:"\u221e",ang:"\u2220",and:"\u2227",or:"\u2228",cap:"\u2229",cup:"\u222a",int:"\u222b",there4:"\u2234",sim:"\u223c",cong:"\u2245",asymp:"\u2248",ne:"\u2260",equiv:"\u2261",le:"\u2264",ge:"\u2265",sub:"\u2282",sup:"\u2283",nsub:"\u2284",sube:"\u2286",supe:"\u2287",oplus:"\u2295",otimes:"\u2297",perp:"\u22a5",sdot:"\u22c5",lceil:"\u2308",rceil:"\u2309",lfloor:"\u230a",rfloor:"\u230b",loz:"\u25ca",spades:"\u2660",clubs:"\u2663",hearts:"\u2665",diams:"\u2666",lang:"\u27e8",rang:"\u27e9"}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(10),i=n(12),o=n(13),a=function(){function e(){this.values=[],this.curly=this.paren=-1}return e.prototype.beforeFunctionExpression=function(e){return["(","{","[","in","typeof","instanceof","new","return","case","delete","throw","void","=","+=","-=","*=","**=","/=","%=","<<=",">>=",">>>=","&=","|=","^=",",","+","-","*","**","/","%","++","--","<<",">>",">>>","&","|","^","!","~","&&","||","?",":","===","==",">=","<=","<",">","!=","!=="].indexOf(e)>=0},e.prototype.isRegexStart=function(){var e=this.values[this.values.length-1],t=null!==e;switch(e){case"this":case"]":t=!1;break;case")":var n=this.values[this.paren-1];t="if"===n||"while"===n||"for"===n||"with"===n;break;case"}":if(t=!1,"function"===this.values[this.curly-3]){var r=this.values[this.curly-4];t=!!r&&!this.beforeFunctionExpression(r)}else if("function"===this.values[this.curly-4]){var r=this.values[this.curly-5];t=!r||!this.beforeFunctionExpression(r)}}return t},e.prototype.push=function(e){7===e.type||4===e.type?("{"===e.value?this.curly=this.values.length:"("===e.value&&(this.paren=this.values.length),this.values.push(e.value)):this.values.push(null)},e}(),s=function(){function e(e,t){this.errorHandler=new r.ErrorHandler,this.errorHandler.tolerant=!!t&&("boolean"===typeof t.tolerant&&t.tolerant),this.scanner=new i.Scanner(e,this.errorHandler),this.scanner.trackComment=!!t&&("boolean"===typeof t.comment&&t.comment),this.trackRange=!!t&&("boolean"===typeof t.range&&t.range),this.trackLoc=!!t&&("boolean"===typeof t.loc&&t.loc),this.buffer=[],this.reader=new a}return e.prototype.errors=function(){return this.errorHandler.errors},e.prototype.getNextToken=function(){if(0===this.buffer.length){var e=this.scanner.scanComments();if(this.scanner.trackComment)for(var t=0;tr&&" "!==e[h+1],h=o);else if(!l(a))return le;m=m&&p(a)}u=u||d&&o-h-1>r&&" "!==e[h+1]}return s||u?" "===e[0]&&n>9?le:u?ce:ue:m&&!i(e)?ae:se}function h(e,t,n,r){e.dump=function(){function i(t){return u(e,t)}if(0===t.length)return"''";if(!e.noCompatMode&&-1!==oe.indexOf(t))return"'"+t+"'";var o=e.indent*Math.max(1,n),s=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-o),c=r||e.flowLevel>-1&&n>=e.flowLevel;switch(d(t,c,e.indent,s,i)){case ae:return t;case se:return"'"+t.replace(/'/g,"''")+"'";case ue:return"|"+m(t,e.indent)+g(a(t,o));case ce:return">"+m(t,e.indent)+g(a(y(t,s),o));case le:return'"'+b(t)+'"';default:throw new F("impossible error: invalid scalar style")}}()}function m(e,t){var n=" "===e[0]?String(t):"",r="\n"===e[e.length-1];return n+(!r||"\n"!==e[e.length-2]&&"\n"!==e?r?"":"-":"+")+"\n"}function g(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function y(e,t){for(var n,r,i=/(\n+)([^\n]*)/g,o=function(){var n=e.indexOf("\n");return n=-1!==n?n:e.length,i.lastIndex=n,v(e.slice(0,n),t)}(),a="\n"===e[0]||" "===e[0];r=i.exec(e);){var s=r[1],u=r[2];n=" "===u[0],o+=s+(a||n||""===u?"":"\n")+v(u,t),a=n}return o}function v(e,t){if(""===e||" "===e[0])return e;for(var n,r,i=/ [^ ]/g,o=0,a=0,s=0,u="";n=i.exec(e);)s=n.index,s-o>t&&(r=a>o?a:s,u+="\n"+e.slice(o,r),o=r+1),a=s;return u+="\n",e.length-o>t&&a>o?u+=e.slice(o,a)+"\n"+e.slice(a+1):u+=e.slice(o),u.slice(1)}function b(e){for(var t,n,r,o="",a=0;a=55296&&t<=56319&&(n=e.charCodeAt(a+1))>=56320&&n<=57343?(o+=i(1024*(t-55296)+n-56320+65536),a++):(r=ie[t],o+=!r&&l(t)?e[a]:r||i(t));return o}function x(e,t,n){var r,i,o="",a=e.tag;for(r=0,i=n.length;r1024&&(s+="? "),s+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),S(e,t,a,!1,!1)&&(s+=e.dump,u+=s));e.tag=c,e.dump="{"+u+"}"}function D(e,t,n,r){var i,o,a,u,c,l,p="",f=e.tag,d=Object.keys(n);if(!0===e.sortKeys)d.sort();else if("function"===typeof e.sortKeys)d.sort(e.sortKeys);else if(e.sortKeys)throw new F("sortKeys must be a boolean or a function");for(i=0,o=d.length;i1024,c&&(e.dump&&j===e.dump.charCodeAt(0)?l+="?":l+="? "),l+=e.dump,c&&(l+=s(e,t)),S(e,t+1,u,!0,c)&&(e.dump&&j===e.dump.charCodeAt(0)?l+=":":l+=": ",l+=e.dump,p+=l));e.tag=f,e.dump=p||"{}"}function w(e,t,n){var r,i,o,a,s,u;for(i=n?e.explicitTypes:e.implicitTypes,o=0,a=i.length;o tag resolver accepts not "'+u+'" style');r=s.represent[u](t,u)}e.dump=r}return!0}return!1}function S(e,t,n,r,i,o){e.tag=null,e.dump=n,w(e,n,!1)||w(e,n,!0);var a=L.call(e.dump);r&&(r=e.flowLevel<0||e.flowLevel>t);var s,u,c="[object Object]"===a||"[object Array]"===a;if(c&&(s=e.duplicates.indexOf(n),u=-1!==s),(null!==e.tag&&"?"!==e.tag||u||2!==e.indent&&t>0)&&(i=!1),u&&e.usedDuplicates[s])e.dump="*ref_"+s;else{if(c&&u&&!e.usedDuplicates[s]&&(e.usedDuplicates[s]=!0),"[object Object]"===a)r&&0!==Object.keys(e.dump).length?(D(e,t,e.dump,i),u&&(e.dump="&ref_"+s+e.dump)):(E(e,t,e.dump),u&&(e.dump="&ref_"+s+" "+e.dump));else if("[object Array]"===a)r&&0!==e.dump.length?(C(e,t,e.dump,i),u&&(e.dump="&ref_"+s+e.dump)):(x(e,t,e.dump),u&&(e.dump="&ref_"+s+" "+e.dump));else{if("[object String]"!==a){if(e.skipInvalid)return!1;throw new F("unacceptable kind of an object to dump "+a)}"?"!==e.tag&&h(e,e.dump,t,o)}null!==e.tag&&"?"!==e.tag&&(e.dump="!<"+e.tag+"> "+e.dump)}return!0}function k(e,t){var n,r,i=[],o=[];for(A(e,i,o),n=0,r=o.length;n - }, - (playground.HandlerConfig) { - Path: (string) (len=26) "/playground/playground.css", - Handler: (http.HandlerFunc) - }, - (playground.HandlerConfig) { - Path: (string) (len=25) "/playground/playground.js", - Handler: (http.HandlerFunc) - }, - (playground.HandlerConfig) { - Path: (string) (len=23) "/playground/favicon.png", - Handler: (http.HandlerFunc) - }, - (playground.HandlerConfig) { - Path: (string) (len=20) "/playground/logo.png", - Handler: (http.HandlerFunc) - } -} diff --git a/pkg/playground/playground.go b/pkg/playground/playground.go deleted file mode 100644 index 1addb7fc6..000000000 --- a/pkg/playground/playground.go +++ /dev/null @@ -1,186 +0,0 @@ -// Package playground is a http.Handler hosting the GraphQL Playground application. -package playground - -import ( - "embed" - "fmt" - "html/template" - "net/http" - "path" - "strings" -) - -const ( - playgroundTemplate = "playgroundTemplate" - - contentTypeHeader = "Content-Type" - contentTypeImagePNG = "image/png" - contentTypeTextHTML = "text/html" - contentTypeTextCSS = "text/css" - contentTypeTextJavascript = "text/javascript" - - cssFile = "playground.css" - jsFile = "playground.js" - faviconFile = "favicon.png" - logoFile = "logo.png" -) - -//go:embed files/* -var files embed.FS - -// Config is the configuration Object to instruct ConfigureHandlers on how to setup all the http Handlers for the playground -type Config struct { - // PathPrefix is a prefix you intend to put in front of all handlers - PathPrefix string - // PlaygroundPath is the Path where the playground website should be hosted - PlaygroundPath string - // GraphqlEndpointPath is the Path where the http Handler for synchronous (Query,Mutation) GraphQL requests should be hosted - GraphqlEndpointPath string - // GraphQLSubscriptionEndpointPath is the Path where the http Handler for asynchronous (Subscription) GraphQL requests should be hosted - GraphQLSubscriptionEndpointPath string -} - -type playgroundTemplateData struct { - CssURL string - JsURL string - FavIconURL string - LogoURL string - EndpointURL string - SubscriptionEndpointURL string -} - -type fileConfig struct { - name string - url string - contentType string -} - -// HandlerConfig is the configuration Object for playground http Handlers -type HandlerConfig struct { - // Path is where the handler should be hosted - Path string - // Handler is the http.HandlerFunc that should be hosted on the corresponding Path - Handler http.HandlerFunc -} - -// Handlers is an array of HandlerConfig -// The playground expects that you make all assigned Handlers available on the corresponding Path -type Handlers []HandlerConfig - -func (h *Handlers) add(path string, handler http.HandlerFunc) { - *h = append(*h, HandlerConfig{ - Path: path, - Handler: handler, - }) -} - -// Playground manages the configuration of all HTTP handlers responsible for serving the GraphQL Playground -type Playground struct { - cfg Config - files []fileConfig - data playgroundTemplateData -} - -// New creates a Playground for given Config -func New(config Config) *Playground { - prepareURL := func(file string) string { - return strings.TrimPrefix(path.Join(config.PlaygroundPath, file), "/") - } - - data := playgroundTemplateData{ - CssURL: prepareURL(cssFile), - JsURL: prepareURL(jsFile), - FavIconURL: prepareURL(faviconFile), - LogoURL: prepareURL(logoFile), - EndpointURL: config.GraphqlEndpointPath, - SubscriptionEndpointURL: config.GraphQLSubscriptionEndpointPath, - } - - files := []fileConfig{ - { - name: cssFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, cssFile), - contentType: contentTypeTextCSS, - }, - { - name: jsFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, jsFile), - contentType: contentTypeTextJavascript, - }, - { - name: faviconFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, faviconFile), - contentType: contentTypeImagePNG, - }, - { - name: logoFile, - url: path.Join(config.PathPrefix, config.PlaygroundPath, logoFile), - contentType: contentTypeImagePNG, - }, - } - - return &Playground{ - cfg: config, - files: files, - data: data, - } -} - -// Handlers configures and returns all Handlers for the Playground -func (p *Playground) Handlers() (handlers Handlers, err error) { - handlers = make(Handlers, 0, len(p.files)+1) - - if err = p.configurePlaygroundHandler(&handlers); err != nil { - return - } - - for _, file := range p.files { - if err = p.configureFileHandler(&handlers, file); err != nil { - return - } - } - - return -} - -func (p *Playground) configurePlaygroundHandler(handlers *Handlers) (err error) { - playgroundHTML, err := files.ReadFile("files/playground.html") - if err != nil { - return - } - templates, err := template.New(playgroundTemplate).Parse(string(playgroundHTML)) - if err != nil { - return - } - - playgroundURL := path.Join(p.cfg.PathPrefix, p.cfg.PlaygroundPath) - if playgroundURL != "/" && (playgroundURL == "" || strings.HasSuffix(p.cfg.PlaygroundPath, "/") || - (p.cfg.PlaygroundPath == "" && strings.HasSuffix(p.cfg.PathPrefix, "/"))) { - playgroundURL += "/" - } - - handlers.add(playgroundURL, func(writer http.ResponseWriter, request *http.Request) { - writer.Header().Add(contentTypeHeader, contentTypeTextHTML) - - if err := templates.ExecuteTemplate(writer, playgroundTemplate, p.data); err != nil { - writer.WriteHeader(http.StatusInternalServerError) - _, _ = writer.Write([]byte(err.Error())) - } - }) - - return nil -} - -func (p *Playground) configureFileHandler(handlers *Handlers, file fileConfig) error { - data, err := files.ReadFile(fmt.Sprintf("files/%s", file.name)) - if err != nil { - return err - } - - handlers.add(file.url, func(writer http.ResponseWriter, request *http.Request) { - writer.Header().Add(contentTypeHeader, file.contentType) - _, _ = writer.Write(data) - }) - - return nil -} diff --git a/pkg/playground/playground_test.go b/pkg/playground/playground_test.go deleted file mode 100644 index 83d8a32dd..000000000 --- a/pkg/playground/playground_test.go +++ /dev/null @@ -1,104 +0,0 @@ -package playground - -import ( - "bytes" - "os" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/jensneuse/diffview" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/goldie" -) - -func TestNew(t *testing.T) { - t.Run("should prefix asset paths with slash (/) even when prefix path is empty", func(t *testing.T) { - config := Config{ - PathPrefix: "", - PlaygroundPath: "/playground", - GraphqlEndpointPath: "/graphql", - GraphQLSubscriptionEndpointPath: "/graphqlws", - } - - playground := New(config) - - assert.Equal(t, playground.data.CssURL, "playground/playground.css") - assert.Equal(t, playground.data.JsURL, "playground/playground.js") - assert.Equal(t, playground.data.FavIconURL, "playground/favicon.png") - assert.Equal(t, playground.data.LogoURL, "playground/logo.png") - }) -} - -func TestConfigureHandlers(t *testing.T) { - t.Run("should create handlers", func(t *testing.T) { - config := Config{ - PathPrefix: "/", - PlaygroundPath: "/playground", - GraphqlEndpointPath: "/graphql", - GraphQLSubscriptionEndpointPath: "/graphqlws", - } - - p := New(config) - - handlers, err := p.Handlers() - if err != nil { - t.Fatal(err) - } - - for i := range handlers { - handlers[i].Handler = nil - } - - var out bytes.Buffer - spew.Fdump(&out, handlers) - - goldie.Assert(t, "handlers", out.Bytes()) - if t.Failed() { - fixture, err := os.ReadFile("./fixtures/handlers.golden") - if err != nil { - t.Fatal(err) - } - - diffview.NewGoland().DiffViewBytes("handlers", fixture, out.Bytes()) - } - }) - - t.Run("should respect trailing slash for playground path", func(t *testing.T) { - config := Config{ - PathPrefix: "/", - PlaygroundPath: "/playground/", - GraphqlEndpointPath: "/graphql", - GraphQLSubscriptionEndpointPath: "/graphqlws", - } - - p := New(config) - handlers, err := p.Handlers() - require.NoError(t, err) - assert.Equal(t, handlers[0].Path, "/playground/") - }) - - t.Run("should be / when path prefix and playground path /,empty combinations", func(t *testing.T) { - combinations := [][]string{ - {"/", "/"}, - {"", "/"}, - {"/", ""}, - {"", ""}, - } - - for _, combination := range combinations { - config := Config{ - PathPrefix: combination[0], - PlaygroundPath: combination[1], - GraphqlEndpointPath: "/graphql", - GraphQLSubscriptionEndpointPath: "/graphqlws", - } - - p := New(config) - handlers, err := p.Handlers() - require.NoError(t, err) - assert.Equal(t, "/", handlers[0].Path) - } - }) -} diff --git a/pkg/pool/bytesbuffer.go b/pkg/pool/bytesbuffer.go deleted file mode 100644 index 0d0086eed..000000000 --- a/pkg/pool/bytesbuffer.go +++ /dev/null @@ -1,29 +0,0 @@ -package pool - -import ( - "bytes" - "sync" -) - -var ( - BytesBuffer = bytesBufferPool{ - pool: sync.Pool{ - New: func() interface{} { - return bytes.NewBuffer(make([]byte, 0, 1024)) - }, - }, - } -) - -type bytesBufferPool struct { - pool sync.Pool -} - -func (b *bytesBufferPool) Get() *bytes.Buffer { - return b.pool.Get().(*bytes.Buffer) -} - -func (b *bytesBufferPool) Put(buf *bytes.Buffer) { - buf.Reset() - b.pool.Put(buf) -} diff --git a/pkg/pool/fastbuffer.go b/pkg/pool/fastbuffer.go deleted file mode 100644 index fd036a1bb..000000000 --- a/pkg/pool/fastbuffer.go +++ /dev/null @@ -1,28 +0,0 @@ -package pool - -import ( - "sync" - - "github.com/wundergraph/graphql-go-tools/pkg/fastbuffer" -) - -var FastBuffer = fastBufferPool{ - pool: sync.Pool{ - New: func() interface{} { - return fastbuffer.New() - }, - }, -} - -type fastBufferPool struct { - pool sync.Pool -} - -func (f *fastBufferPool) Get() *fastbuffer.FastBuffer { - return f.pool.Get().(*fastbuffer.FastBuffer) -} - -func (f *fastBufferPool) Put(buf *fastbuffer.FastBuffer) { - buf.Reset() - f.pool.Put(buf) -} diff --git a/pkg/pool/hash64.go b/pkg/pool/hash64.go deleted file mode 100644 index 41b89e49f..000000000 --- a/pkg/pool/hash64.go +++ /dev/null @@ -1,31 +0,0 @@ -package pool - -import ( - "hash" - "sync" - - "github.com/cespare/xxhash/v2" -) - -var ( - Hash64 = hash64Pool{ - pool: sync.Pool{ - New: func() interface{} { - return xxhash.New() - }, - }, - } -) - -type hash64Pool struct { - pool sync.Pool -} - -func (b *hash64Pool) Get() hash.Hash64 { - return b.pool.Get().(hash.Hash64) -} - -func (b *hash64Pool) Put(hash64 hash.Hash64) { - hash64.Reset() - b.pool.Put(hash64) -} diff --git a/pkg/postprocess/datasourceinput.go b/pkg/postprocess/datasourceinput.go deleted file mode 100644 index 67cf894f0..000000000 --- a/pkg/postprocess/datasourceinput.go +++ /dev/null @@ -1,104 +0,0 @@ -package postprocess - -import ( - "strconv" - "strings" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -type ProcessDataSource struct{} - -func (d *ProcessDataSource) Process(pre plan.Plan) plan.Plan { - switch t := pre.(type) { - case *plan.SynchronousResponsePlan: - d.traverseNode(t.Response.Data) - case *plan.StreamingResponsePlan: - d.traverseNode(t.Response.InitialResponse.Data) - for i := range t.Response.Patches { - d.traverseFetch(t.Response.Patches[i].Fetch) - d.traverseNode(t.Response.Patches[i].Value) - } - case *plan.SubscriptionResponsePlan: - d.traverseTrigger(&t.Response.Trigger) - d.traverseNode(t.Response.Response.Data) - } - return pre -} - -func (d *ProcessDataSource) traverseNode(node resolve.Node) { - switch n := node.(type) { - case *resolve.Object: - d.traverseFetch(n.Fetch) - for i := range n.Fields { - d.traverseNode(n.Fields[i].Value) - } - case *resolve.Array: - d.traverseNode(n.Item) - } -} - -func (d *ProcessDataSource) traverseFetch(fetch resolve.Fetch) { - if fetch == nil { - return - } - switch f := fetch.(type) { - case *resolve.SingleFetch: - d.traverseSingleFetch(f) - case *resolve.BatchFetch: - d.traverseSingleFetch(f.Fetch) - case *resolve.ParallelFetch: - for i := range f.Fetches { - d.traverseFetch(f.Fetches[i]) - } - } -} - -func (d *ProcessDataSource) traverseTrigger(trigger *resolve.GraphQLSubscriptionTrigger) { - d.resolveInputTemplate(trigger.Variables, string(trigger.Input), &trigger.InputTemplate) - trigger.Input = nil - trigger.Variables = nil -} - -func (d *ProcessDataSource) traverseSingleFetch(fetch *resolve.SingleFetch) { - d.resolveInputTemplate(fetch.Variables, fetch.Input, &fetch.InputTemplate) - fetch.Input = "" - fetch.Variables = nil - fetch.InputTemplate.SetTemplateOutputToNullOnVariableNull = fetch.SetTemplateOutputToNullOnVariableNull - fetch.SetTemplateOutputToNullOnVariableNull = false -} - -func (d *ProcessDataSource) resolveInputTemplate(variables resolve.Variables, input string, template *resolve.InputTemplate) { - - if input == "" { - return - } - - if !strings.Contains(input, "$$") { - template.Segments = append(template.Segments, resolve.TemplateSegment{ - SegmentType: resolve.StaticSegmentType, - Data: []byte(input), - }) - return - } - - segments := strings.Split(input, "$$") - - isVariable := false - for _, seg := range segments { - switch { - case isVariable: - i, _ := strconv.Atoi(seg) - variableTemplateSegment := (variables)[i].TemplateSegment() - template.Segments = append(template.Segments, variableTemplateSegment) - isVariable = false - default: - template.Segments = append(template.Segments, resolve.TemplateSegment{ - SegmentType: resolve.StaticSegmentType, - Data: []byte(seg), - }) - isVariable = true - } - } -} diff --git a/pkg/postprocess/datasourceinput_test.go b/pkg/postprocess/datasourceinput_test.go deleted file mode 100644 index 71c3534d2..000000000 --- a/pkg/postprocess/datasourceinput_test.go +++ /dev/null @@ -1,316 +0,0 @@ -package postprocess - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -func TestDataSourceInput_Process(t *testing.T) { - pre := &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://localhost:4001/$$0$$","body":{"query":"{me {id username}}"}}`, - DataSource: nil, - Variables: []resolve.Variable{ - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"$$0$$","__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - }, - ), - DataSource: nil, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.SingleFetch{ - BufferId: 2, - Input: `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"$$0$$","__typename":"Product"}]}}}`, - DataSource: nil, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"upc"}, - }, - ), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001/`), - SegmentType: resolve.StaticSegmentType, - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.HeaderVariableKind, - VariableSourcePath: []string{"Authorization"}, - }, - { - Data: []byte(`","body":{"query":"{me {id username}}"}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - }, - DataSource: nil, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"`), - SegmentType: resolve.StaticSegmentType, - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - { - Data: []byte(`","__typename":"User"}]}}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - DataSource: nil, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.SingleFetch{ - BufferId: 2, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"`), - SegmentType: resolve.StaticSegmentType, - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - }, - { - Data: []byte(`","__typename":"Product"}]}}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - SetTemplateOutputToNullOnVariableNull: true, - }, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - processor := &ProcessDataSource{} - actual := processor.Process(pre) - - assert.Equal(t, expected, actual) -} - -func TestDataSourceInput_Subscription_Process(t *testing.T) { - - pre := &plan.SubscriptionResponsePlan{ - Response: &resolve.GraphQLSubscription{ - Trigger: resolve.GraphQLSubscriptionTrigger{ - Input: []byte(`{"method":"POST","url":"http://localhost:4001/$$0$$","body":{"query":"{me {id username}}"}}`), - Variables: []resolve.Variable{ - &resolve.HeaderVariable{ - Path: []string{"Authorization"}, - }, - }, - }, - Response: &resolve.GraphQLResponse{}, - }, - } - - expected := &plan.SubscriptionResponsePlan{ - Response: &resolve.GraphQLSubscription{ - Trigger: resolve.GraphQLSubscriptionTrigger{ - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - Data: []byte(`{"method":"POST","url":"http://localhost:4001/`), - SegmentType: resolve.StaticSegmentType, - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.HeaderVariableKind, - VariableSourcePath: []string{"Authorization"}, - }, - { - Data: []byte(`","body":{"query":"{me {id username}}"}}`), - SegmentType: resolve.StaticSegmentType, - }, - }, - }, - }, - Response: &resolve.GraphQLResponse{}, - }, - } - - processor := &ProcessDataSource{} - actual := processor.Process(pre) - - assert.Equal(t, expected, actual) -} diff --git a/pkg/postprocess/defer.go b/pkg/postprocess/defer.go deleted file mode 100644 index 952bb0388..000000000 --- a/pkg/postprocess/defer.go +++ /dev/null @@ -1,169 +0,0 @@ -package postprocess - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type ProcessDefer struct { - objects []*resolve.Object - out *plan.StreamingResponsePlan - updated bool -} - -func (p *ProcessDefer) Process(pre plan.Plan) plan.Plan { - - p.out = nil - p.updated = false - p.objects = p.objects[:0] - - switch in := pre.(type) { - case *plan.SynchronousResponsePlan: - return p.synchronousResponse(in) - case *plan.StreamingResponsePlan: - return p.processStreamingResponsePlan(in) - default: - return pre - } -} - -func (p *ProcessDefer) processStreamingResponsePlan(in *plan.StreamingResponsePlan) plan.Plan { - p.out = in - for i := range p.out.Response.Patches { - p.traverseNode(p.out.Response.Patches[i].Value) - } - p.traverseNode(p.out.Response.InitialResponse.Data) - return p.out -} - -func (p *ProcessDefer) synchronousResponse(pre *plan.SynchronousResponsePlan) plan.Plan { - p.out = &plan.StreamingResponsePlan{ - FlushInterval: pre.FlushInterval, - Response: &resolve.GraphQLStreamingResponse{ - InitialResponse: pre.Response, - FlushInterval: pre.FlushInterval, - }, - } - p.traverseNode(p.out.Response.InitialResponse.Data) - if p.updated { - return p.out - } - return pre -} - -func (p *ProcessDefer) traverseNode(node resolve.Node) { - - switch n := node.(type) { - case *resolve.Object: - p.objects = append(p.objects, n) - for i := range n.Fields { - if n.Fields[i].Defer != nil { - p.updated = true - patchIndex, ok := p.createPatch(n, i) - if !ok { - continue - } - n.Fields[i].Defer = nil - n.Fields[i].Value = &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: patchIndex, - }, - } - p.traverseNode(p.out.Response.Patches[patchIndex].Value) - } else { - p.traverseNode(n.Fields[i].Value) - } - } - p.objects = p.objects[:len(p.objects)-1] - case *resolve.Array: - p.traverseNode(n.Item) - } -} - -func (p *ProcessDefer) createPatch(object *resolve.Object, field int) (int, bool) { - oldValue := object.Fields[field].Value - var patch *resolve.GraphQLResponsePatch - if object.Fields[field].HasBuffer && !p.bufferUsedOnNonDeferField(object, field, object.Fields[field].BufferID) { - patchFetch, ok := p.processFieldSetBuffer(object, field) - if !ok { - return 0, false - } - patch = &resolve.GraphQLResponsePatch{ - Value: oldValue, - Fetch: &patchFetch, - Operation: literal.REPLACE, - } - object.Fields[field].HasBuffer = false - object.Fields[field].BufferID = 0 - } else { - patch = &resolve.GraphQLResponsePatch{ - Value: oldValue, - Operation: literal.REPLACE, - } - } - p.out.Response.Patches = append(p.out.Response.Patches, patch) - patchIndex := len(p.out.Response.Patches) - 1 - return patchIndex, true -} - -func (p *ProcessDefer) bufferUsedOnNonDeferField(object *resolve.Object, field, bufferID int) bool { - for i := range object.Fields { - if object.Fields[i].BufferID != bufferID { - continue - } - if i == field { - continue // skip currently evaluated field - } - if object.Fields[i].Defer == nil { - return true - } - } - return false -} - -func (p *ProcessDefer) processFieldSetBuffer(object *resolve.Object, field int) (patchFetch resolve.SingleFetch, ok bool) { - id := object.Fields[field].BufferID - if p.objects[len(p.objects)-1].Fetch == nil { - return patchFetch, false - } - switch fetch := p.objects[len(p.objects)-1].Fetch.(type) { - case *resolve.SingleFetch: - if fetch.BufferId != id { - return patchFetch, false - } - patchFetch = *fetch - patchFetch.BufferId = 0 - p.objects[len(p.objects)-1].Fetch = nil - return patchFetch, true - case *resolve.BatchFetch: - if fetch.Fetch.BufferId != id { - return patchFetch, false - } - patchFetch = *fetch.Fetch - patchFetch.BufferId = 0 - p.objects[len(p.objects)-1].Fetch = nil - return patchFetch, true - case *resolve.ParallelFetch: - for k := range fetch.Fetches { - var singleFetch *resolve.SingleFetch - switch f := fetch.Fetches[k].(type) { - case *resolve.SingleFetch: - singleFetch = f - case *resolve.BatchFetch: - singleFetch = f.Fetch - } - if id == singleFetch.BufferId { - patchFetch = *singleFetch - patchFetch.BufferId = 0 - fetch.Fetches = append(fetch.Fetches[:k], fetch.Fetches[k+1:]...) - if len(fetch.Fetches) == 1 { - p.objects[len(p.objects)-1].Fetch = fetch.Fetches[0] - } - return patchFetch, true - } - } - } - return patchFetch, false -} diff --git a/pkg/postprocess/defer_test.go b/pkg/postprocess/defer_test.go deleted file mode 100644 index fb8692bf0..000000000 --- a/pkg/postprocess/defer_test.go +++ /dev/null @@ -1,941 +0,0 @@ -package postprocess - -import ( - "context" - "io" - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestProcessDefer_Process(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - - Name: []byte("posts"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Fetch: &resolve.SingleFetch{ - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - } - - proc := &ProcessDefer{} - actual := proc.Process(original) - - assert.Equal(t, expected, actual) -} - -func TestProcessDefer_Process_Nested(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - commentsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 2, - DataSource: commentsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 2, - Name: []byte("comments"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("user"), - Value: &resolve.String{ - Path: []string{"user"}, - }, - }, - { - Name: []byte("text"), - Value: &resolve.String{ - Path: []string{"text"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - - Name: []byte("posts"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Fetch: &resolve.SingleFetch{ - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - - Name: []byte("comments"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 1, - }, - }, - }, - }, - }, - }, - }, - { - Operation: literal.REPLACE, - Fetch: &resolve.SingleFetch{ - BufferId: 0, - DataSource: commentsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("user"), - Value: &resolve.String{ - Path: []string{"user"}, - }, - }, - { - Name: []byte("text"), - Value: &resolve.String{ - Path: []string{"text"}, - }, - }, - }, - }, - }, - }, - }, - }, - } - - proc := &ProcessDefer{} - actual := proc.Process(original) - - assert.Equal(t, expected, actual) -} - -func TestProcessDefer_Process_KeepFetchIfUsedUndeferred(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("no_defer_posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("no_defer_posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - } - - proc := &ProcessDefer{} - actual := proc.Process(original) - - assert.Equal(t, expected, actual) -} - -func TestProcessDefer_Process_ParallelFetch(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.ParallelFetch{ - Fetches: []resolve.Fetch{ - &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - &resolve.SingleFetch{ - BufferId: 2, - DataSource: postsService, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 2, - DataSource: postsService, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - Name: []byte("posts"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Fetch: &resolve.SingleFetch{ - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - } - - proc := &ProcessDefer{} - actual := proc.Process(original) - - assert.Equal(t, expected, actual) -} - -func TestProcessDefer_Process_ShouldSkipWithoutDefer(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - planFactory := func() plan.Plan { - return &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - HasBuffer: true, - BufferID: 1, - Name: []byte("non_deferred_posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - } - - original := planFactory() - clone := planFactory() - - proc := &ProcessDefer{} - actual := proc.Process(original) - - assert.Equal(t, clone, actual) -} - -type fakeService struct { -} - -func (f *fakeService) Load(ctx context.Context, input []byte, w io.Writer) (err error) { - panic("implement me") -} diff --git a/pkg/postprocess/postprocess.go b/pkg/postprocess/postprocess.go deleted file mode 100644 index 19b1d9a27..000000000 --- a/pkg/postprocess/postprocess.go +++ /dev/null @@ -1,31 +0,0 @@ -package postprocess - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" -) - -type PostProcessor interface { - Process(pre plan.Plan) plan.Plan -} - -type Processor struct { - postProcessors []PostProcessor -} - -func DefaultProcessor() *Processor { - return &Processor{ - []PostProcessor{ - &ProcessDefer{}, - &ProcessStream{}, - &ProcessDataSource{}, - }, - } -} - -func (p *Processor) Process(pre plan.Plan) (post plan.Plan) { - post = pre - for i := range p.postProcessors { - post = p.postProcessors[i].Process(post) - } - return -} diff --git a/pkg/postprocess/postprocess_test.go b/pkg/postprocess/postprocess_test.go deleted file mode 100644 index 8da84c9c3..000000000 --- a/pkg/postprocess/postprocess_test.go +++ /dev/null @@ -1,437 +0,0 @@ -package postprocess - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestDefaultProcessor_Process(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Stream: &resolve.StreamField{ - InitialBatchSize: 0, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Stream: resolve.Stream{ - Enabled: true, - InitialBatchSize: 0, - PatchIndex: 1, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.REPLACE, - Fetch: &resolve.SingleFetch{ - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - { - Operation: literal.ADD, - Value: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - Name: []byte("posts"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - } - - processor := DefaultProcessor() - actual := processor.Process(original) - - assert.Equal(t, expected, actual) -} - -func TestDefaultProcessor_Federation(t *testing.T) { - pre := &plan.SynchronousResponsePlan{ - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - Input: `{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - Input: `{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"$$0$$","__typename":"User"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"id"}, - }, - ), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("reviews"), - Defer: &resolve.DeferField{}, - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.SingleFetch{ - BufferId: 2, - Input: `{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"$$0$$","__typename":"Product"}]}}}`, - Variables: resolve.NewVariables( - &resolve.ObjectVariable{ - Path: []string{"upc"}, - }, - ), - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - Response: &resolve.GraphQLStreamingResponse{ - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 0, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.StaticSegmentType, - Data: []byte(`{"method":"POST","url":"http://localhost:4001","body":{"query":"{me {id username}}"}}`), - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("me"), - Value: &resolve.Object{ - Path: []string{"me"}, - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.String{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("username"), - Value: &resolve.String{ - Path: []string{"username"}, - }, - }, - { - Name: []byte("reviews"), - Value: &resolve.Null{ - Defer: resolve.Defer{ - Enabled: true, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Fetch: &resolve.SingleFetch{ - BufferId: 0, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.StaticSegmentType, - Data: []byte(`{"method":"POST","url":"http://localhost:4002","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on User {reviews {body product {upc __typename}}}}}","variables":{"representations":[{"id":"`), - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - { - SegmentType: resolve.StaticSegmentType, - Data: []byte(`","__typename":"User"}]}}}`), - }, - }, - }, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - Operation: literal.REPLACE, - Value: &resolve.Array{ - Path: []string{"reviews"}, - Nullable: true, - Item: &resolve.Object{ - Nullable: true, - Fields: []*resolve.Field{ - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - { - Name: []byte("product"), - Value: &resolve.Object{ - Path: []string{"product"}, - Fetch: &resolve.SingleFetch{ - BufferId: 2, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.StaticSegmentType, - Data: []byte(`{"method":"POST","url":"http://localhost:4003","body":{"query":"query($representations: [_Any!]!){_entities(representations: $representations){... on Product {name}}}","variables":{"representations":[{"upc":"`), - }, - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"upc"}, - }, - { - SegmentType: resolve.StaticSegmentType, - Data: []byte(`","__typename":"Product"}]}}}`), - }, - }, - }, - ProcessResponseConfig: resolve.ProcessResponseConfig{ - ExtractGraphqlResponse: true, - ExtractFederationEntities: true, - }, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 2, - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - processor := DefaultProcessor() - actual := processor.Process(pre) - assert.Equal(t, expected, actual) -} diff --git a/pkg/postprocess/stream.go b/pkg/postprocess/stream.go deleted file mode 100644 index ab6d5ed8f..000000000 --- a/pkg/postprocess/stream.go +++ /dev/null @@ -1,86 +0,0 @@ -package postprocess - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -type ProcessStream struct { - out *plan.StreamingResponsePlan - didUpdate bool -} - -func (p *ProcessStream) Process(pre plan.Plan) plan.Plan { - - p.out = nil - p.didUpdate = false - - switch in := pre.(type) { - case *plan.SynchronousResponsePlan: - return p.processSynchronousPlan(in) - case *plan.StreamingResponsePlan: - return p.processStreamingResponsePlan(in) - default: - return pre - } -} - -func (p *ProcessStream) processStreamingResponsePlan(in *plan.StreamingResponsePlan) plan.Plan { - p.out = in - for i := range p.out.Response.Patches { - p.traverseNode(p.out.Response.Patches[i].Value) - } - p.traverseNode(p.out.Response.InitialResponse.Data) - return p.out -} - -func (p *ProcessStream) processSynchronousPlan(in *plan.SynchronousResponsePlan) plan.Plan { - p.out = &plan.StreamingResponsePlan{ - FlushInterval: in.FlushInterval, - Response: &resolve.GraphQLStreamingResponse{ - InitialResponse: in.Response, - FlushInterval: in.FlushInterval, - }, - } - p.traverseNode(in.Response.Data) - if p.didUpdate { - return p.out - } - return in -} - -func (p *ProcessStream) traverseNode(node resolve.Node) { - switch n := node.(type) { - case *resolve.Object: - for i := range n.Fields { - if n.Fields[i].Stream != nil { - switch array := n.Fields[i].Value.(type) { - case *resolve.Array: - array.Stream.Enabled = true - array.Stream.InitialBatchSize = n.Fields[i].Stream.InitialBatchSize - n.Fields[i].Stream = nil - } - } - p.traverseNode(n.Fields[i].Value) - } - case *resolve.Array: - if n.Stream.Enabled { - p.didUpdate = true - patch := &resolve.GraphQLResponsePatch{ - Value: n.Item, - Operation: literal.ADD, - } - if n.Stream.InitialBatchSize == 0 { - n.Item = nil - } - p.out.Response.Patches = append(p.out.Response.Patches, patch) - n.Stream.PatchIndex = len(p.out.Response.Patches) - 1 - - p.traverseNode(p.out.Response.Patches[n.Stream.PatchIndex].Value) - - return - } - p.traverseNode(n.Item) - } -} diff --git a/pkg/postprocess/stream_test.go b/pkg/postprocess/stream_test.go deleted file mode 100644 index cd0afe236..000000000 --- a/pkg/postprocess/stream_test.go +++ /dev/null @@ -1,411 +0,0 @@ -package postprocess - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/lexer/literal" -) - -func TestProcessStream_Process(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Stream: &resolve.StreamField{ - InitialBatchSize: 0, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Stream: resolve.Stream{ - Enabled: true, - InitialBatchSize: 0, - PatchIndex: 0, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.ADD, - Value: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - proc := &ProcessStream{} - actual := proc.Process(original) - - assert.Equal(t, expected, actual) -} - -func TestProcessStream_Process_BatchSize_1(t *testing.T) { - - userService := &fakeService{} - postsService := &fakeService{} - - original := &plan.SynchronousResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Stream: &resolve.StreamField{ - InitialBatchSize: 1, - }, - Value: &resolve.Array{ - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - expected := &plan.StreamingResponsePlan{ - FlushInterval: 500, - Response: &resolve.GraphQLStreamingResponse{ - FlushInterval: 500, - InitialResponse: &resolve.GraphQLResponse{ - Data: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - DataSource: userService, - BufferId: 0, - }, - Fields: []*resolve.Field{ - { - HasBuffer: true, - BufferID: 0, - Name: []byte("users"), - Value: &resolve.Array{ - Stream: resolve.Stream{ - Enabled: true, - InitialBatchSize: 1, - }, - Item: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - - { - - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - Patches: []*resolve.GraphQLResponsePatch{ - { - Operation: literal.ADD, - Value: &resolve.Object{ - Fetch: &resolve.SingleFetch{ - BufferId: 1, - DataSource: postsService, - InputTemplate: resolve.InputTemplate{ - Segments: []resolve.TemplateSegment{ - { - SegmentType: resolve.VariableSegmentType, - VariableKind: resolve.ObjectVariableKind, - VariableSourcePath: []string{"id"}, - }, - }, - }, - }, - Fields: []*resolve.Field{ - { - Name: []byte("id"), - Value: &resolve.Integer{ - Path: []string{"id"}, - }, - }, - { - Name: []byte("name"), - Value: &resolve.String{ - Path: []string{"name"}, - }, - }, - { - HasBuffer: true, - BufferID: 1, - Name: []byte("posts"), - Value: &resolve.Array{ - Item: &resolve.Object{ - Fields: []*resolve.Field{ - { - Name: []byte("title"), - Value: &resolve.String{ - Path: []string{"title"}, - }, - }, - { - Name: []byte("body"), - Value: &resolve.String{ - Path: []string{"body"}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } - - proc := &ProcessStream{} - actual := proc.Process(original) - - assert.Equal(t, expected, actual) -} diff --git a/pkg/repair/repair.go b/pkg/repair/repair.go deleted file mode 100644 index 983c01106..000000000 --- a/pkg/repair/repair.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package repair helps fixing problems in GraphQL documents -package repair diff --git a/pkg/repair/sdl.go b/pkg/repair/sdl.go deleted file mode 100644 index fbc03fa8d..000000000 --- a/pkg/repair/sdl.go +++ /dev/null @@ -1,189 +0,0 @@ -package repair - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/astparser" - "github.com/wundergraph/graphql-go-tools/pkg/astprinter" - "github.com/wundergraph/graphql-go-tools/pkg/astvisitor" - "github.com/wundergraph/graphql-go-tools/pkg/operationreport" -) - -type OptionsSDL struct { - SetAllMutationFieldsNullable bool -} - -func SDL(input string, options OptionsSDL) (string, error) { - repair := sdlRepair{ - sdl: input, - options: options, - } - return repair.do() -} - -type sdlRepair struct { - sdl string - doc *ast.Document - options OptionsSDL -} - -func (r *sdlRepair) do() (string, error) { - doc, report := astparser.ParseGraphqlDocumentString(r.sdl) - if report.HasErrors() { - return "", report - } - r.doc = &doc - err := r.repairEmptyInputObjectTypeDefinitions() - if err != nil { - return "", err - } - return astprinter.PrintString(r.doc, nil) -} - -func (r *sdlRepair) repairEmptyInputObjectTypeDefinitions() error { - walker := astvisitor.NewWalker(8) - visitor := &emptyInputObjectTypeDefinitionVisitor{ - walker: &walker, - } - walker.RegisterEnterInputObjectTypeDefinitionVisitor(visitor) - walker.RegisterEnterInputValueDefinitionVisitor(visitor) - walker.RegisterDocumentVisitor(visitor) - if r.options.SetAllMutationFieldsNullable { - setAllMutationFieldsNullableVisitor := &setAllMutationFieldsNullableVisitor{ - walker: &walker, - } - walker.RegisterEnterDocumentVisitor(setAllMutationFieldsNullableVisitor) - walker.RegisterEnterFieldDefinitionVisitor(setAllMutationFieldsNullableVisitor) - walker.RegisterObjectTypeDefinitionVisitor(setAllMutationFieldsNullableVisitor) - } - report := operationreport.Report{} - for { - walker.Walk(r.doc, nil, &report) - if report.HasErrors() { - return report - } - if visitor.changed { - continue - } - return nil - } -} - -type emptyInputObjectTypeDefinitionVisitor struct { - walker *astvisitor.Walker - changed bool - doc *ast.Document - - removeRootNode bool - rootNode ast.Node - - removeFieldsWithType []string - - removeInputValueDefinition bool - inputObjectTypeDefinition int - inputValueDefinition int - - removeFieldArgument bool - fieldDefinition int -} - -func (e *emptyInputObjectTypeDefinitionVisitor) EnterInputValueDefinition(ref int) { - fieldType := e.doc.InputValueDefinitionType(ref) - typeName := e.doc.ResolveTypeNameString(fieldType) - for _, s := range e.removeFieldsWithType { - if typeName == s { - ancestor := e.walker.Ancestors[len(e.walker.Ancestors)-1] - switch ancestor.Kind { - case ast.NodeKindInputObjectTypeDefinition: - e.changed = true - e.removeInputValueDefinition = true - e.inputObjectTypeDefinition = ancestor.Ref - e.inputValueDefinition = ref - return - case ast.NodeKindFieldDefinition: - e.changed = true - e.removeFieldArgument = true - e.fieldDefinition = ancestor.Ref - e.inputValueDefinition = ref - } - } - } -} - -func (e *emptyInputObjectTypeDefinitionVisitor) LeaveDocument(operation, definition *ast.Document) { - if e.removeRootNode { - e.doc.RemoveRootNode(e.rootNode) - } - if e.removeInputValueDefinition { - for i, ref := range e.doc.InputObjectTypeDefinitions[e.inputObjectTypeDefinition].InputFieldsDefinition.Refs { - if ref == e.inputValueDefinition { - e.doc.InputObjectTypeDefinitions[e.inputObjectTypeDefinition].InputFieldsDefinition.Refs = - append(e.doc.InputObjectTypeDefinitions[e.inputObjectTypeDefinition].InputFieldsDefinition.Refs[:i], e.doc.InputObjectTypeDefinitions[e.inputObjectTypeDefinition].InputFieldsDefinition.Refs[i+1:]...) - e.doc.InputObjectTypeDefinitions[e.inputObjectTypeDefinition].HasInputFieldsDefinition = len(e.doc.InputObjectTypeDefinitions[e.inputObjectTypeDefinition].InputFieldsDefinition.Refs) != 0 - return - } - } - } - if e.removeFieldArgument { - for i, ref := range e.doc.FieldDefinitions[e.fieldDefinition].ArgumentsDefinition.Refs { - if ref == e.inputValueDefinition { - e.doc.FieldDefinitions[e.fieldDefinition].ArgumentsDefinition.Refs = - append(e.doc.FieldDefinitions[e.fieldDefinition].ArgumentsDefinition.Refs[:i], - e.doc.FieldDefinitions[e.fieldDefinition].ArgumentsDefinition.Refs[i+1:]...) - e.doc.FieldDefinitions[e.fieldDefinition].HasArgumentsDefinitions = len(e.doc.FieldDefinitions[e.fieldDefinition].ArgumentsDefinition.Refs) != 0 - } - } - } -} - -func (e *emptyInputObjectTypeDefinitionVisitor) EnterDocument(operation, definition *ast.Document) { - e.doc = operation - e.changed = false - e.removeInputValueDefinition = false -} - -func (e *emptyInputObjectTypeDefinitionVisitor) EnterInputObjectTypeDefinition(ref int) { - if e.doc.InputObjectTypeDefinitions[ref].HasInputFieldsDefinition { - return - } - e.changed = true - for _, node := range e.doc.RootNodes { - if node.Kind != ast.NodeKindInputObjectTypeDefinition || node.Ref != ref { - continue - } - e.removeRootNode = true - e.rootNode = node - e.removeFieldsWithType = append(e.removeFieldsWithType, node.NameString(e.doc)) - return - } -} - -type setAllMutationFieldsNullableVisitor struct { - walker *astvisitor.Walker - definition *ast.Document - insideMutation bool - mutationTypeName string -} - -func (s *setAllMutationFieldsNullableVisitor) LeaveObjectTypeDefinition(ref int) { - s.insideMutation = false -} - -func (s *setAllMutationFieldsNullableVisitor) EnterDocument(operation, definition *ast.Document) { - s.definition = operation - s.mutationTypeName = operation.Index.MutationTypeName.String() -} - -func (s *setAllMutationFieldsNullableVisitor) EnterObjectTypeDefinition(ref int) { - typeName := s.definition.ObjectTypeDefinitionNameString(ref) - s.insideMutation = typeName == s.mutationTypeName -} - -func (s *setAllMutationFieldsNullableVisitor) EnterFieldDefinition(ref int) { - if !s.insideMutation { - return - } - typeRef := s.definition.FieldDefinitions[ref].Type - if s.definition.Types[typeRef].TypeKind == ast.TypeKindNonNull { - s.definition.FieldDefinitions[ref].Type = s.definition.Types[typeRef].OfType - } -} diff --git a/pkg/repair/sdl_test.go b/pkg/repair/sdl_test.go deleted file mode 100644 index d6d6886f2..000000000 --- a/pkg/repair/sdl_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package repair - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/internal/unsafeprinter" -) - -func TestSDL(t *testing.T) { - t.Run("should remove empty input object type definitions", func(t *testing.T) { - input := ` -type String -schema { - query: Query - mutation: Mutation -} -type Query { foo(a: A): String! } -input A { - b: B -} -input B {} -type Mutation { - foo: String! - bar: Boolean! -} -` - expected := ` -type String -schema { - query: Query - mutation: Mutation -} -type Query { foo: String! } -type Mutation { - foo: String - bar: Boolean -} -` - actual, err := SDL(input, OptionsSDL{ - SetAllMutationFieldsNullable: true, - }) - assert.NoError(t, err) - assert.Equal(t, unsafeprinter.Prettify(expected), unsafeprinter.Prettify(actual)) - }) -} diff --git a/pkg/starwars/starwars.go b/pkg/starwars/starwars.go deleted file mode 100644 index d73c3ad68..000000000 --- a/pkg/starwars/starwars.go +++ /dev/null @@ -1,101 +0,0 @@ -package starwars - -import ( - "encoding/json" - "os" - "path" - "testing" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/execution" - "github.com/wundergraph/graphql-go-tools/pkg/execution/datasource" -) - -type QueryVariables map[string]interface{} - -const ( - FileSimpleHeroQuery = "testdata/queries/simple_hero.query" - FileHeroWithOperationNameQuery = "testdata/queries/hero_with_operation_name.query" - FileHeroWithAliasesQuery = "testdata/queries/hero_with_aliases.query" - FileDroidWithArgQuery = "testdata/queries/droid_with_arg.query" - FileDroidWithArgAndVarQuery = "testdata/queries/droid_with_arg_and_var.query" - FileFragmentsQuery = "testdata/queries/fragments.query" - FileDirectivesIncludeQuery = "testdata/queries/directives_include.query" - FileDirectivesSkipQuery = "testdata/queries/directives_skip.query" - FileCreateReviewMutation = "testdata/mutations/create_review.mutation" - FileInlineFragmentsQuery = "testdata/queries/inline_fragments.query" - FileUnionQuery = "testdata/queries/inline_fragments.query" - FileRemainingJedisSubscription = "testdata/subscriptions/remaining_jedis.subscription" - FileIntrospectionQuery = "testdata/queries/introspection.query" - FileMultiQueries = "testdata/queries/multi_queries.query" - FileMultiQueriesWithArguments = "testdata/queries/multi_queries_with_arguments.query" - FileInvalidQuery = "testdata/queries/invalid.query" - FileInvalidFragmentsQuery = "testdata/queries/invalid_fragments.query" - FileInterfaceFragmentsOnUnion = "testdata/queries/interface_fragments_on_union.graphql" -) - -var ( - testdataPath = "./" -) - -type TestCase struct { - Name string - RequestBody []byte -} - -func SetRelativePathToStarWarsPackage(path string) { - testdataPath = path -} - -func NewExecutionHandler(t *testing.T) *execution.Handler { - base, err := datasource.NewBaseDataSourcePlanner(Schema(t), datasource.PlannerConfiguration{}, abstractlogger.NoopLogger) - require.NoError(t, err) - executionHandler := execution.NewHandler(base, nil) - return executionHandler -} - -func Schema(t *testing.T) []byte { - schema, err := os.ReadFile(path.Join(testdataPath, "testdata/star_wars.graphql")) - require.NoError(t, err) - return schema -} - -func LoadQuery(t *testing.T, fileName string, variables QueryVariables) []byte { - query, err := os.ReadFile(path.Join(testdataPath, fileName)) - require.NoError(t, err) - - return RequestBody(t, string(query), variables) -} - -func InvalidQueryRequestBody(t *testing.T) []byte { - return RequestBody(t, "query { trap { meme } }", nil) -} - -func RequestBody(t *testing.T, query string, variables QueryVariables) []byte { - var variableJsonBytes []byte - if len(variables) > 0 { - var err error - variableJsonBytes, err = json.Marshal(variables) - require.NoError(t, err) - } - - body := execution.GraphqlRequest{ - OperationName: "", - Variables: variableJsonBytes, - Query: query, - } - - jsonBytes, err := json.Marshal(body) - require.NoError(t, err) - - return jsonBytes -} - -func ReviewInput() map[string]interface{} { - return map[string]interface{}{ - "stars": 5, - "commentary": "This is a great movie!", - } -} diff --git a/pkg/starwars/testdata/mutations/create_review.mutation b/pkg/starwars/testdata/mutations/create_review.mutation deleted file mode 100644 index efd69caa8..000000000 --- a/pkg/starwars/testdata/mutations/create_review.mutation +++ /dev/null @@ -1,7 +0,0 @@ -mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { - createReview(episode: $ep, review: $review) { - id - stars - commentary - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/directives_include.query b/pkg/starwars/testdata/queries/directives_include.query deleted file mode 100644 index 93e60d764..000000000 --- a/pkg/starwars/testdata/queries/directives_include.query +++ /dev/null @@ -1,8 +0,0 @@ -query Hero($withFriends: Boolean!) { - hero { - name - friends @include(if: $withFriends) { - name - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/directives_skip.query b/pkg/starwars/testdata/queries/directives_skip.query deleted file mode 100644 index 6a3c8a2e2..000000000 --- a/pkg/starwars/testdata/queries/directives_skip.query +++ /dev/null @@ -1,8 +0,0 @@ -query Hero($skipFriends: Boolean!) { - hero { - name - friends @skip(if: $skipFriends) { - name - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/droid_with_arg.query b/pkg/starwars/testdata/queries/droid_with_arg.query deleted file mode 100644 index 604f02bb2..000000000 --- a/pkg/starwars/testdata/queries/droid_with_arg.query +++ /dev/null @@ -1,5 +0,0 @@ -{ - droid(id: "R2D2") { - name - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/droid_with_arg_and_var.query b/pkg/starwars/testdata/queries/droid_with_arg_and_var.query deleted file mode 100644 index 562498d90..000000000 --- a/pkg/starwars/testdata/queries/droid_with_arg_and_var.query +++ /dev/null @@ -1,5 +0,0 @@ -query Droid($droidID: ID!) { - droid(id: $droidID) { - name - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/fragments.query b/pkg/starwars/testdata/queries/fragments.query deleted file mode 100644 index 29b6503f7..000000000 --- a/pkg/starwars/testdata/queries/fragments.query +++ /dev/null @@ -1,12 +0,0 @@ -query Fragments($droidID: ID!){ - hero { - ...characterFields - } - droid(id: $droidID) { - ...characterFields - } -} - -fragment characterFields on Character { - name -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/hero_with_aliases.query b/pkg/starwars/testdata/queries/hero_with_aliases.query deleted file mode 100644 index 3796ac3a9..000000000 --- a/pkg/starwars/testdata/queries/hero_with_aliases.query +++ /dev/null @@ -1,8 +0,0 @@ -{ - empireHero: hero { - name - } - jediHero: hero { - name - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/hero_with_operation_name.query b/pkg/starwars/testdata/queries/hero_with_operation_name.query deleted file mode 100644 index c6e4e7af2..000000000 --- a/pkg/starwars/testdata/queries/hero_with_operation_name.query +++ /dev/null @@ -1,5 +0,0 @@ -query Hero { - hero { - name - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/inline_fragments.query b/pkg/starwars/testdata/queries/inline_fragments.query deleted file mode 100644 index fe2ac994c..000000000 --- a/pkg/starwars/testdata/queries/inline_fragments.query +++ /dev/null @@ -1,14 +0,0 @@ -{ - hero { - friends { - ...on Droid { - name - primaryFunction - } - ...on Human { - name - height - } - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/interface_fragments_on_union.graphql b/pkg/starwars/testdata/queries/interface_fragments_on_union.graphql deleted file mode 100644 index db3162de2..000000000 --- a/pkg/starwars/testdata/queries/interface_fragments_on_union.graphql +++ /dev/null @@ -1,10 +0,0 @@ -query SearchResults { - searchResults { - ...on Character { - name - } - ...on Vehicle { - length - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/introspection.query b/pkg/starwars/testdata/queries/introspection.query deleted file mode 100644 index 996742faf..000000000 --- a/pkg/starwars/testdata/queries/introspection.query +++ /dev/null @@ -1,99 +0,0 @@ -query IntrospectionQuery { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - ...FullType - } - directives { - name - description - locations - args { - ...InputValue - } - } - } -} - -fragment FullType on __Type { - kind - name - description - fields(includeDeprecated: true) { - name - description - args { - ...InputValue - } - type { - ...TypeRef - } - isDeprecated - deprecationReason - } - inputFields { - ...InputValue - } - interfaces { - ...TypeRef - } - enumValues(includeDeprecated: true) { - name - description - isDeprecated - deprecationReason - } - possibleTypes { - ...TypeRef - } -} - -fragment InputValue on __InputValue { - name - description - type { - ...TypeRef - } - defaultValue -} - -fragment TypeRef on __Type { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - ofType { - kind - name - } - } - } - } - } - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/invalid.query b/pkg/starwars/testdata/queries/invalid.query deleted file mode 100644 index 9d8a80a8f..000000000 --- a/pkg/starwars/testdata/queries/invalid.query +++ /dev/null @@ -1,5 +0,0 @@ -{ - hero { - invalid - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/invalid_fragments.query b/pkg/starwars/testdata/queries/invalid_fragments.query deleted file mode 100644 index e3e9f26dc..000000000 --- a/pkg/starwars/testdata/queries/invalid_fragments.query +++ /dev/null @@ -1,11 +0,0 @@ -query Fragments($droidID: ID!){ - droid(id: $droidID) { - ...reviewFields - } -} - -fragment reviewFields on Review { - id - stars - commentary -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/multi_queries.query b/pkg/starwars/testdata/queries/multi_queries.query deleted file mode 100644 index 0268327cb..000000000 --- a/pkg/starwars/testdata/queries/multi_queries.query +++ /dev/null @@ -1,14 +0,0 @@ -query MultiHeroes { - empireHero: hero { - name - } - jediHero: hero { - name - } -} - -query SingleHero { - hero { - name - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/multi_queries_with_arguments.query b/pkg/starwars/testdata/queries/multi_queries_with_arguments.query deleted file mode 100644 index 8cdb9a9ee..000000000 --- a/pkg/starwars/testdata/queries/multi_queries_with_arguments.query +++ /dev/null @@ -1,22 +0,0 @@ -query GetDroid { - droid(id: "1") { - name - } -} - -query Search { - search(name: "C3PO") { - ...on Droid { - name - primaryFunction - } - ...on Human { - name - height - } - ...on Starship { - name - length - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/simple_hero.query b/pkg/starwars/testdata/queries/simple_hero.query deleted file mode 100644 index add80bdb3..000000000 --- a/pkg/starwars/testdata/queries/simple_hero.query +++ /dev/null @@ -1,5 +0,0 @@ -{ - hero { - name - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/queries/union.query b/pkg/starwars/testdata/queries/union.query deleted file mode 100644 index 0bd308981..000000000 --- a/pkg/starwars/testdata/queries/union.query +++ /dev/null @@ -1,16 +0,0 @@ -query Search($name: String!) { - search(name: $name) { - ...on Droid { - name - primaryFunction - } - ...on Human { - name - height - } - ...on Starship { - name - length - } - } -} \ No newline at end of file diff --git a/pkg/starwars/testdata/star_wars.graphql b/pkg/starwars/testdata/star_wars.graphql deleted file mode 100644 index 8a63a0692..000000000 --- a/pkg/starwars/testdata/star_wars.graphql +++ /dev/null @@ -1,65 +0,0 @@ -union SearchResult = Human | Droid | Starship - -schema { - query: Query - mutation: Mutation - subscription: Subscription -} - -type Query { - hero: Character @deprecated - droid(id: ID!): Droid - search(name: String!): SearchResult - searchResults: [SearchResult] -} - -type Mutation { - createReview(episode: Episode!, review: ReviewInput!): Review -} - -type Subscription { - remainingJedis: Int! -} - -input ReviewInput { - stars: Int! - commentary: String -} - -type Review { - id: ID! - stars: Int! - commentary: String -} - -enum Episode { - NEWHOPE - EMPIRE - JEDI @deprecated -} - -interface Character { - name: String! - friends: [Character] -} - -type Human implements Character { - name: String! - height: String! @deprecated - friends: [Character] -} - -type Droid implements Character { - name: String! - primaryFunction: String! - friends: [Character] -} - -interface Vehicle { - length: Float! -} - -type Starship implements Vehicle { - name: String! - length: Float! -} diff --git a/pkg/starwars/testdata/subscriptions/remaining_jedis.subscription b/pkg/starwars/testdata/subscriptions/remaining_jedis.subscription deleted file mode 100644 index ab9eea03f..000000000 --- a/pkg/starwars/testdata/subscriptions/remaining_jedis.subscription +++ /dev/null @@ -1,3 +0,0 @@ -subscription { - remainingJedis -} \ No newline at end of file diff --git a/pkg/subscription/constants.go b/pkg/subscription/constants.go deleted file mode 100644 index 2ed5557bc..000000000 --- a/pkg/subscription/constants.go +++ /dev/null @@ -1,7 +0,0 @@ -package subscription - -const ( - DefaultKeepAliveInterval = "15s" - DefaultSubscriptionUpdateInterval = "1s" - DefaultReadErrorTimeOut = "5s" -) diff --git a/pkg/subscription/context.go b/pkg/subscription/context.go deleted file mode 100644 index 13b9acbf7..000000000 --- a/pkg/subscription/context.go +++ /dev/null @@ -1,73 +0,0 @@ -package subscription - -import ( - "context" - "errors" - "fmt" - "net/http" - "sync" -) - -var ( - ErrSubscriberIDAlreadyExists = errors.New("subscriber id already exists") -) - -type InitialHttpRequestContext struct { - context.Context - Request *http.Request -} - -func NewInitialHttpRequestContext(r *http.Request) *InitialHttpRequestContext { - return &InitialHttpRequestContext{ - Context: r.Context(), - Request: r, - } -} - -type subscriptionCancellations struct { - mu sync.RWMutex - cancellations map[string]context.CancelFunc -} - -func (sc *subscriptionCancellations) AddWithParent(id string, parent context.Context) (context.Context, error) { - sc.mu.Lock() - defer sc.mu.Unlock() - if sc.cancellations == nil { - sc.cancellations = make(map[string]context.CancelFunc) - } - if _, ok := sc.cancellations[id]; ok { - return nil, fmt.Errorf("%w: %s", ErrSubscriberIDAlreadyExists, id) - } - ctx, cancelFunc := context.WithCancel(parent) - sc.cancellations[id] = cancelFunc - return ctx, nil -} - -func (sc *subscriptionCancellations) Cancel(id string) (ok bool) { - sc.mu.Lock() - defer sc.mu.Unlock() - cancelFunc, ok := sc.cancellations[id] - if !ok { - return false - } - - cancelFunc() - delete(sc.cancellations, id) - return true -} - -func (sc *subscriptionCancellations) CancelAll() { - // We have full control over the cancellation functions (see AddWithParent()), so - // it's fine to invoke them with the lock held - sc.mu.RLock() - defer sc.mu.RUnlock() - for _, cancelFunc := range sc.cancellations { - cancelFunc() - } -} - -func (sc *subscriptionCancellations) Len() int { - sc.mu.RLock() - defer sc.mu.RUnlock() - return len(sc.cancellations) -} diff --git a/pkg/subscription/context_test.go b/pkg/subscription/context_test.go deleted file mode 100644 index ebe72f89c..000000000 --- a/pkg/subscription/context_test.go +++ /dev/null @@ -1,73 +0,0 @@ -package subscription - -import ( - "bytes" - "context" - "net/http" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestNewInitialHttpRequestContext(t *testing.T) { - ctx, cancelFn := context.WithCancel(context.Background()) - defer cancelFn() - - req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://localhost:8080", bytes.NewBufferString("lorem ipsum")) - require.NoError(t, err) - - initialReqCtx := NewInitialHttpRequestContext(req) - assert.Equal(t, ctx, initialReqCtx.Context) - assert.Equal(t, req, initialReqCtx.Request) -} - -func TestSubscriptionCancellations(t *testing.T) { - cancellations := subscriptionCancellations{} - var ctx context.Context - var err error - - t.Run("should add a cancellation func to map", func(t *testing.T) { - require.Equal(t, 0, cancellations.Len()) - - ctx, err = cancellations.AddWithParent("1", context.Background()) - assert.Nil(t, err) - assert.Equal(t, 1, cancellations.Len()) - assert.NotNil(t, ctx) - }) - - t.Run("should execute cancellation from map", func(t *testing.T) { - require.Equal(t, 1, cancellations.Len()) - ctxTestFunc := func() bool { - <-ctx.Done() - return true - } - - ok := cancellations.Cancel("1") - assert.Eventually(t, ctxTestFunc, time.Second, 5*time.Millisecond) - assert.True(t, ok) - assert.Equal(t, 0, cancellations.Len()) - }) -} - -func TestSubscriptionIdsShouldBeUnique(t *testing.T) { - sc := subscriptionCancellations{} - var ctx context.Context - var err error - - ctx, err = sc.AddWithParent("1", context.Background()) - assert.Nil(t, err) - assert.Equal(t, 1, sc.Len()) - assert.NotNil(t, ctx) - - ctx, err = sc.AddWithParent("2", context.Background()) - assert.Nil(t, err) - assert.Equal(t, 2, sc.Len()) - assert.NotNil(t, ctx) - - ctx, err = sc.AddWithParent("2", context.Background()) - assert.NotNil(t, err) - assert.Equal(t, 2, sc.Len()) - assert.Nil(t, ctx) -} diff --git a/pkg/subscription/engine.go b/pkg/subscription/engine.go deleted file mode 100644 index 313bfef9f..000000000 --- a/pkg/subscription/engine.go +++ /dev/null @@ -1,215 +0,0 @@ -package subscription - -//go:generate mockgen -destination=engine_mock_test.go -package=subscription . Engine -//go:generate mockgen -destination=websocket/engine_mock_test.go -package=websocket . Engine - -import ( - "context" - "errors" - "fmt" - "sync" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -type errOnBeforeStartHookFailure struct { - wrappedErr error -} - -func (e *errOnBeforeStartHookFailure) Unwrap() error { - return e.wrappedErr -} - -func (e *errOnBeforeStartHookFailure) Error() string { - return fmt.Sprintf("on before start hook failed: %s", e.wrappedErr.Error()) -} - -// Engine defines the function for a subscription engine. -type Engine interface { - StartOperation(ctx context.Context, id string, payload []byte, eventHandler EventHandler) error - StopSubscription(id string, eventHandler EventHandler) error - TerminateAllSubscriptions(eventHandler EventHandler) error -} - -// ExecutorEngine is an implementation of Engine and works with subscription.Executor. -type ExecutorEngine struct { - logger abstractlogger.Logger - // subCancellations is map containing the cancellation functions to every active subscription. - subCancellations subscriptionCancellations - // executorPool is responsible to create and hold executors. - executorPool ExecutorPool - // bufferPool will hold buffers. - bufferPool *sync.Pool - // subscriptionUpdateInterval is the actual interval on which the server sends subscription updates to the client. - subscriptionUpdateInterval time.Duration -} - -// StartOperation will start any operation. -func (e *ExecutorEngine) StartOperation(ctx context.Context, id string, payload []byte, eventHandler EventHandler) error { - executor, err := e.executorPool.Get(payload) - if err != nil { - return err - } - - if err = e.handleOnBeforeStart(executor); err != nil { - eventHandler.Emit(EventTypeOnError, id, nil, err) - return &errOnBeforeStartHookFailure{wrappedErr: err} - } - - if ctx, err = e.checkForDuplicateSubscriberID(ctx, id, eventHandler); err != nil { - return err - } - - if executor.OperationType() == ast.OperationTypeSubscription { - go e.startSubscription(ctx, id, executor, eventHandler) - return nil - } - - go e.handleNonSubscriptionOperation(ctx, id, executor, eventHandler) - return nil -} - -// StopSubscription will stop an active subscription. -func (e *ExecutorEngine) StopSubscription(id string, eventHandler EventHandler) error { - e.subCancellations.Cancel(id) - eventHandler.Emit(EventTypeOnSubscriptionCompleted, id, nil, nil) - return nil -} - -// TerminateAllSubscriptions will cancel all active subscriptions. -func (e *ExecutorEngine) TerminateAllSubscriptions(eventHandler EventHandler) error { - if e.subCancellations.Len() == 0 { - return nil - } - - for id := range e.subCancellations.cancellations { - e.subCancellations.Cancel(id) - } - - eventHandler.Emit(EventTypeOnConnectionTerminatedByServer, "", []byte("connection terminated by server"), nil) - return nil -} - -func (e *ExecutorEngine) handleOnBeforeStart(executor Executor) error { - switch e := executor.(type) { - case *ExecutorV2: - if hook := e.engine.GetWebsocketBeforeStartHook(); hook != nil { - return hook.OnBeforeStart(e.reqCtx, e.operation) - } - case *ExecutorV1: - // do nothing - } - - return nil -} - -func (e *ExecutorEngine) checkForDuplicateSubscriberID(ctx context.Context, id string, eventHandler EventHandler) (context.Context, error) { - ctx, subsErr := e.subCancellations.AddWithParent(id, ctx) - if errors.Is(subsErr, ErrSubscriberIDAlreadyExists) { - eventHandler.Emit(EventTypeOnDuplicatedSubscriberID, id, nil, subsErr) - return ctx, subsErr - } else if subsErr != nil { - eventHandler.Emit(EventTypeOnError, id, nil, subsErr) - return ctx, subsErr - } - return ctx, nil -} - -func (e *ExecutorEngine) startSubscription(ctx context.Context, id string, executor Executor, eventHandler EventHandler) { - defer func() { - err := e.executorPool.Put(executor) - if err != nil { - e.logger.Error("subscription.Handle.startSubscription()", - abstractlogger.Error(err), - ) - } - }() - - executor.SetContext(ctx) - buf := e.bufferPool.Get().(*graphql.EngineResultWriter) - buf.Reset() - - defer e.bufferPool.Put(buf) - - e.executeSubscription(buf, id, executor, eventHandler) - - for { - buf.Reset() - select { - case <-ctx.Done(): - return - case <-time.After(e.subscriptionUpdateInterval): - e.executeSubscription(buf, id, executor, eventHandler) - } - } - -} - -func (e *ExecutorEngine) executeSubscription(buf *graphql.EngineResultWriter, id string, executor Executor, eventHandler EventHandler) { - buf.SetFlushCallback(func(data []byte) { - e.logger.Debug("subscription.Handle.executeSubscription()", - abstractlogger.ByteString("execution_result", data), - ) - eventHandler.Emit(EventTypeOnSubscriptionData, id, data, nil) - }) - defer buf.SetFlushCallback(nil) - - err := executor.Execute(buf) - if err != nil { - e.logger.Error("subscription.Handle.executeSubscription()", - abstractlogger.Error(err), - ) - - eventHandler.Emit(EventTypeOnError, id, nil, err) - return - } - - if buf.Len() > 0 { - data := buf.Bytes() - e.logger.Debug("subscription.Handle.executeSubscription()", - abstractlogger.ByteString("execution_result", data), - ) - eventHandler.Emit(EventTypeOnSubscriptionData, id, data, nil) - } -} - -func (e *ExecutorEngine) handleNonSubscriptionOperation(ctx context.Context, id string, executor Executor, eventHandler EventHandler) { - defer func() { - e.subCancellations.Cancel(id) - err := e.executorPool.Put(executor) - if err != nil { - e.logger.Error("subscription.Handle.handleNonSubscriptionOperation()", - abstractlogger.Error(err), - ) - } - }() - - executor.SetContext(ctx) - buf := e.bufferPool.Get().(*graphql.EngineResultWriter) - buf.Reset() - - defer e.bufferPool.Put(buf) - - err := executor.Execute(buf) - if err != nil { - e.logger.Error("subscription.Handle.handleNonSubscriptionOperation()", - abstractlogger.Error(err), - ) - - eventHandler.Emit(EventTypeOnError, id, nil, err) - return - } - - e.logger.Debug("subscription.Handle.handleNonSubscriptionOperation()", - abstractlogger.ByteString("execution_result", buf.Bytes()), - ) - - eventHandler.Emit(EventTypeOnNonSubscriptionExecutionResult, id, buf.Bytes(), err) -} - -// Interface Guards -var _ Engine = (*ExecutorEngine)(nil) diff --git a/pkg/subscription/engine_mock_test.go b/pkg/subscription/engine_mock_test.go deleted file mode 100644 index fb5cd659b..000000000 --- a/pkg/subscription/engine_mock_test.go +++ /dev/null @@ -1,77 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/wundergraph/graphql-go-tools/pkg/subscription (interfaces: Engine) - -// Package subscription is a generated GoMock package. -package subscription - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockEngine is a mock of Engine interface. -type MockEngine struct { - ctrl *gomock.Controller - recorder *MockEngineMockRecorder -} - -// MockEngineMockRecorder is the mock recorder for MockEngine. -type MockEngineMockRecorder struct { - mock *MockEngine -} - -// NewMockEngine creates a new mock instance. -func NewMockEngine(ctrl *gomock.Controller) *MockEngine { - mock := &MockEngine{ctrl: ctrl} - mock.recorder = &MockEngineMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockEngine) EXPECT() *MockEngineMockRecorder { - return m.recorder -} - -// StartOperation mocks base method. -func (m *MockEngine) StartOperation(arg0 context.Context, arg1 string, arg2 []byte, arg3 EventHandler) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartOperation", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(error) - return ret0 -} - -// StartOperation indicates an expected call of StartOperation. -func (mr *MockEngineMockRecorder) StartOperation(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartOperation", reflect.TypeOf((*MockEngine)(nil).StartOperation), arg0, arg1, arg2, arg3) -} - -// StopSubscription mocks base method. -func (m *MockEngine) StopSubscription(arg0 string, arg1 EventHandler) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StopSubscription", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// StopSubscription indicates an expected call of StopSubscription. -func (mr *MockEngineMockRecorder) StopSubscription(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopSubscription", reflect.TypeOf((*MockEngine)(nil).StopSubscription), arg0, arg1) -} - -// TerminateAllSubscriptions mocks base method. -func (m *MockEngine) TerminateAllSubscriptions(arg0 EventHandler) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TerminateAllSubscriptions", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// TerminateAllSubscriptions indicates an expected call of TerminateAllSubscriptions. -func (mr *MockEngineMockRecorder) TerminateAllSubscriptions(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TerminateAllSubscriptions", reflect.TypeOf((*MockEngine)(nil).TerminateAllSubscriptions), arg0) -} diff --git a/pkg/subscription/engine_test.go b/pkg/subscription/engine_test.go deleted file mode 100644 index 5ad01ae34..000000000 --- a/pkg/subscription/engine_test.go +++ /dev/null @@ -1,512 +0,0 @@ -package subscription - -import ( - "bytes" - "context" - "errors" - "runtime" - "sync" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -func TestExecutorEngine_StartOperation(t *testing.T) { - t.Run("execute non-subscription operation", func(t *testing.T) { - t.Run("on execution failure", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx, cancelFunc := context.WithTimeout(context.Background(), 25*time.Millisecond) - defer cancelFunc() - - idQuery := "1" - payloadQuery := []byte(`{"query":"{ hello }"}`) - - idMutation := "2" - payloadMutation := []byte(`{"query":"mutation { update }"}`) - - executorMock := NewMockExecutor(ctrl) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeQuery). - Times(1) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeMutation). - Times(1) - executorMock.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(2) - executorMock.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Return(errors.New("error")). - Times(2) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payloadQuery)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Get(gomock.Eq(payloadMutation)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMock)). - Do(func(_ Executor) { - wg.Done() - }). - Times(2) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnError), gomock.Eq(idQuery), gomock.Nil(), gomock.Any()). - Times(1) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnError), gomock.Eq(idMutation), gomock.Nil(), gomock.Any()). - Times(1) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 0, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, idQuery, payloadQuery, eventHandlerMock) - assert.NoError(t, err) - - err = engine.StartOperation(ctx, idMutation, payloadMutation, eventHandlerMock) - assert.NoError(t, err) - - <-ctx.Done() - wg.Wait() - return true - }, 1*time.Second, 10*time.Millisecond) - }) - - t.Run("on execution success", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(2) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx, cancelFunc := context.WithTimeout(context.Background(), 25*time.Millisecond) - defer cancelFunc() - - idQuery := "1" - payloadQuery := []byte(`{"query":"{ hello }"}`) - - idMutation := "2" - payloadMutation := []byte(`{"query":"mutation { update }"}`) - - executorMock := NewMockExecutor(ctrl) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeQuery). - Times(1) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeMutation). - Times(1) - executorMock.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(2) - executorMock.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Times(2) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payloadQuery)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Get(gomock.Eq(payloadMutation)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMock)). - Do(func(_ Executor) { - wg.Done() - }). - Times(2) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnNonSubscriptionExecutionResult), gomock.Eq(idQuery), gomock.AssignableToTypeOf([]byte{}), gomock.Nil()). - Times(1) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnNonSubscriptionExecutionResult), gomock.Eq(idMutation), gomock.AssignableToTypeOf([]byte{}), gomock.Nil()). - Times(1) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 0, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, idQuery, payloadQuery, eventHandlerMock) - assert.NoError(t, err) - - err = engine.StartOperation(ctx, idMutation, payloadMutation, eventHandlerMock) - assert.NoError(t, err) - - <-ctx.Done() - wg.Wait() - return true - }, 1*time.Second, 10*time.Millisecond) - }) - }) - - t.Run("execute subscription operation", func(t *testing.T) { - t.Run("on execution failure", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("this test fails on Windows due to different timings than unix, consider fixing it at some point") - } - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx, cancelFunc := context.WithTimeout(context.Background(), 25*time.Millisecond) - defer cancelFunc() - - id := "1" - payload := []byte(`{"query":"subscription { receiveData }"}`) - - executorMock := NewMockExecutor(ctrl) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeSubscription). - Times(1) - executorMock.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(1) - executorMock.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Return(errors.New("error")). - MinTimes(2) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payload)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMock)). - Do(func(_ Executor) { - wg.Done() - }). - Times(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnError), gomock.Eq(id), gomock.Nil(), gomock.Any()). - MinTimes(2) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 2 * time.Millisecond, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, id, payload, eventHandlerMock) - <-ctx.Done() - wg.Wait() - return assert.NoError(t, err) - }, 1*time.Second, 10*time.Millisecond) - }) - - t.Run("on execution success", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("this test fails on Windows due to different timings than unix, consider fixing it at some point") - } - - wg := sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx, cancelFunc := context.WithTimeout(context.Background(), 25*time.Millisecond) - defer cancelFunc() - - id := "1" - payload := []byte(`{"query":"subscription { receiveData }"}`) - - executorMock := NewMockExecutor(ctrl) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeSubscription). - Times(1) - executorMock.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(1) - executorMock.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Do(func(resultWriter *graphql.EngineResultWriter) { - _, _ = resultWriter.Write([]byte(`{ "data": { "update": "newData" } }`)) - }). - MinTimes(2) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payload)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMock)). - Do(func(_ Executor) { - wg.Done() - }). - Times(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnSubscriptionData), gomock.Eq(id), gomock.AssignableToTypeOf([]byte{}), gomock.Nil()). - MinTimes(2) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 2 * time.Millisecond, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, id, payload, eventHandlerMock) - <-ctx.Done() - wg.Wait() - return assert.NoError(t, err) - }, 1*time.Second, 10*time.Millisecond) - }) - }) - - t.Run("error on duplicate id", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx, cancelFunc := context.WithTimeout(context.Background(), 25*time.Millisecond) - defer cancelFunc() - - id := "1" - payloadSubscription := []byte(`{"query":"subscription { receiveData }"}`) - payloadQuery := []byte(`{"query":"query { hello }"}`) - - executorMockQuery := NewMockExecutor(ctrl) - executorMockSubscription := NewMockExecutor(ctrl) - executorMockSubscription.EXPECT().OperationType(). - Return(ast.OperationTypeSubscription). - Times(1) - executorMockSubscription.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(1) - executorMockSubscription.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Do(func(resultWriter *graphql.EngineResultWriter) { - _, _ = resultWriter.Write([]byte(`{ "data": { "receiveData": "newData" } }`)) - }). - Times(1) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payloadSubscription)). - Return(executorMockSubscription, nil). - Times(1) - executorPoolMock.EXPECT().Get(gomock.Eq(payloadQuery)). - Return(executorMockQuery, nil). - Times(1) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMockSubscription)). - Do(func(_ Executor) { - wg.Done() - }). - Times(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnDuplicatedSubscriberID), gomock.Eq(id), gomock.Nil(), gomock.Any()). - Times(1) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnSubscriptionData), gomock.Eq(id), gomock.AssignableToTypeOf([]byte{}), gomock.Nil()). - Times(1) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 100 * time.Millisecond, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, id, payloadSubscription, eventHandlerMock) - assert.NoError(t, err) - - err = engine.StartOperation(ctx, id, payloadQuery, eventHandlerMock) - assert.Error(t, err) - - <-ctx.Done() - wg.Wait() - return true - }, 1*time.Second, 10*time.Millisecond) - }) -} - -func TestExecutorEngine_StopSubscription(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx := context.Background() - - id := "1" - payload := []byte(`{"query":"subscription { receiveData }"}`) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnSubscriptionCompleted), gomock.Eq(id), gomock.Nil(), gomock.Nil()). - Times(1) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnSubscriptionData), gomock.Eq(id), gomock.AssignableToTypeOf([]byte{}), gomock.Nil()). - MinTimes(1) - - executorMock := NewMockExecutor(ctrl) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeSubscription). - Times(1) - executorMock.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(1) - executorMock.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Do(func(resultWriter *graphql.EngineResultWriter) { - _, _ = resultWriter.Write([]byte(`{ "data": { "receiveData": "newData" } }`)) - }). - MinTimes(1) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payload)). - Return(executorMock, nil). - Times(1) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMock)). - Do(func(_ Executor) { - wg.Done() - }). - Times(1) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 2 * time.Millisecond, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, id, payload, eventHandlerMock) - assert.NoError(t, err) - assert.Equal(t, 1, engine.subCancellations.Len()) - time.Sleep(5 * time.Millisecond) - - err = engine.StopSubscription(id, eventHandlerMock) - assert.NoError(t, err) - assert.Equal(t, 0, engine.subCancellations.Len()) - wg.Wait() - - return true - }, 1*time.Second, 5*time.Millisecond) -} - -func TestExecutorEngine_TerminateAllConnections(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(3) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - ctx := context.Background() - - payload := []byte(`{"query":"subscription { receiveData }"}`) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnConnectionTerminatedByServer), gomock.Eq(""), gomock.Eq([]byte("connection terminated by server")), gomock.Nil()). - Times(1) - eventHandlerMock.EXPECT().Emit(gomock.Eq(EventTypeOnSubscriptionData), gomock.Any(), gomock.AssignableToTypeOf([]byte{}), gomock.Nil()). - MinTimes(3) - - executorMock := NewMockExecutor(ctrl) - executorMock.EXPECT().OperationType(). - Return(ast.OperationTypeSubscription). - Times(3) - executorMock.EXPECT().SetContext(assignableToContextWithCancel(ctx)). - Times(3) - executorMock.EXPECT().Execute(gomock.AssignableToTypeOf(&graphql.EngineResultWriter{})). - Do(func(resultWriter *graphql.EngineResultWriter) { - _, _ = resultWriter.Write([]byte(`{ "data": { "receiveData": "newData" } }`)) - }). - MinTimes(3) - - executorPoolMock := NewMockExecutorPool(ctrl) - executorPoolMock.EXPECT().Get(gomock.Eq(payload)). - Return(executorMock, nil). - Times(3) - executorPoolMock.EXPECT().Put(gomock.Eq(executorMock)). - Do(func(_ Executor) { - wg.Done() - }). - Times(3) - - engine := ExecutorEngine{ - logger: abstractlogger.Noop{}, - subCancellations: subscriptionCancellations{}, - executorPool: executorPoolMock, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - subscriptionUpdateInterval: 2 * time.Millisecond, - } - - assert.Eventually(t, func() bool { - err := engine.StartOperation(ctx, "1", payload, eventHandlerMock) - assert.NoError(t, err) - err = engine.StartOperation(ctx, "2", payload, eventHandlerMock) - assert.NoError(t, err) - err = engine.StartOperation(ctx, "3", payload, eventHandlerMock) - assert.NoError(t, err) - assert.Equal(t, 3, engine.subCancellations.Len()) - time.Sleep(5 * time.Millisecond) - - err = engine.TerminateAllSubscriptions(eventHandlerMock) - assert.NoError(t, err) - assert.Equal(t, 0, engine.subCancellations.Len()) - wg.Wait() - - return true - }, 1*time.Second, 5*time.Millisecond) -} - -func assignableToContextWithCancel(ctx context.Context) gomock.Matcher { - ctxWithCancel, _ := context.WithCancel(ctx) //nolint:govet - return gomock.AssignableToTypeOf(ctxWithCancel) -} diff --git a/pkg/subscription/executor.go b/pkg/subscription/executor.go deleted file mode 100644 index 81c2ae2dc..000000000 --- a/pkg/subscription/executor.go +++ /dev/null @@ -1,24 +0,0 @@ -package subscription - -//go:generate mockgen -destination=executor_mock_test.go -package=subscription . Executor,ExecutorPool - -import ( - "context" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -// Executor is an abstraction for executing a GraphQL engine -type Executor interface { - Execute(writer resolve.FlushWriter) error - OperationType() ast.OperationType - SetContext(context context.Context) - Reset() -} - -// ExecutorPool is an abstraction for creating executors -type ExecutorPool interface { - Get(payload []byte) (Executor, error) - Put(executor Executor) error -} diff --git a/pkg/subscription/executor_mock_test.go b/pkg/subscription/executor_mock_test.go deleted file mode 100644 index 6d7716678..000000000 --- a/pkg/subscription/executor_mock_test.go +++ /dev/null @@ -1,141 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/wundergraph/graphql-go-tools/pkg/subscription (interfaces: Executor,ExecutorPool) - -// Package subscription is a generated GoMock package. -package subscription - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - ast "github.com/wundergraph/graphql-go-tools/pkg/ast" - resolve "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" -) - -// MockExecutor is a mock of Executor interface. -type MockExecutor struct { - ctrl *gomock.Controller - recorder *MockExecutorMockRecorder -} - -// MockExecutorMockRecorder is the mock recorder for MockExecutor. -type MockExecutorMockRecorder struct { - mock *MockExecutor -} - -// NewMockExecutor creates a new mock instance. -func NewMockExecutor(ctrl *gomock.Controller) *MockExecutor { - mock := &MockExecutor{ctrl: ctrl} - mock.recorder = &MockExecutorMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockExecutor) EXPECT() *MockExecutorMockRecorder { - return m.recorder -} - -// Execute mocks base method. -func (m *MockExecutor) Execute(arg0 resolve.FlushWriter) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Execute", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// Execute indicates an expected call of Execute. -func (mr *MockExecutorMockRecorder) Execute(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockExecutor)(nil).Execute), arg0) -} - -// OperationType mocks base method. -func (m *MockExecutor) OperationType() ast.OperationType { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OperationType") - ret0, _ := ret[0].(ast.OperationType) - return ret0 -} - -// OperationType indicates an expected call of OperationType. -func (mr *MockExecutorMockRecorder) OperationType() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OperationType", reflect.TypeOf((*MockExecutor)(nil).OperationType)) -} - -// Reset mocks base method. -func (m *MockExecutor) Reset() { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Reset") -} - -// Reset indicates an expected call of Reset. -func (mr *MockExecutorMockRecorder) Reset() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Reset", reflect.TypeOf((*MockExecutor)(nil).Reset)) -} - -// SetContext mocks base method. -func (m *MockExecutor) SetContext(arg0 context.Context) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "SetContext", arg0) -} - -// SetContext indicates an expected call of SetContext. -func (mr *MockExecutorMockRecorder) SetContext(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContext", reflect.TypeOf((*MockExecutor)(nil).SetContext), arg0) -} - -// MockExecutorPool is a mock of ExecutorPool interface. -type MockExecutorPool struct { - ctrl *gomock.Controller - recorder *MockExecutorPoolMockRecorder -} - -// MockExecutorPoolMockRecorder is the mock recorder for MockExecutorPool. -type MockExecutorPoolMockRecorder struct { - mock *MockExecutorPool -} - -// NewMockExecutorPool creates a new mock instance. -func NewMockExecutorPool(ctrl *gomock.Controller) *MockExecutorPool { - mock := &MockExecutorPool{ctrl: ctrl} - mock.recorder = &MockExecutorPoolMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockExecutorPool) EXPECT() *MockExecutorPoolMockRecorder { - return m.recorder -} - -// Get mocks base method. -func (m *MockExecutorPool) Get(arg0 []byte) (Executor, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Get", arg0) - ret0, _ := ret[0].(Executor) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Get indicates an expected call of Get. -func (mr *MockExecutorPoolMockRecorder) Get(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockExecutorPool)(nil).Get), arg0) -} - -// Put mocks base method. -func (m *MockExecutorPool) Put(arg0 Executor) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Put", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// Put indicates an expected call of Put. -func (mr *MockExecutorPoolMockRecorder) Put(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockExecutorPool)(nil).Put), arg0) -} diff --git a/pkg/subscription/executor_v1.go b/pkg/subscription/executor_v1.go deleted file mode 100644 index 627617baa..000000000 --- a/pkg/subscription/executor_v1.go +++ /dev/null @@ -1,70 +0,0 @@ -package subscription - -import ( - "context" - "sync" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/execution" -) - -type ExecutorV1Pool struct { - ExecutionHandler *execution.Handler - executorPool *sync.Pool -} - -func NewExecutorV1Pool(executionHandler *execution.Handler) *ExecutorV1Pool { - return &ExecutorV1Pool{ - ExecutionHandler: executionHandler, - executorPool: &sync.Pool{ - New: func() interface{} { - return &ExecutorV1{} - }, - }, - } -} - -func (e *ExecutorV1Pool) Get(payload []byte) (Executor, error) { - engineExecutor, node, executionContext, err := e.ExecutionHandler.Handle(payload, []byte("")) - if err != nil { - return nil, err - } - - executor := e.executorPool.Get().(*ExecutorV1) - executor.engineExecutor = engineExecutor - executor.rootNode = node - executor.executionContext = executionContext - - return executor, nil -} - -func (e *ExecutorV1Pool) Put(executor Executor) error { - executor.Reset() - e.executorPool.Put(executor) - return nil -} - -type ExecutorV1 struct { - engineExecutor *execution.Executor - rootNode execution.RootNode - executionContext execution.Context -} - -func (e *ExecutorV1) Execute(writer resolve.FlushWriter) error { - return e.engineExecutor.Execute(e.executionContext, e.rootNode, writer) -} - -func (e *ExecutorV1) OperationType() ast.OperationType { - return e.rootNode.OperationType() -} - -func (e *ExecutorV1) SetContext(context context.Context) { - e.executionContext.Context = context -} - -func (e *ExecutorV1) Reset() { - e.engineExecutor = nil - e.rootNode = nil - e.executionContext = execution.Context{} -} diff --git a/pkg/subscription/executor_v2.go b/pkg/subscription/executor_v2.go deleted file mode 100644 index 5bfa2468f..000000000 --- a/pkg/subscription/executor_v2.go +++ /dev/null @@ -1,88 +0,0 @@ -package subscription - -import ( - "bytes" - "context" - "sync" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/engine/resolve" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -// ExecutorV2Pool - provides reusable executors -type ExecutorV2Pool struct { - engine *graphql.ExecutionEngineV2 - executorPool *sync.Pool - connectionInitReqCtx context.Context // connectionInitReqCtx - holds original request context used to establish websocket connection -} - -func NewExecutorV2Pool(engine *graphql.ExecutionEngineV2, connectionInitReqCtx context.Context) *ExecutorV2Pool { - return &ExecutorV2Pool{ - engine: engine, - executorPool: &sync.Pool{ - New: func() interface{} { - return &ExecutorV2{} - }, - }, - connectionInitReqCtx: connectionInitReqCtx, - } -} - -func (e *ExecutorV2Pool) Get(payload []byte) (Executor, error) { - operation := graphql.Request{} - err := graphql.UnmarshalRequest(bytes.NewReader(payload), &operation) - if err != nil { - return nil, err - } - - return &ExecutorV2{ - engine: e.engine, - operation: &operation, - context: context.Background(), - reqCtx: e.connectionInitReqCtx, - }, nil -} - -func (e *ExecutorV2Pool) Put(executor Executor) error { - executor.Reset() - e.executorPool.Put(executor) - return nil -} - -type ExecutorV2 struct { - engine *graphql.ExecutionEngineV2 - operation *graphql.Request - context context.Context - reqCtx context.Context -} - -func (e *ExecutorV2) Execute(writer resolve.FlushWriter) error { - options := make([]graphql.ExecutionOptionsV2, 0) - switch ctx := e.reqCtx.(type) { - case *InitialHttpRequestContext: - options = append(options, graphql.WithAdditionalHttpHeaders(ctx.Request.Header)) - } - - return e.engine.Execute(e.context, e.operation, writer, options...) -} - -func (e *ExecutorV2) OperationType() ast.OperationType { - opType, err := e.operation.OperationType() - if err != nil { - return ast.OperationTypeUnknown - } - - return ast.OperationType(opType) -} - -func (e *ExecutorV2) SetContext(context context.Context) { - e.context = context -} - -func (e *ExecutorV2) Reset() { - e.engine = nil - e.operation = nil - e.context = context.Background() - e.reqCtx = context.TODO() -} diff --git a/pkg/subscription/handler.go b/pkg/subscription/handler.go deleted file mode 100644 index 544b8bc13..000000000 --- a/pkg/subscription/handler.go +++ /dev/null @@ -1,210 +0,0 @@ -package subscription - -//go:generate mockgen -destination=handler_mock_test.go -package=subscription . Protocol,EventHandler - -import ( - "bytes" - "context" - "errors" - "sync" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -var ErrCouldNotReadMessageFromClient = errors.New("could not read message from client") - -// EventType can be used to define subscription events decoupled from any protocols. -type EventType int - -const ( - EventTypeOnError EventType = iota - EventTypeOnSubscriptionData - EventTypeOnSubscriptionCompleted - EventTypeOnNonSubscriptionExecutionResult - EventTypeOnConnectionTerminatedByClient - EventTypeOnConnectionTerminatedByServer - EventTypeOnConnectionError - EventTypeOnConnectionOpened - EventTypeOnDuplicatedSubscriberID -) - -// Protocol defines an interface for a subscription protocol decoupled from the underlying transport. -type Protocol interface { - Handle(ctx context.Context, engine Engine, message []byte) error - EventHandler() EventHandler -} - -// EventHandler is an interface that handles subscription events. -type EventHandler interface { - Emit(eventType EventType, id string, data []byte, err error) -} - -// UniversalProtocolHandlerOptions is struct that defines options for the UniversalProtocolHandler. -type UniversalProtocolHandlerOptions struct { - Logger abstractlogger.Logger - CustomSubscriptionUpdateInterval time.Duration - CustomReadErrorTimeOut time.Duration - CustomEngine Engine -} - -// UniversalProtocolHandler can handle any protocol by using the Protocol interface. -type UniversalProtocolHandler struct { - logger abstractlogger.Logger - client TransportClient - protocol Protocol - engine Engine - readErrorTimeOut time.Duration - isReadTimeOutTimerRunning bool - readTimeOutCancel context.CancelFunc -} - -// NewUniversalProtocolHandler creates a new UniversalProtocolHandler. -func NewUniversalProtocolHandler(client TransportClient, protocol Protocol, executorPool ExecutorPool) (*UniversalProtocolHandler, error) { - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - } - - return NewUniversalProtocolHandlerWithOptions(client, protocol, executorPool, options) -} - -// NewUniversalProtocolHandlerWithOptions creates a new UniversalProtocolHandler. It requires an option struct. -func NewUniversalProtocolHandlerWithOptions(client TransportClient, protocol Protocol, executorPool ExecutorPool, options UniversalProtocolHandlerOptions) (*UniversalProtocolHandler, error) { - handler := UniversalProtocolHandler{ - logger: abstractlogger.Noop{}, - client: client, - protocol: protocol, - } - - if options.Logger != nil { - handler.logger = options.Logger - } - - if options.CustomReadErrorTimeOut != 0 { - handler.readErrorTimeOut = options.CustomReadErrorTimeOut - } else { - parsedReadErrorTimeOut, err := time.ParseDuration(DefaultReadErrorTimeOut) - if err != nil { - return nil, err - } - handler.readErrorTimeOut = parsedReadErrorTimeOut - } - - if options.CustomEngine != nil { - handler.engine = options.CustomEngine - } else { - engine := ExecutorEngine{ - logger: handler.logger, - subCancellations: subscriptionCancellations{}, - executorPool: executorPool, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - } - - if options.CustomSubscriptionUpdateInterval != 0 { - engine.subscriptionUpdateInterval = options.CustomSubscriptionUpdateInterval - } else { - subscriptionUpdateInterval, err := time.ParseDuration(DefaultSubscriptionUpdateInterval) - if err != nil { - return nil, err - } - engine.subscriptionUpdateInterval = subscriptionUpdateInterval - } - handler.engine = &engine - } - - return &handler, nil -} - -// Handle will handle the subscription logic and forward messages to the actual protocol handler. -func (u *UniversalProtocolHandler) Handle(ctx context.Context) { - ctxWithCancel, cancel := context.WithCancel(ctx) - defer func() { - err := u.engine.TerminateAllSubscriptions(u.protocol.EventHandler()) - if err != nil { - u.logger.Error("subscription.UniversalProtocolHandler.Handle: on terminate connections", - abstractlogger.Error(err), - ) - } - cancel() - }() - - u.protocol.EventHandler().Emit(EventTypeOnConnectionOpened, "", nil, nil) - - for { - if !u.client.IsConnected() { - u.logger.Debug("subscription.UniversalProtocolHandler.Handle: on client is connected check", - abstractlogger.String("message", "client has disconnected"), - ) - - return - } - - message, err := u.client.ReadBytesFromClient() - if errors.Is(err, ErrTransportClientClosedConnection) { - u.logger.Debug("subscription.UniversalProtocolHandler.Handle: reading from a closed connection") - return - } else if err != nil { - u.logger.Error("subscription.UniversalProtocolHandler.Handle: on reading bytes from client", - abstractlogger.Error(err), - abstractlogger.ByteString("message", message), - ) - - if !u.isReadTimeOutTimerRunning { - var timeOutCtx context.Context - timeOutCtx, u.readTimeOutCancel = context.WithCancel(context.Background()) - params := TimeOutParams{ - Name: "subscription reader error time out", - Logger: u.logger, - TimeOutContext: timeOutCtx, - TimeOutAction: func() { - cancel() // stop the handler if timer runs out - }, - TimeOutDuration: u.readErrorTimeOut, - } - go TimeOutChecker(params) - u.isReadTimeOutTimerRunning = true - } - - u.protocol.EventHandler().Emit(EventTypeOnConnectionError, "", nil, ErrCouldNotReadMessageFromClient) - } else { - if u.isReadTimeOutTimerRunning && u.readTimeOutCancel != nil { - u.readTimeOutCancel() - u.isReadTimeOutTimerRunning = false - u.readTimeOutCancel = nil - } - - if len(message) > 0 { - err := u.protocol.Handle(ctxWithCancel, u.engine, message) - if err != nil { - var onBeforeStartHookError *errOnBeforeStartHookFailure - if errors.As(err, &onBeforeStartHookError) { - // if we do have an errOnBeforeStartHookFailure than the error is expected and should be - // logged as 'Debug'. - u.logger.Debug("subscription.UniversalProtocolHandler.Handle: on protocol handling message", - abstractlogger.Error(err), - ) - } else { - // all other errors should be treated as unexpected and therefore being logged as 'Error'. - u.logger.Error("subscription.UniversalProtocolHandler.Handle: on protocol handling message", - abstractlogger.Error(err), - ) - } - } - } - } - - select { - case <-ctxWithCancel.Done(): - return - default: - continue - } - } -} diff --git a/pkg/subscription/handler_mock_test.go b/pkg/subscription/handler_mock_test.go deleted file mode 100644 index f9124b83c..000000000 --- a/pkg/subscription/handler_mock_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/wundergraph/graphql-go-tools/pkg/subscription (interfaces: Protocol,EventHandler) - -// Package subscription is a generated GoMock package. -package subscription - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockProtocol is a mock of Protocol interface. -type MockProtocol struct { - ctrl *gomock.Controller - recorder *MockProtocolMockRecorder -} - -// MockProtocolMockRecorder is the mock recorder for MockProtocol. -type MockProtocolMockRecorder struct { - mock *MockProtocol -} - -// NewMockProtocol creates a new mock instance. -func NewMockProtocol(ctrl *gomock.Controller) *MockProtocol { - mock := &MockProtocol{ctrl: ctrl} - mock.recorder = &MockProtocolMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockProtocol) EXPECT() *MockProtocolMockRecorder { - return m.recorder -} - -// EventHandler mocks base method. -func (m *MockProtocol) EventHandler() EventHandler { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "EventHandler") - ret0, _ := ret[0].(EventHandler) - return ret0 -} - -// EventHandler indicates an expected call of EventHandler. -func (mr *MockProtocolMockRecorder) EventHandler() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EventHandler", reflect.TypeOf((*MockProtocol)(nil).EventHandler)) -} - -// Handle mocks base method. -func (m *MockProtocol) Handle(arg0 context.Context, arg1 Engine, arg2 []byte) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Handle", arg0, arg1, arg2) - ret0, _ := ret[0].(error) - return ret0 -} - -// Handle indicates an expected call of Handle. -func (mr *MockProtocolMockRecorder) Handle(arg0, arg1, arg2 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Handle", reflect.TypeOf((*MockProtocol)(nil).Handle), arg0, arg1, arg2) -} - -// MockEventHandler is a mock of EventHandler interface. -type MockEventHandler struct { - ctrl *gomock.Controller - recorder *MockEventHandlerMockRecorder -} - -// MockEventHandlerMockRecorder is the mock recorder for MockEventHandler. -type MockEventHandlerMockRecorder struct { - mock *MockEventHandler -} - -// NewMockEventHandler creates a new mock instance. -func NewMockEventHandler(ctrl *gomock.Controller) *MockEventHandler { - mock := &MockEventHandler{ctrl: ctrl} - mock.recorder = &MockEventHandlerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockEventHandler) EXPECT() *MockEventHandlerMockRecorder { - return m.recorder -} - -// Emit mocks base method. -func (m *MockEventHandler) Emit(arg0 EventType, arg1 string, arg2 []byte, arg3 error) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Emit", arg0, arg1, arg2, arg3) -} - -// Emit indicates an expected call of Emit. -func (mr *MockEventHandlerMockRecorder) Emit(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Emit", reflect.TypeOf((*MockEventHandler)(nil).Emit), arg0, arg1, arg2, arg3) -} diff --git a/pkg/subscription/handler_test.go b/pkg/subscription/handler_test.go deleted file mode 100644 index 125cee516..000000000 --- a/pkg/subscription/handler_test.go +++ /dev/null @@ -1,338 +0,0 @@ -package subscription - -import ( - "context" - "errors" - "sync" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestUniversalProtocolHandler_Handle(t *testing.T) { - t.Run("should terminate when client is disconnected", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - clientMock := NewMockTransportClient(ctrl) - clientMock.EXPECT().IsConnected(). - Return(false). - Times(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionOpened, gomock.Eq(""), gomock.Nil(), gomock.Nil()) - - protocolMock := NewMockProtocol(ctrl) - protocolMock.EXPECT().EventHandler(). - Return(eventHandlerMock). - Times(2) - - engineMock := NewMockEngine(ctrl) - engineMock.EXPECT().TerminateAllSubscriptions(eventHandlerMock). - Do(func(_ EventHandler) { - wg.Done() - }). - Times(1) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - CustomSubscriptionUpdateInterval: 0, - CustomEngine: engineMock, - } - handler, err := NewUniversalProtocolHandlerWithOptions(clientMock, protocolMock, nil, options) - require.NoError(t, err) - - assert.Eventually(t, func() bool { - go handler.Handle(ctx) - time.Sleep(5 * time.Millisecond) - cancelFunc() - <-ctx.Done() // Check if channel is closed - wg.Wait() - return true - }, 1*time.Second, 5*time.Millisecond) - }) - - t.Run("should terminate when reading on closed connection", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - clientMock := NewMockTransportClient(ctrl) - clientMock.EXPECT().IsConnected(). - Return(true). - Times(1) - clientMock.EXPECT().ReadBytesFromClient(). - Return(nil, ErrTransportClientClosedConnection). - Times(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionOpened, gomock.Eq(""), gomock.Nil(), gomock.Nil()) - - protocolMock := NewMockProtocol(ctrl) - protocolMock.EXPECT().EventHandler(). - Return(eventHandlerMock). - Times(2) - - engineMock := NewMockEngine(ctrl) - engineMock.EXPECT().TerminateAllSubscriptions(eventHandlerMock). - Do(func(_ EventHandler) { - wg.Done() - }). - Times(1) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - CustomSubscriptionUpdateInterval: 0, - CustomEngine: engineMock, - } - handler, err := NewUniversalProtocolHandlerWithOptions(clientMock, protocolMock, nil, options) - require.NoError(t, err) - - assert.Eventually(t, func() bool { - go handler.Handle(ctx) - time.Sleep(5 * time.Millisecond) - cancelFunc() - <-ctx.Done() // Check if channel is closed - wg.Wait() - return true - }, 1*time.Second, 5*time.Millisecond) - }) - - t.Run("should sent event on client read error", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - clientMock := NewMockTransportClient(ctrl) - clientMock.EXPECT().ReadBytesFromClient(). - Return(nil, errors.New("read error")). - MinTimes(1) - clientMock.EXPECT().IsConnected(). - Return(true). - MinTimes(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionError, gomock.Eq(""), gomock.Nil(), gomock.Eq(ErrCouldNotReadMessageFromClient)). - MinTimes(1) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionOpened, gomock.Eq(""), gomock.Nil(), gomock.Nil()) - - protocolMock := NewMockProtocol(ctrl) - protocolMock.EXPECT().EventHandler(). - Return(eventHandlerMock). - MinTimes(1) - - engineMock := NewMockEngine(ctrl) - engineMock.EXPECT().TerminateAllSubscriptions(eventHandlerMock). - Do(func(_ EventHandler) { - wg.Done() - }). - Times(1) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - CustomSubscriptionUpdateInterval: 0, - CustomEngine: engineMock, - } - handler, err := NewUniversalProtocolHandlerWithOptions(clientMock, protocolMock, nil, options) - require.NoError(t, err) - - assert.Eventually(t, func() bool { - go handler.Handle(ctx) - time.Sleep(5 * time.Millisecond) - cancelFunc() - <-ctx.Done() // Check if channel is closed - wg.Wait() - return true - }, 1*time.Second, 5*time.Millisecond) - }) - - t.Run("should handover message to protocol handler", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - clientMock := NewMockTransportClient(ctrl) - clientMock.EXPECT().ReadBytesFromClient(). - Return([]byte(`{"type":"start","id":"1","payload":"{\"query\":\"{ hello }\”}"}`), nil). - MinTimes(1) - clientMock.EXPECT().IsConnected(). - Return(true). - MinTimes(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionOpened, gomock.Eq(""), gomock.Nil(), gomock.Nil()) - - engineMock := NewMockEngine(ctrl) - engineMock.EXPECT().TerminateAllSubscriptions(eventHandlerMock). - Do(func(_ EventHandler) { - wg.Done() - }). - Times(1) - - protocolMock := NewMockProtocol(ctrl) - protocolMock.EXPECT().EventHandler(). - Return(eventHandlerMock). - Times(2) - protocolMock.EXPECT().Handle(assignableToContextWithCancel(ctx), gomock.Eq(engineMock), gomock.Eq([]byte(`{"type":"start","id":"1","payload":"{\"query\":\"{ hello }\”}"}`))). - Return(nil). - MinTimes(1) - - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - CustomSubscriptionUpdateInterval: 0, - CustomEngine: engineMock, - } - handler, err := NewUniversalProtocolHandlerWithOptions(clientMock, protocolMock, nil, options) - require.NoError(t, err) - - assert.Eventually(t, func() bool { - go handler.Handle(ctx) - time.Sleep(5 * time.Millisecond) - cancelFunc() - <-ctx.Done() // Check if channel is closed - wg.Wait() - return true - }, 1*time.Second, 5*time.Millisecond) - }) - - t.Run("read error time out", func(t *testing.T) { - t.Run("should stop handler when read error timer runs out", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - clientMock := NewMockTransportClient(ctrl) - clientMock.EXPECT().ReadBytesFromClient(). - Return(nil, errors.New("random error")). - MinTimes(1) - clientMock.EXPECT().IsConnected(). - Return(true). - MinTimes(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionError, gomock.Eq(""), gomock.Nil(), gomock.Eq(ErrCouldNotReadMessageFromClient)). - MinTimes(1) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionOpened, gomock.Eq(""), gomock.Nil(), gomock.Nil()) - - protocolMock := NewMockProtocol(ctrl) - protocolMock.EXPECT().EventHandler(). - Return(eventHandlerMock). - MinTimes(1) - - engineMock := NewMockEngine(ctrl) - engineMock.EXPECT().TerminateAllSubscriptions(eventHandlerMock). - Do(func(_ EventHandler) { - wg.Done() - }). - Times(1) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - CustomSubscriptionUpdateInterval: 0, - CustomReadErrorTimeOut: 5 * time.Millisecond, - CustomEngine: engineMock, - } - handler, err := NewUniversalProtocolHandlerWithOptions(clientMock, protocolMock, nil, options) - require.NoError(t, err) - - assert.Eventually(t, func() bool { - go handler.Handle(ctx) - time.Sleep(30 * time.Millisecond) - wg.Wait() - return true - }, 1*time.Second, 5*time.Millisecond) - }) - - t.Run("should continue running handler after intermittent read error", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - readErrorCounter := 0 - readErrorReturn := func() error { - var err error - if readErrorCounter == 0 { - err = errors.New("random error") - } - readErrorCounter++ - return err - } - - clientMock := NewMockTransportClient(ctrl) - clientMock.EXPECT().ReadBytesFromClient(). - DoAndReturn(func() ([]byte, error) { - return nil, readErrorReturn() - }, - ). - MinTimes(1) - clientMock.EXPECT().IsConnected(). - Return(true). - MinTimes(1) - - eventHandlerMock := NewMockEventHandler(ctrl) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionError, gomock.Eq(""), gomock.Nil(), gomock.Eq(ErrCouldNotReadMessageFromClient)). - MinTimes(1) - eventHandlerMock.EXPECT().Emit(EventTypeOnConnectionOpened, gomock.Eq(""), gomock.Nil(), gomock.Nil()) - - protocolMock := NewMockProtocol(ctrl) - protocolMock.EXPECT().EventHandler(). - Return(eventHandlerMock). - MinTimes(1) - - engineMock := NewMockEngine(ctrl) - engineMock.EXPECT().TerminateAllSubscriptions(eventHandlerMock). - Do(func(_ EventHandler) { - wg.Done() - }). - Times(1) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - options := UniversalProtocolHandlerOptions{ - Logger: abstractlogger.Noop{}, - CustomSubscriptionUpdateInterval: 0, - CustomReadErrorTimeOut: 5 * time.Millisecond, - CustomEngine: engineMock, - } - handler, err := NewUniversalProtocolHandlerWithOptions(clientMock, protocolMock, nil, options) - require.NoError(t, err) - - assert.Eventually(t, func() bool { - go handler.Handle(ctx) - time.Sleep(10 * time.Millisecond) - cancelFunc() - <-ctx.Done() // Check if channel is closed - wg.Wait() - return true - }, 1*time.Second, 5*time.Millisecond) - }) - }) -} diff --git a/pkg/subscription/init.go b/pkg/subscription/init.go deleted file mode 100644 index f63a3a7e3..000000000 --- a/pkg/subscription/init.go +++ /dev/null @@ -1,49 +0,0 @@ -package subscription - -import ( - "context" - "encoding/json" -) - -// WebsocketInitFunc is called when the server receives connection init message from the client. -// This can be used to check initial payload to see whether to accept the websocket connection. -// Deprecated: Use websocket.InitFunc instead. -type WebsocketInitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error) - -// InitPayload is a structure that is parsed from the websocket init message payload. -// Deprecated: Use websocket.InitPayload instead. -type InitPayload json.RawMessage - -// GetString safely gets a string value from the payload. It returns an empty string if the -// payload is nil or the value isn't set. -func (p InitPayload) GetString(key string) string { - if p == nil { - return "" - } - - var payload map[string]interface{} - if err := json.Unmarshal(p, &payload); err != nil { - return "" - } - - if value, ok := payload[key]; ok { - res, _ := value.(string) - return res - } - - return "" -} - -// Authorization is a shorthand for getting the Authorization header from the -// payload. -func (p InitPayload) Authorization() string { - if value := p.GetString("Authorization"); value != "" { - return value - } - - if value := p.GetString("authorization"); value != "" { - return value - } - - return "" -} diff --git a/pkg/subscription/legacy_handler.go b/pkg/subscription/legacy_handler.go deleted file mode 100644 index 5e25738ca..000000000 --- a/pkg/subscription/legacy_handler.go +++ /dev/null @@ -1,499 +0,0 @@ -package subscription - -import ( - "bytes" - "context" - "encoding/json" - "sync" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/ast" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -const ( - MessageTypeConnectionInit = "connection_init" - MessageTypeConnectionAck = "connection_ack" - MessageTypeConnectionError = "connection_error" - MessageTypeConnectionTerminate = "connection_terminate" - MessageTypeConnectionKeepAlive = "ka" - MessageTypeStart = "start" - MessageTypeStop = "stop" - MessageTypeData = "data" - MessageTypeError = "error" - MessageTypeComplete = "complete" -) - -// Message defines the actual subscription message which will be passed from client to server and vice versa. -// -// Deprecated: Prefer using TransportClient that is based on byte slices instead of this Message struct. -type Message struct { - Id string `json:"id"` - Type string `json:"type"` - Payload json.RawMessage `json:"payload"` -} - -// Client provides an interface which can be implemented by any possible subscription client like websockets, mqtt, etc. -// -// Deprecated: Use TransportClient instead. -type Client interface { - // ReadFromClient will invoke a read operation from the client connection. - ReadFromClient() (*Message, error) - // WriteToClient will invoke a write operation to the client connection. - WriteToClient(Message) error - // IsConnected will indicate if a connection is still established. - IsConnected() bool - // Disconnect will close the connection between server and client. - Disconnect() error -} - -// Handler is the actual subscription handler which will keep track on how to handle messages coming from the client. -type Handler struct { - logger abstractlogger.Logger - // client will hold the subscription client implementation. - client Client - // keepAliveInterval is the actual interval on which the server send keep alive messages to the client. - keepAliveInterval time.Duration - // subscriptionUpdateInterval is the actual interval on which the server sends subscription updates to the client. - subscriptionUpdateInterval time.Duration - // subCancellations stores a map containing the cancellation functions to every active subscription. - subCancellations subscriptionCancellations - // executorPool is responsible to create and hold executors. - executorPool ExecutorPool - // bufferPool will hold buffers. - bufferPool *sync.Pool - // initFunc will check initial payload to see whether to accept the websocket connection. - initFunc WebsocketInitFunc -} - -func NewHandlerWithInitFunc( - logger abstractlogger.Logger, - client Client, - executorPool ExecutorPool, - initFunc WebsocketInitFunc, -) (*Handler, error) { - keepAliveInterval, err := time.ParseDuration(DefaultKeepAliveInterval) - if err != nil { - return nil, err - } - - subscriptionUpdateInterval, err := time.ParseDuration(DefaultSubscriptionUpdateInterval) - if err != nil { - return nil, err - } - - return &Handler{ - logger: logger, - client: client, - keepAliveInterval: keepAliveInterval, - subscriptionUpdateInterval: subscriptionUpdateInterval, - subCancellations: subscriptionCancellations{}, - executorPool: executorPool, - bufferPool: &sync.Pool{ - New: func() interface{} { - writer := graphql.NewEngineResultWriterFromBuffer(bytes.NewBuffer(make([]byte, 0, 1024))) - return &writer - }, - }, - initFunc: initFunc, - }, nil -} - -// NewHandler creates a new subscription handler. -func NewHandler(logger abstractlogger.Logger, client Client, executorPool ExecutorPool) (*Handler, error) { - return NewHandlerWithInitFunc(logger, client, executorPool, nil) -} - -// Handle will handle the subscription connection. -func (h *Handler) Handle(ctx context.Context) { - defer h.subCancellations.CancelAll() - - for { - if !h.client.IsConnected() { - h.logger.Debug("subscription.Handler.Handle()", - abstractlogger.String("message", "client has disconnected"), - ) - - return - } - - message, err := h.client.ReadFromClient() - if err != nil { - h.logger.Error("subscription.Handler.Handle()", - abstractlogger.Error(err), - abstractlogger.Any("message", message), - ) - - h.handleConnectionError("could not read message from client") - } else if message != nil { - switch message.Type { - case MessageTypeConnectionInit: - ctx, err = h.handleInit(ctx, message.Payload) - if err != nil { - h.terminateConnection("failed to accept the websocket connection") - return - } - - go h.handleKeepAlive(ctx) - case MessageTypeStart: - h.handleStart(ctx, message.Id, message.Payload) - case MessageTypeStop: - h.handleStop(message.Id) - case MessageTypeConnectionTerminate: - h.handleConnectionTerminate() - return - } - } - - select { - case <-ctx.Done(): - return - default: - continue - } - } -} - -// ChangeKeepAliveInterval can be used to change the keep alive interval. -func (h *Handler) ChangeKeepAliveInterval(d time.Duration) { - h.keepAliveInterval = d -} - -// ChangeSubscriptionUpdateInterval can be used to change the update interval. -func (h *Handler) ChangeSubscriptionUpdateInterval(d time.Duration) { - h.subscriptionUpdateInterval = d -} - -// handleInit will handle an init message. -func (h *Handler) handleInit(ctx context.Context, payload []byte) (extendedCtx context.Context, err error) { - if h.initFunc != nil { - var initPayload InitPayload - // decode initial payload - if len(payload) > 0 { - initPayload = payload - } - // check initial payload to see whether to accept the websocket connection - if extendedCtx, err = h.initFunc(ctx, initPayload); err != nil { - return extendedCtx, err - } - } else { - extendedCtx = ctx - } - - ackMessage := Message{ - Type: MessageTypeConnectionAck, - } - - if err = h.client.WriteToClient(ackMessage); err != nil { - return extendedCtx, err - } - - return extendedCtx, nil -} - -// handleStart will handle s start message. -func (h *Handler) handleStart(ctx context.Context, id string, payload []byte) { - executor, err := h.executorPool.Get(payload) - if err != nil { - h.logger.Error("subscription.Handler.handleStart()", - abstractlogger.Error(err), - ) - - h.handleError(id, graphql.RequestErrorsFromError(err)) - return - } - - if err = h.handleOnBeforeStart(executor); err != nil { - h.handleError(id, graphql.RequestErrorsFromError(err)) - return - } - - if executor.OperationType() == ast.OperationTypeSubscription { - ctx, subsErr := h.subCancellations.AddWithParent(id, ctx) - if subsErr != nil { - h.handleError(id, graphql.RequestErrorsFromError(subsErr)) - return - } - go h.startSubscription(ctx, id, executor) - return - } - - go h.handleNonSubscriptionOperation(ctx, id, executor) -} - -func (h *Handler) handleOnBeforeStart(executor Executor) error { - switch e := executor.(type) { - case *ExecutorV2: - if hook := e.engine.GetWebsocketBeforeStartHook(); hook != nil { - return hook.OnBeforeStart(e.reqCtx, e.operation) - } - case *ExecutorV1: - // do nothing - } - - return nil -} - -// handleNonSubscriptionOperation will handle a non-subscription operation like a query or a mutation. -func (h *Handler) handleNonSubscriptionOperation(ctx context.Context, id string, executor Executor) { - defer func() { - err := h.executorPool.Put(executor) - if err != nil { - h.logger.Error("subscription.Handle.handleNonSubscriptionOperation()", - abstractlogger.Error(err), - ) - } - }() - - executor.SetContext(ctx) - buf := h.bufferPool.Get().(*graphql.EngineResultWriter) - buf.Reset() - - defer h.bufferPool.Put(buf) - - // err := executor.Execute(executionContext, node, buf) - err := executor.Execute(buf) - if err != nil { - h.logger.Error("subscription.Handle.handleNonSubscriptionOperation()", - abstractlogger.Error(err), - ) - - h.handleError(id, graphql.RequestErrorsFromError(err)) - return - } - - h.logger.Debug("subscription.Handle.handleNonSubscriptionOperation()", - abstractlogger.ByteString("execution_result", buf.Bytes()), - ) - - h.sendData(id, buf.Bytes()) - h.sendComplete(id) -} - -// startSubscription will invoke the actual subscription. -func (h *Handler) startSubscription(ctx context.Context, id string, executor Executor) { - defer func() { - err := h.executorPool.Put(executor) - if err != nil { - h.logger.Error("subscription.Handle.startSubscription()", - abstractlogger.Error(err), - ) - } - }() - - executor.SetContext(ctx) - buf := h.bufferPool.Get().(*graphql.EngineResultWriter) - buf.Reset() - - defer h.bufferPool.Put(buf) - - h.executeSubscription(buf, id, executor) - - for { - buf.Reset() - select { - case <-ctx.Done(): - return - case <-time.After(h.subscriptionUpdateInterval): - h.executeSubscription(buf, id, executor) - } - } - -} - -// executeSubscription will keep execution the subscription until it ends. -func (h *Handler) executeSubscription(buf *graphql.EngineResultWriter, id string, executor Executor) { - buf.SetFlushCallback(func(data []byte) { - h.logger.Debug("subscription.Handle.executeSubscription()", - abstractlogger.ByteString("execution_result", data), - ) - h.sendData(id, data) - }) - defer buf.SetFlushCallback(nil) - - err := executor.Execute(buf) - if err != nil { - h.logger.Error("subscription.Handle.executeSubscription()", - abstractlogger.Error(err), - ) - - h.handleError(id, graphql.RequestErrorsFromError(err)) - return - } - - if buf.Len() > 0 { - data := buf.Bytes() - h.logger.Debug("subscription.Handle.executeSubscription()", - abstractlogger.ByteString("execution_result", data), - ) - h.sendData(id, data) - } -} - -// handleStop will handle a stop message, -func (h *Handler) handleStop(id string) { - h.subCancellations.Cancel(id) - h.sendComplete(id) -} - -// sendData will send a data message to the client. -func (h *Handler) sendData(id string, responseData []byte) { - dataMessage := Message{ - Id: id, - Type: MessageTypeData, - Payload: responseData, - } - - err := h.client.WriteToClient(dataMessage) - if err != nil { - h.logger.Error("subscription.Handler.sendData()", - abstractlogger.Error(err), - ) - } -} - -// nolint -// sendComplete will send a complete message to the client. -func (h *Handler) sendComplete(id string) { - completeMessage := Message{ - Id: id, - Type: MessageTypeComplete, - Payload: nil, - } - - err := h.client.WriteToClient(completeMessage) - if err != nil { - h.logger.Error("subscription.Handler.sendComplete()", - abstractlogger.Error(err), - ) - } -} - -// handleConnectionTerminate will handle a connection terminate message. -func (h *Handler) handleConnectionTerminate() { - err := h.client.Disconnect() - if err != nil { - h.logger.Error("subscription.Handler.handleConnectionTerminate()", - abstractlogger.Error(err), - ) - } -} - -// handleKeepAlive will handle the keep alive loop. -func (h *Handler) handleKeepAlive(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case <-time.After(h.keepAliveInterval): - if !h.client.IsConnected() { - return - } - h.sendKeepAlive() - } - } -} - -// sendKeepAlive will send a keep alive message to the client. -func (h *Handler) sendKeepAlive() { - keepAliveMessage := Message{ - Type: MessageTypeConnectionKeepAlive, - } - - err := h.client.WriteToClient(keepAliveMessage) - if err != nil { - h.logger.Error("subscription.Handler.sendKeepAlive()", - abstractlogger.Error(err), - ) - } -} - -func (h *Handler) terminateConnection(reason interface{}) { - payloadBytes, err := json.Marshal(reason) - if err != nil { - h.logger.Error("subscription.Handler.terminateConnection()", - abstractlogger.Error(err), - abstractlogger.Any("errorPayload", reason), - ) - } - - connectionErrorMessage := Message{ - Type: MessageTypeConnectionTerminate, - Payload: payloadBytes, - } - - err = h.client.WriteToClient(connectionErrorMessage) - if err != nil { - h.logger.Error("subscription.Handler.terminateConnection()", - abstractlogger.Error(err), - ) - - err := h.client.Disconnect() - if err != nil { - h.logger.Error("subscription.Handler.terminateConnection()", - abstractlogger.Error(err), - ) - } - } -} - -// handleConnectionError will handle a connection error message. -func (h *Handler) handleConnectionError(errorPayload interface{}) { - payloadBytes, err := json.Marshal(errorPayload) - if err != nil { - h.logger.Error("subscription.Handler.handleConnectionError()", - abstractlogger.Error(err), - abstractlogger.Any("errorPayload", errorPayload), - ) - } - - connectionErrorMessage := Message{ - Type: MessageTypeConnectionError, - Payload: payloadBytes, - } - - err = h.client.WriteToClient(connectionErrorMessage) - if err != nil { - h.logger.Error("subscription.Handler.handleConnectionError()", - abstractlogger.Error(err), - ) - - err := h.client.Disconnect() - if err != nil { - h.logger.Error("subscription.Handler.handleError()", - abstractlogger.Error(err), - ) - } - } -} - -// handleError will handle an error message. -func (h *Handler) handleError(id string, errors graphql.RequestErrors) { - payloadBytes, err := json.Marshal(errors) - if err != nil { - h.logger.Error("subscription.Handler.handleError()", - abstractlogger.Error(err), - abstractlogger.Any("errors", errors), - ) - } - - errorMessage := Message{ - Id: id, - Type: MessageTypeError, - Payload: payloadBytes, - } - - err = h.client.WriteToClient(errorMessage) - if err != nil { - h.logger.Error("subscription.Handler.handleError()", - abstractlogger.Error(err), - ) - } -} - -// ActiveSubscriptions will return the actual number of active subscriptions for that client. -func (h *Handler) ActiveSubscriptions() int { - return h.subCancellations.Len() -} diff --git a/pkg/subscription/legacy_handler_test.go b/pkg/subscription/legacy_handler_test.go deleted file mode 100644 index 9b9c941c6..000000000 --- a/pkg/subscription/legacy_handler_test.go +++ /dev/null @@ -1,917 +0,0 @@ -package subscription - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/starwars" - "github.com/wundergraph/graphql-go-tools/pkg/testing/subscriptiontesting" -) - -type handlerRoutine func(ctx context.Context) func() bool - -type websocketHook struct { - called bool - reqCtx context.Context - hook func(reqCtx context.Context, operation *graphql.Request) error -} - -func (w *websocketHook) OnBeforeStart(reqCtx context.Context, operation *graphql.Request) error { - w.called = true - if w.hook != nil { - return w.hook(reqCtx, operation) - } - return nil -} - -func TestHandler_Handle(t *testing.T) { - starwars.SetRelativePathToStarWarsPackage("../starwars") - - t.Run("engine v1", func(t *testing.T) { - executorPool := NewExecutorV1Pool(starwars.NewExecutionHandler(t)) - - t.Run("connection_init", func(t *testing.T) { - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("should send connection error message when error on read occurs", func(t *testing.T) { - client.prepareConnectionInitMessage().withError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Type: MessageTypeConnectionError, - Payload: jsonizePayload(t, "could not read message from client"), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - - t.Run("should successfully init connection and respond with ack", func(t *testing.T) { - client.reconnect().and().prepareConnectionInitMessage().withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Type: MessageTypeConnectionAck, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - }) - - t.Run("connection_keep_alive", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("should successfully send keep alive messages after connection_init", func(t *testing.T) { - keepAliveInterval, err := time.ParseDuration("5ms") - require.NoError(t, err) - - subscriptionHandler.ChangeKeepAliveInterval(keepAliveInterval) - - client.prepareConnectionInitMessage().withoutError().and().send() - ctx, cancelFunc := context.WithCancel(context.Background()) - - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - expectedMessage := Message{ - Type: MessageTypeConnectionKeepAlive, - } - - messagesFromServer := client.readFromServer() - waitForKeepAliveMessage := func() bool { - for len(messagesFromServer) < 2 { - messagesFromServer = client.readFromServer() - } - return true - } - - assert.Eventually(t, waitForKeepAliveMessage, 1*time.Second, 5*time.Millisecond) - assert.Contains(t, messagesFromServer, expectedMessage) - - cancelFunc() - }) - }) - - t.Run("erroneous operation(s)", func(t *testing.T) { - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - t.Run("should send error when query contains syntax errors", func(t *testing.T) { - payload := []byte(`{"operationName": "Broken", "query Broken {": "", "variables": null}`) - client.prepareStartMessage("1", payload).withoutError().send() - - waitForClientHavingAMessage := func() bool { - return client.hasMoreMessagesThan(0) - } - require.Eventually(t, waitForClientHavingAMessage, 5*time.Second, 5*time.Millisecond) - - messagesFromServer := client.readFromServer() - assert.Len(t, messagesFromServer, 1) - assert.Equal(t, "1", messagesFromServer[0].Id) - assert.Equal(t, MessageTypeError, messagesFromServer[0].Type) - assert.Equal(t, `[{"message":"document doesn't contain any executable operation"}]`, string(messagesFromServer[0].Payload)) - }) - - cancelFunc() - }) - - t.Run("non-subscription query", func(t *testing.T) { - - t.Run("should process query and return error when query is not valid", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - payload := starwars.LoadQuery(t, starwars.FileInvalidQuery, nil) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - cancelFunc() - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForClientHavingAMessage := func() bool { - return client.hasMoreMessagesThan(0) - } - require.Eventually(t, waitForClientHavingAMessage, 1*time.Second, 5*time.Millisecond) - - messagesFromServer := client.readFromServer() - assert.Len(t, messagesFromServer, 1) - assert.Equal(t, "1", messagesFromServer[0].Id) - assert.Equal(t, MessageTypeError, messagesFromServer[0].Type) - assert.Equal(t, `[{"message":"field: invalid not defined on type: Character","path":["query","hero","invalid"]}]`, string(messagesFromServer[0].Payload)) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - }) - - t.Run("should process and send result for a query", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - payload := starwars.LoadQuery(t, starwars.FileSimpleHeroQuery, nil) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - cancelFunc() - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForClientHavingTwoMessages := func() bool { - return client.hasMoreMessagesThan(1) - } - require.Eventually(t, waitForClientHavingTwoMessages, 60*time.Second, 5*time.Millisecond) - - expectedDataMessage := Message{ - Id: "1", - Type: MessageTypeData, - Payload: []byte(`{"data":null}`), - } - - expectedCompleteMessage := Message{ - Id: "1", - Type: MessageTypeComplete, - Payload: nil, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedDataMessage) - assert.Contains(t, messagesFromServer, expectedCompleteMessage) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - }) - }) - - t.Run("subscription query", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("should start subscription on start", func(t *testing.T) { - payload := starwars.LoadQuery(t, starwars.FileRemainingJedisSubscription, nil) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - time.Sleep(10 * time.Millisecond) - cancelFunc() - - expectedMessage := Message{ - Id: "1", - Type: MessageTypeData, - Payload: []byte(`{"data":null}`), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - assert.Equal(t, 1, subscriptionHandler.ActiveSubscriptions()) - }) - - t.Run("should stop subscription on stop and send complete message to client", func(t *testing.T) { - client.reconnect().prepareStopMessage("1").withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForCanceledSubscription := func() bool { - for subscriptionHandler.ActiveSubscriptions() > 0 { - } - return true - } - - assert.Eventually(t, waitForCanceledSubscription, 1*time.Second, 5*time.Millisecond) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - - expectedMessage := Message{ - Id: "1", - Type: MessageTypeComplete, - Payload: nil, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - - cancelFunc() - }) - }) - - t.Run("connection_terminate", func(t *testing.T) { - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("should successfully disconnect from client", func(t *testing.T) { - client.prepareConnectionTerminateMessage().withoutError().and().send() - require.True(t, client.connected) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - assert.False(t, client.connected) - }) - }) - - t.Run("client is disconnected", func(t *testing.T) { - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("server should not read from client and stop handler", func(t *testing.T) { - err := client.Disconnect() - require.NoError(t, err) - require.False(t, client.connected) - - client.prepareConnectionInitMessage().withoutError() - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - assert.False(t, client.serverHasRead) - }) - }) - }) - - t.Run("engine v2", func(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - chatServer := httptest.NewServer(subscriptiontesting.ChatGraphQLEndpointHandler()) - defer chatServer.Close() - - t.Run("connection_init", func(t *testing.T) { - var initPayloadAuthorization string - - executorPool, _ := setupEngineV2(t, ctx, chatServer.URL) - _, client, handlerRoutine := setupSubscriptionHandlerWithInitFuncTest(t, executorPool, func(ctx context.Context, initPayload InitPayload) (context.Context, error) { - if initPayloadAuthorization == "" { - return ctx, nil - } - - if initPayloadAuthorization != initPayload.Authorization() { - return nil, fmt.Errorf("unknown user: %s", initPayload.Authorization()) - } - - return ctx, nil - }) - - t.Run("should send connection error message when error on read occurs", func(t *testing.T) { - client.prepareConnectionInitMessage().withError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Type: MessageTypeConnectionError, - Payload: jsonizePayload(t, "could not read message from client"), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - - t.Run("should successfully init connection and respond with ack", func(t *testing.T) { - client.reconnect().and().prepareConnectionInitMessage().withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Type: MessageTypeConnectionAck, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - - t.Run("should send connection error message when error on check initial payload occurs", func(t *testing.T) { - initPayloadAuthorization = "123" - defer func() { initPayloadAuthorization = "" }() - - client.reconnect().and().prepareConnectionInitMessageWithPayload([]byte(`{"Authorization": "111"}`)).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Type: MessageTypeConnectionTerminate, - Payload: jsonizePayload(t, "failed to accept the websocket connection"), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - - t.Run("should successfully init connection and respond with ack when initial payload successfully occurred ", func(t *testing.T) { - initPayloadAuthorization = "123" - defer func() { initPayloadAuthorization = "" }() - - client.reconnect().and().prepareConnectionInitMessageWithPayload([]byte(`{"Authorization": "123"}`)).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Type: MessageTypeConnectionAck, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - }) - - t.Run("connection_keep_alive", func(t *testing.T) { - executorPool, _ := setupEngineV2(t, ctx, chatServer.URL) - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("should successfully send keep alive messages after connection_init", func(t *testing.T) { - keepAliveInterval, err := time.ParseDuration("5ms") - require.NoError(t, err) - - subscriptionHandler.ChangeKeepAliveInterval(keepAliveInterval) - - client.prepareConnectionInitMessage().withoutError().and().send() - ctx, cancelFunc := context.WithCancel(context.Background()) - - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - expectedMessage := Message{ - Type: MessageTypeConnectionKeepAlive, - } - - messagesFromServer := client.readFromServer() - waitForKeepAliveMessage := func() bool { - for len(messagesFromServer) < 2 { - messagesFromServer = client.readFromServer() - } - return true - } - - assert.Eventually(t, waitForKeepAliveMessage, 1*time.Second, 5*time.Millisecond) - assert.Contains(t, messagesFromServer, expectedMessage) - - cancelFunc() - }) - }) - - t.Run("erroneous operation(s)", func(t *testing.T) { - executorPool, _ := setupEngineV2(t, ctx, chatServer.URL) - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - t.Run("should send error when query contains syntax errors", func(t *testing.T) { - payload := []byte(`{"operationName": "Broken", "query Broken {": "", "variables": null}`) - client.prepareStartMessage("1", payload).withoutError().send() - - waitForClientHavingAMessage := func() bool { - return client.hasMoreMessagesThan(0) - } - require.Eventually(t, waitForClientHavingAMessage, 5*time.Second, 5*time.Millisecond) - - expectedMessage := Message{ - Id: "1", - Type: MessageTypeError, - Payload: []byte(`[{"message":"document doesn't contain any executable operation"}]`), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - }) - - cancelFunc() - }) - - t.Run("non-subscription query", func(t *testing.T) { - executorPool, hookHolder := setupEngineV2(t, ctx, chatServer.URL) - - t.Run("should process query and return error when query is not valid", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.InvalidOperation) - require.NoError(t, err) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - cancelFunc() - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForClientHavingAMessage := func() bool { - return client.hasMoreMessagesThan(0) - } - require.Eventually(t, waitForClientHavingAMessage, 1*time.Second, 5*time.Millisecond) - - expectedErrorMessage := Message{ - Id: "1", - Type: MessageTypeError, - Payload: []byte(`[{"message":"field: serverName not defined on type: Query","path":["query","serverName"]}]`), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedErrorMessage) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - }) - - t.Run("should process and send result for a query", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.MutationSendMessage) - require.NoError(t, err) - - hookHolder.hook = func(ctx context.Context, operation *graphql.Request) error { - assert.Equal(t, hookHolder.reqCtx, ctx) - assert.Contains(t, operation.Query, "mutation SendMessage") - return nil - } - defer func() { - hookHolder.hook = nil - }() - - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForClientHavingTwoMessages := func() bool { - return client.hasMoreMessagesThan(1) - } - require.Eventually(t, waitForClientHavingTwoMessages, 60*time.Second, 5*time.Millisecond) - - expectedDataMessage := Message{ - Id: "1", - Type: MessageTypeData, - Payload: []byte(`{"data":{"post":{"text":"Hello World!","createdBy":"myuser"}}}`), - } - - expectedCompleteMessage := Message{ - Id: "1", - Type: MessageTypeComplete, - Payload: nil, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedDataMessage) - assert.Contains(t, messagesFromServer, expectedCompleteMessage) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - assert.True(t, hookHolder.called) - }) - - t.Run("should process and send error message from hook for a query", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.MutationSendMessage) - require.NoError(t, err) - - errMsg := "error_on_operation" - hookHolder.hook = func(ctx context.Context, operation *graphql.Request) error { - return errors.New(errMsg) - } - defer func() { - hookHolder.hook = nil - }() - - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - cancelFunc() - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForClientHavingTwoMessages := func() bool { - return client.hasMoreMessagesThan(0) - } - require.Eventually(t, waitForClientHavingTwoMessages, 5*time.Second, 5*time.Millisecond) - - jsonErrMessage, err := json.Marshal(graphql.RequestErrors{ - {Message: errMsg}, - }) - require.NoError(t, err) - expectedErrMessage := Message{ - Id: "1", - Type: MessageTypeError, - Payload: jsonErrMessage, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedErrMessage) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - assert.True(t, hookHolder.called) - }) - - }) - - t.Run("subscription query", func(t *testing.T) { - executorPool, hookHolder := setupEngineV2(t, ctx, chatServer.URL) - - t.Run("should start subscription on start", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.SubscriptionLiveMessages) - require.NoError(t, err) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - time.Sleep(50 * time.Millisecond) - defer cancelFunc() - - go sendChatMutation(t, chatServer.URL) - - require.Eventually(t, func() bool { - return client.hasMoreMessagesThan(0) - }, 1*time.Second, 10*time.Millisecond) - - expectedMessage := Message{ - Id: "1", - Type: MessageTypeData, - Payload: []byte(`{"data":{"messageAdded":{"text":"Hello World!","createdBy":"myuser"}}}`), - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - assert.Equal(t, 1, subscriptionHandler.ActiveSubscriptions()) - }) - - t.Run("id collisions should not be allowed", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.SubscriptionLiveMessages) - require.NoError(t, err) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - time.Sleep(10 * time.Millisecond) - defer cancelFunc() - - go sendChatMutation(t, chatServer.URL) - - require.Eventually(t, func() bool { - return client.hasMoreMessagesThan(0) - }, 5*time.Second, 10*time.Millisecond) - - assert.Equal(t, 1, subscriptionHandler.ActiveSubscriptions()) - - client.prepareStartMessage("1", payload).withoutError().and().send() - require.Eventually(t, func() bool { - return client.hasMoreMessagesThan(1) - }, 5*time.Second, 10*time.Millisecond) - - messagesFromServer := client.readFromServer() - // There are two messages in this slice. The first one is a data message for the first start message - // The second one is an error message because we tried to create a new subscription with an already existed - // id. - - expectedDataMessage := Message{ - Id: "1", - Type: MessageTypeData, - Payload: []byte(`{"data":{"messageAdded":{"text":"Hello World!","createdBy":"myuser"}}}`), - } - assert.Contains(t, messagesFromServer, expectedDataMessage) - - expectedErrorMessage := Message{ - Id: "1", - Type: MessageTypeError, - Payload: []byte(`[{"message":"subscriber id already exists: 1"}]`), - } - assert.Contains(t, messagesFromServer, expectedErrorMessage) - }) - - t.Run("should fail with validation error for invalid Subscription", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.InvalidSubscriptionLiveMessages) - require.NoError(t, err) - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - time.Sleep(10 * time.Millisecond) - cancelFunc() - - go sendChatMutation(t, chatServer.URL) - - require.Eventually(t, func() bool { - return client.hasMoreMessagesThan(0) - }, 1*time.Second, 10*time.Millisecond) - - messagesFromServer := client.readFromServer() - assert.Len(t, messagesFromServer, 1) - assert.Equal(t, "1", messagesFromServer[0].Id) - assert.Equal(t, MessageTypeError, messagesFromServer[0].Type) - assert.Equal(t, `[{"message":"differing fields for objectName 'a' on (potentially) same type","path":["subscription","messageAdded"]}]`, string(messagesFromServer[0].Payload)) - assert.Equal(t, 1, subscriptionHandler.ActiveSubscriptions()) - }) - - t.Run("should stop subscription on stop and send complete message to client", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - client.reconnect().prepareStopMessage("1").withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - waitForCanceledSubscription := func() bool { - for subscriptionHandler.ActiveSubscriptions() > 0 { - } - return true - } - - assert.Eventually(t, waitForCanceledSubscription, 1*time.Second, 5*time.Millisecond) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - - expectedMessage := Message{ - Id: "1", - Type: MessageTypeComplete, - Payload: nil, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedMessage) - - cancelFunc() - }) - - t.Run("should interrupt subscription on start and return error message from hook", func(t *testing.T) { - subscriptionHandler, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - payload, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.SubscriptionLiveMessages) - require.NoError(t, err) - - errMsg := "sub_interrupted" - hookHolder.hook = func(ctx context.Context, operation *graphql.Request) error { - return errors.New(errMsg) - } - - client.prepareStartMessage("1", payload).withoutError().and().send() - - ctx, cancelFunc := context.WithCancel(context.Background()) - handlerRoutineFunc := handlerRoutine(ctx) - go handlerRoutineFunc() - - time.Sleep(10 * time.Millisecond) - cancelFunc() - - go sendChatMutation(t, chatServer.URL) - - require.Eventually(t, func() bool { - return client.hasMoreMessagesThan(0) - }, 1*time.Second, 10*time.Millisecond) - - jsonErrMessage, err := json.Marshal(graphql.RequestErrors{ - {Message: errMsg}, - }) - require.NoError(t, err) - expectedErrMessage := Message{ - Id: "1", - Type: MessageTypeError, - Payload: jsonErrMessage, - } - - messagesFromServer := client.readFromServer() - assert.Contains(t, messagesFromServer, expectedErrMessage) - assert.Equal(t, 0, subscriptionHandler.ActiveSubscriptions()) - assert.True(t, hookHolder.called) - }) - }) - - t.Run("connection_terminate", func(t *testing.T) { - executorPool, _ := setupEngineV2(t, ctx, chatServer.URL) - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("should successfully disconnect from client", func(t *testing.T) { - client.prepareConnectionTerminateMessage().withoutError().and().send() - require.True(t, client.connected) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - assert.False(t, client.connected) - }) - }) - - t.Run("client is disconnected", func(t *testing.T) { - executorPool, _ := setupEngineV2(t, ctx, chatServer.URL) - _, client, handlerRoutine := setupSubscriptionHandlerTest(t, executorPool) - - t.Run("server should not read from client and stop handler", func(t *testing.T) { - err := client.Disconnect() - require.NoError(t, err) - require.False(t, client.connected) - - client.prepareConnectionInitMessage().withoutError() - ctx, cancelFunc := context.WithCancel(context.Background()) - - cancelFunc() - require.Eventually(t, handlerRoutine(ctx), 1*time.Second, 5*time.Millisecond) - - assert.False(t, client.serverHasRead) - }) - }) - }) - -} - -func setupEngineV2(t *testing.T, ctx context.Context, chatServerURL string) (*ExecutorV2Pool, *websocketHook) { - chatSchemaBytes, err := subscriptiontesting.LoadSchemaFromExamplesDirectoryWithinPkg() - require.NoError(t, err) - - chatSchema, err := graphql.NewSchemaFromReader(bytes.NewBuffer(chatSchemaBytes)) - require.NoError(t, err) - - engineConf := graphql.NewEngineV2Configuration(chatSchema) - engineConf.SetDataSources([]plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Mutation", FieldNames: []string{"post"}}, - {TypeName: "Subscription", FieldNames: []string{"messageAdded"}}, - }, - ChildNodes: []plan.TypeField{ - {TypeName: "Message", FieldNames: []string{"text", "createdBy"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: httpclient.DefaultNetHttpClient, - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: chatServerURL, - Method: http.MethodPost, - Header: nil, - }, - Subscription: graphql_datasource.SubscriptionConfiguration{ - URL: chatServerURL, - }, - }), - }, - }) - engineConf.SetFieldConfigurations([]plan.FieldConfiguration{ - { - TypeName: "Mutation", - FieldName: "post", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "roomName", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "username", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "text", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Subscription", - FieldName: "messageAdded", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "roomName", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }) - - hookHolder := &websocketHook{ - reqCtx: context.Background(), - } - engineConf.SetWebsocketBeforeStartHook(hookHolder) - - req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://localhost:8080", nil) - require.NoError(t, err) - - req.Header.Set("X-Other-Key", "x-other-value") - - initCtx := NewInitialHttpRequestContext(req) - - engine, err := graphql.NewExecutionEngineV2(initCtx, abstractlogger.NoopLogger, engineConf) - require.NoError(t, err) - - executorPool := NewExecutorV2Pool(engine, hookHolder.reqCtx) - - return executorPool, hookHolder -} - -func setupSubscriptionHandlerTest(t *testing.T, executorPool ExecutorPool) (subscriptionHandler *Handler, client *mockClient, routine handlerRoutine) { - return setupSubscriptionHandlerWithInitFuncTest(t, executorPool, nil) -} - -func setupSubscriptionHandlerWithInitFuncTest( - t *testing.T, - executorPool ExecutorPool, - initFunc WebsocketInitFunc, -) (subscriptionHandler *Handler, client *mockClient, routine handlerRoutine) { - client = newMockClient() - - var err error - subscriptionHandler, err = NewHandlerWithInitFunc(abstractlogger.NoopLogger, client, executorPool, initFunc) - require.NoError(t, err) - - routine = func(ctx context.Context) func() bool { - return func() bool { - subscriptionHandler.Handle(ctx) - return true - } - } - - return subscriptionHandler, client, routine -} - -func jsonizePayload(t *testing.T, payload interface{}) json.RawMessage { - jsonBytes, err := json.Marshal(payload) - require.NoError(t, err) - - return jsonBytes -} - -func sendChatMutation(t *testing.T, url string) { - reqBody, err := subscriptiontesting.GraphQLRequestForOperation(subscriptiontesting.MutationSendMessage) - require.NoError(t, err) - - req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(reqBody)) - require.NoError(t, err) - req.Header.Set("Content-Type", "application/json") - - httpClient := http.Client{} - resp, err := httpClient.Do(req) - require.NoError(t, err) - require.Equal(t, http.StatusOK, resp.StatusCode) -} diff --git a/pkg/subscription/mock_client_test.go b/pkg/subscription/mock_client_test.go deleted file mode 100644 index d1ccb7f1c..000000000 --- a/pkg/subscription/mock_client_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package subscription - -import ( - "errors" - "sync" -) - -type mockClient struct { - mu sync.Mutex - messagesFromServer []Message - messageToServer *Message - err error - messagePipe chan *Message - connected bool - serverHasRead bool -} - -func newMockClient() *mockClient { - return &mockClient{ - connected: true, - messagePipe: make(chan *Message, 1), - } -} - -func (c *mockClient) ReadFromClient() (*Message, error) { - c.mu.Lock() - returnErr := c.err - c.mu.Unlock() - returnMessage := <-c.messagePipe - if returnErr != nil { - return nil, returnErr - } - - c.mu.Lock() - defer c.mu.Unlock() - c.serverHasRead = true - c.err = nil - return returnMessage, returnErr -} - -func (c *mockClient) WriteToClient(message Message) error { - c.mu.Lock() - defer c.mu.Unlock() - c.messagesFromServer = append(c.messagesFromServer, message) - return c.err -} - -func (c *mockClient) IsConnected() bool { - return c.connected -} - -func (c *mockClient) Disconnect() error { - c.connected = false - return nil -} - -func (c *mockClient) hasMoreMessagesThan(num int) bool { - c.mu.Lock() - defer c.mu.Unlock() - return len(c.messagesFromServer) > num -} - -func (c *mockClient) readFromServer() []Message { - c.mu.Lock() - defer c.mu.Unlock() - return c.messagesFromServer[0:len(c.messagesFromServer):len(c.messagesFromServer)] -} - -func (c *mockClient) prepareConnectionInitMessage() *mockClient { - c.messageToServer = &Message{ - Type: MessageTypeConnectionInit, - } - - return c -} - -func (c *mockClient) prepareConnectionInitMessageWithPayload(payload []byte) *mockClient { - c.messageToServer = &Message{ - Type: MessageTypeConnectionInit, - Payload: payload, - } - - return c -} - -func (c *mockClient) prepareStartMessage(id string, payload []byte) *mockClient { - c.messageToServer = &Message{ - Id: id, - Type: MessageTypeStart, - Payload: payload, - } - - return c -} - -func (c *mockClient) prepareStopMessage(id string) *mockClient { - c.messageToServer = &Message{ - Id: id, - Type: MessageTypeStop, - Payload: nil, - } - - return c -} - -func (c *mockClient) prepareConnectionTerminateMessage() *mockClient { - c.messageToServer = &Message{ - Type: MessageTypeConnectionTerminate, - } - - return c -} - -func (c *mockClient) send() bool { - c.messagePipe <- c.messageToServer - c.messageToServer = nil - return true -} - -func (c *mockClient) withoutError() *mockClient { - c.mu.Lock() - defer c.mu.Unlock() - c.err = nil - return c -} - -func (c *mockClient) withError() *mockClient { - c.mu.Lock() - defer c.mu.Unlock() - c.err = errors.New("error") - return c -} - -func (c *mockClient) and() *mockClient { - return c -} - -func (c *mockClient) reset() *mockClient { - c.mu.Lock() - defer c.mu.Unlock() - c.messagesFromServer = []Message{} - c.err = nil - return c -} - -func (c *mockClient) reconnect() *mockClient { - c.reset() - c.connected = true - return c -} diff --git a/pkg/subscription/time_out.go b/pkg/subscription/time_out.go deleted file mode 100644 index 329065910..000000000 --- a/pkg/subscription/time_out.go +++ /dev/null @@ -1,38 +0,0 @@ -package subscription - -import ( - "context" - "time" - - "github.com/jensneuse/abstractlogger" -) - -// TimeOutParams is a struct to configure a TimeOutChecker. -type TimeOutParams struct { - Name string - Logger abstractlogger.Logger - TimeOutContext context.Context - TimeOutAction func() - TimeOutDuration time.Duration -} - -// TimeOutChecker is a function that can be used in a go routine to perform a time-out action -// after a specific duration or prevent the time-out action by canceling the time-out context before. -// Use TimeOutParams for configuration. -func TimeOutChecker(params TimeOutParams) { - timer := time.NewTimer(params.TimeOutDuration) - defer timer.Stop() - - for { - select { - case <-params.TimeOutContext.Done(): - return - case <-timer.C: - params.Logger.Error("time out happened", - abstractlogger.String("name", params.Name), - ) - params.TimeOutAction() - return - } - } -} diff --git a/pkg/subscription/time_out_test.go b/pkg/subscription/time_out_test.go deleted file mode 100644 index 72968fb6c..000000000 --- a/pkg/subscription/time_out_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package subscription - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" -) - -func TestTimeOutChecker(t *testing.T) { - t.Run("should stop timer if context is done before", func(t *testing.T) { - timeOutActionExecuted := false - timeOutAction := func() { - timeOutActionExecuted = true - } - - timeOutCtx, timeOutCancel := context.WithCancel(context.Background()) - params := TimeOutParams{ - Name: "", - Logger: abstractlogger.Noop{}, - TimeOutContext: timeOutCtx, - TimeOutAction: timeOutAction, - TimeOutDuration: 100 * time.Millisecond, - } - go TimeOutChecker(params) - time.Sleep(5 * time.Millisecond) - timeOutCancel() - <-timeOutCtx.Done() - assert.False(t, timeOutActionExecuted) - }) - - t.Run("should stop process if timer runs out", func(t *testing.T) { - wg := &sync.WaitGroup{} - wg.Add(1) - - timeOutActionExecuted := false - timeOutAction := func() { - timeOutActionExecuted = true - wg.Done() - } - - timeOutCtx, timeOutCancel := context.WithCancel(context.Background()) - defer timeOutCancel() - - params := TimeOutParams{ - Name: "", - Logger: abstractlogger.Noop{}, - TimeOutContext: timeOutCtx, - TimeOutAction: timeOutAction, - TimeOutDuration: 10 * time.Millisecond, - } - go TimeOutChecker(params) - wg.Wait() - assert.True(t, timeOutActionExecuted) - }) -} diff --git a/pkg/subscription/transport_client.go b/pkg/subscription/transport_client.go deleted file mode 100644 index c5ce7b2ab..000000000 --- a/pkg/subscription/transport_client.go +++ /dev/null @@ -1,27 +0,0 @@ -package subscription - -import ( - "errors" -) - -//go:generate mockgen -destination=transport_client_mock_test.go -package=subscription . TransportClient - -// ErrTransportClientClosedConnection is an error to indicate that the transport client is using closed connection. -var ErrTransportClientClosedConnection = errors.New("transport client has a closed connection") - -// TransportClient provides an interface that can be implemented by any possible subscription client like websockets, mqtt, etc. -// It operates with raw byte slices. -type TransportClient interface { - // ReadBytesFromClient will invoke a read operation from the client connection and return a byte slice. - // This function should return ErrTransportClientClosedConnection when reading on a closed connection. - ReadBytesFromClient() ([]byte, error) - // WriteBytesToClient will invoke a write operation to the client connection using a byte slice. - // This function should return ErrTransportClientClosedConnection when writing on a closed connection. - WriteBytesToClient([]byte) error - // IsConnected will indicate if a connection is still established. - IsConnected() bool - // Disconnect will close the connection between server and client. - Disconnect() error - // DisconnectWithReason will close the connection but is also able to process a reason for closure. - DisconnectWithReason(reason interface{}) error -} diff --git a/pkg/subscription/transport_client_mock_test.go b/pkg/subscription/transport_client_mock_test.go deleted file mode 100644 index cf1b3850f..000000000 --- a/pkg/subscription/transport_client_mock_test.go +++ /dev/null @@ -1,105 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/wundergraph/graphql-go-tools/pkg/subscription (interfaces: TransportClient) - -// Package subscription is a generated GoMock package. -package subscription - -import ( - reflect "reflect" - - gomock "github.com/golang/mock/gomock" -) - -// MockTransportClient is a mock of TransportClient interface. -type MockTransportClient struct { - ctrl *gomock.Controller - recorder *MockTransportClientMockRecorder -} - -// MockTransportClientMockRecorder is the mock recorder for MockTransportClient. -type MockTransportClientMockRecorder struct { - mock *MockTransportClient -} - -// NewMockTransportClient creates a new mock instance. -func NewMockTransportClient(ctrl *gomock.Controller) *MockTransportClient { - mock := &MockTransportClient{ctrl: ctrl} - mock.recorder = &MockTransportClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockTransportClient) EXPECT() *MockTransportClientMockRecorder { - return m.recorder -} - -// Disconnect mocks base method. -func (m *MockTransportClient) Disconnect() error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Disconnect") - ret0, _ := ret[0].(error) - return ret0 -} - -// Disconnect indicates an expected call of Disconnect. -func (mr *MockTransportClientMockRecorder) Disconnect() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Disconnect", reflect.TypeOf((*MockTransportClient)(nil).Disconnect)) -} - -// DisconnectWithReason mocks base method. -func (m *MockTransportClient) DisconnectWithReason(arg0 interface{}) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DisconnectWithReason", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// DisconnectWithReason indicates an expected call of DisconnectWithReason. -func (mr *MockTransportClientMockRecorder) DisconnectWithReason(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisconnectWithReason", reflect.TypeOf((*MockTransportClient)(nil).DisconnectWithReason), arg0) -} - -// IsConnected mocks base method. -func (m *MockTransportClient) IsConnected() bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "IsConnected") - ret0, _ := ret[0].(bool) - return ret0 -} - -// IsConnected indicates an expected call of IsConnected. -func (mr *MockTransportClientMockRecorder) IsConnected() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsConnected", reflect.TypeOf((*MockTransportClient)(nil).IsConnected)) -} - -// ReadBytesFromClient mocks base method. -func (m *MockTransportClient) ReadBytesFromClient() ([]byte, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ReadBytesFromClient") - ret0, _ := ret[0].([]byte) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ReadBytesFromClient indicates an expected call of ReadBytesFromClient. -func (mr *MockTransportClientMockRecorder) ReadBytesFromClient() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadBytesFromClient", reflect.TypeOf((*MockTransportClient)(nil).ReadBytesFromClient)) -} - -// WriteBytesToClient mocks base method. -func (m *MockTransportClient) WriteBytesToClient(arg0 []byte) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WriteBytesToClient", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// WriteBytesToClient indicates an expected call of WriteBytesToClient. -func (mr *MockTransportClientMockRecorder) WriteBytesToClient(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WriteBytesToClient", reflect.TypeOf((*MockTransportClient)(nil).WriteBytesToClient), arg0) -} diff --git a/pkg/subscription/websocket/client.go b/pkg/subscription/websocket/client.go deleted file mode 100644 index 003eccdab..000000000 --- a/pkg/subscription/websocket/client.go +++ /dev/null @@ -1,187 +0,0 @@ -package websocket - -import ( - "errors" - "io" - "net" - "sync" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -// CloseReason is type that is used to provide a close reason to Client.DisconnectWithReason. -type CloseReason ws.Frame - -// CompiledCloseReason is a pre-compiled close reason to be provided to Client.DisconnectWithReason. -type CompiledCloseReason []byte - -var ( - CompiledCloseReasonNormal CompiledCloseReason = ws.MustCompileFrame( - ws.NewCloseFrame(ws.NewCloseFrameBody( - ws.StatusNormalClosure, "Normal Closure", - )), - ) - CompiledCloseReasonInternalServerError CompiledCloseReason = ws.MustCompileFrame( - ws.NewCloseFrame(ws.NewCloseFrameBody( - ws.StatusInternalServerError, "Internal Server Error", - )), - ) -) - -// NewCloseReason is used to compose a close frame with code and reason message. -func NewCloseReason(code uint16, reason string) CloseReason { - wsCloseFrame := ws.NewCloseFrame(ws.NewCloseFrameBody( - ws.StatusCode(code), reason, - )) - return CloseReason(wsCloseFrame) -} - -// Client is an actual implementation of the subscription client interface. -type Client struct { - logger abstractlogger.Logger - // clientConn holds the actual connection to the client. - clientConn net.Conn - // isClosedConnection indicates if the websocket connection is closed. - isClosedConnection bool - mu *sync.RWMutex -} - -// NewClient will create a new websocket subscription client. -func NewClient(logger abstractlogger.Logger, clientConn net.Conn) *Client { - return &Client{ - logger: logger, - clientConn: clientConn, - mu: &sync.RWMutex{}, - } -} - -// ReadBytesFromClient will read a subscription message from the websocket client. -func (c *Client) ReadBytesFromClient() ([]byte, error) { - if !c.IsConnected() { - return nil, subscription.ErrTransportClientClosedConnection - } - - data, opCode, err := wsutil.ReadClientData(c.clientConn) - if errors.Is(err, io.EOF) || errors.Is(err, io.ErrClosedPipe) || errors.Is(err, io.ErrUnexpectedEOF) { - c.changeConnectionStateToClosed() - return nil, subscription.ErrTransportClientClosedConnection - } else if err != nil { - if c.isClosedConnectionError(err) { - return nil, subscription.ErrTransportClientClosedConnection - } - - c.logger.Error("websocket.Client.ReadBytesFromClient: after reading from client", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - abstractlogger.Any("opCode", opCode), - ) - - c.isClosedConnectionError(err) - - return nil, err - } - - return data, nil -} - -// WriteBytesToClient will write a subscription message to the websocket client. -func (c *Client) WriteBytesToClient(message []byte) error { - if !c.IsConnected() { - return subscription.ErrTransportClientClosedConnection - } - - err := wsutil.WriteServerMessage(c.clientConn, ws.OpText, message) - if errors.Is(err, io.ErrClosedPipe) { - c.changeConnectionStateToClosed() - return subscription.ErrTransportClientClosedConnection - } else if err != nil { - c.logger.Error("websocket.Client.WriteBytesToClient: after writing to client", - abstractlogger.Error(err), - abstractlogger.ByteString("message", message), - ) - - return err - } - - return nil -} - -// IsConnected will indicate if the websocket connection is still established. -func (c *Client) IsConnected() bool { - c.mu.RLock() - defer c.mu.RUnlock() - return !c.isClosedConnection -} - -// Disconnect will close the websocket connection. -func (c *Client) Disconnect() error { - c.logger.Debug("websocket.Client.Disconnect: before disconnect", - abstractlogger.String("message", "disconnecting client"), - ) - c.changeConnectionStateToClosed() - return c.clientConn.Close() -} - -// DisconnectWithReason will close the websocket and provide the close code and reason. -// It can only consume CloseReason or CompiledCloseReason. -func (c *Client) DisconnectWithReason(reason interface{}) error { - var err error - switch reason := reason.(type) { - case CloseReason: - err = c.writeFrame(ws.Frame(reason)) - case CompiledCloseReason: - err = c.writeCompiledFrame(reason) - default: - c.logger.Error("websocket.Client.DisconnectWithReason: on reason/frame parsing", - abstractlogger.String("message", "unknown reason provided"), - ) - frame := NewCloseReason(4400, "unknown reason") - err = c.writeFrame(ws.Frame(frame)) - } - - c.logger.Debug("websocket.Client.DisconnectWithReason: before sending close frame", - abstractlogger.String("message", "disconnecting client"), - ) - - if err != nil { - c.logger.Error("websocket.Client.DisconnectWithReason: after writing close reason", - abstractlogger.Error(err), - ) - return err - } - - return c.Disconnect() -} - -func (c *Client) writeFrame(frame ws.Frame) error { - return ws.WriteFrame(c.clientConn, frame) -} - -func (c *Client) writeCompiledFrame(compiledFrame []byte) error { - _, err := c.clientConn.Write(compiledFrame) - return err -} - -// isClosedConnectionError will indicate if the given error is a connection closed error. -func (c *Client) isClosedConnectionError(err error) bool { - c.mu.Lock() - defer c.mu.Unlock() - var closedErr wsutil.ClosedError - if errors.As(err, &closedErr) { - c.isClosedConnection = true - } - return c.isClosedConnection -} - -func (c *Client) changeConnectionStateToClosed() { - c.mu.Lock() - defer c.mu.Unlock() - c.isClosedConnection = true -} - -// Interface Guard -var _ subscription.TransportClient = (*Client)(nil) diff --git a/pkg/subscription/websocket/client_test.go b/pkg/subscription/websocket/client_test.go deleted file mode 100644 index 85be6940e..000000000 --- a/pkg/subscription/websocket/client_test.go +++ /dev/null @@ -1,461 +0,0 @@ -package websocket - -import ( - "errors" - "fmt" - "io" - "net" - "sync" - "testing" - "time" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -type testServerWebsocketResponse struct { - data []byte - opCode ws.OpCode - statusCode ws.StatusCode - closeReason string - err error -} - -func TestClient_WriteToClient(t *testing.T) { - t.Run("should write successfully to client", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - messageToClient := []byte(`{ - "id": "1", - "type": "data", - "payload": {"data":null} - }`) - - go func() { - err := websocketClient.WriteBytesToClient(messageToClient) - assert.NoError(t, err) - }() - - data, opCode, err := wsutil.ReadServerData(connToServer) - require.NoError(t, err) - require.Equal(t, ws.OpText, opCode) - - time.Sleep(10 * time.Millisecond) - assert.Equal(t, messageToClient, data) - }) - - t.Run("should not write to client when connection is closed", func(t *testing.T) { - t.Run("when not wrapped", func(t *testing.T) { - t.Run("io: read/write on closed pipe", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - err := connToServer.Close() - require.NoError(t, err) - - err = websocketClient.WriteBytesToClient([]byte("")) - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - }) - - t.Run("when wrapped", func(t *testing.T) { - t.Run("io: read/write on closed pipe", func(t *testing.T) { - connToClient := FakeConn{} - wrappedErr := fmt.Errorf("outside wrapper: %w", - fmt.Errorf("inner wrapper: %w", - io.ErrClosedPipe, - ), - ) - connToClient.setWriteReturns(0, wrappedErr) - websocketClient := NewClient(abstractlogger.NoopLogger, &connToClient) - - err := websocketClient.WriteBytesToClient([]byte("message")) - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - }) - }) -} - -func TestClient_ReadFromClient(t *testing.T) { - t.Run("should successfully read from client", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - messageToServer := []byte(`{ - "id": "1", - "type": "data", - "payload": {"data":null} - }`) - - go func() { - err := wsutil.WriteClientText(connToServer, messageToServer) - require.NoError(t, err) - }() - - time.Sleep(10 * time.Millisecond) - - messageFromClient, err := websocketClient.ReadBytesFromClient() - assert.NoError(t, err) - assert.Equal(t, messageToServer, messageFromClient) - }) - t.Run("should detect a closed connection", func(t *testing.T) { - t.Run("before read", func(t *testing.T) { - _, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - defer connToClient.Close() - websocketClient.isClosedConnection = true - - assert.Eventually(t, func() bool { - _, err := websocketClient.ReadBytesFromClient() - return assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - }, 1*time.Second, 2*time.Millisecond) - }) - t.Run("when not wrapped", func(t *testing.T) { - t.Run("io.EOF", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - err := connToServer.Close() - require.NoError(t, err) - - _, err = websocketClient.ReadBytesFromClient() - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - t.Run("io: read/write on closed pipe", func(t *testing.T) { - connToClient := &FakeConn{} - connToClient.setReadReturns(0, io.ErrClosedPipe) - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - _, err := websocketClient.ReadBytesFromClient() - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - t.Run("unexpected EOF", func(t *testing.T) { - connToClient := &FakeConn{} - connToClient.setReadReturns(0, io.ErrUnexpectedEOF) - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - _, err := websocketClient.ReadBytesFromClient() - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - }) - - t.Run("when wrapped", func(t *testing.T) { - t.Run("io.EOF", func(t *testing.T) { - connToClient := &FakeConn{} - wrappedErr := fmt.Errorf("outside wrapper: %w", - fmt.Errorf("inner wrapper: %w", - io.EOF, - ), - ) - connToClient.setReadReturns(0, wrappedErr) - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - _, err := websocketClient.ReadBytesFromClient() - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - t.Run("io: read/write on closed pipe", func(t *testing.T) { - connToClient := &FakeConn{} - wrappedErr := fmt.Errorf("outside wrapper: %w", - fmt.Errorf("inner wrapper: %w", - io.ErrClosedPipe, - ), - ) - connToClient.setReadReturns(0, wrappedErr) - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - _, err := websocketClient.ReadBytesFromClient() - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - t.Run("unexpected EOF", func(t *testing.T) { - connToClient := &FakeConn{} - wrappedErr := fmt.Errorf("outside wrapper: %w", - fmt.Errorf("inner wrapper: %w", - io.ErrUnexpectedEOF, - ), - ) - connToClient.setReadReturns(0, wrappedErr) - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - _, err := websocketClient.ReadBytesFromClient() - assert.Equal(t, subscription.ErrTransportClientClosedConnection, err) - assert.True(t, websocketClient.isClosedConnection) - }) - }) - - }) -} - -func TestClient_IsConnected(t *testing.T) { - _, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - t.Run("should return true when a connection is established", func(t *testing.T) { - isConnected := websocketClient.IsConnected() - assert.True(t, isConnected) - }) - - t.Run("should return false when a connection is closed", func(t *testing.T) { - err := connToClient.Close() - require.NoError(t, err) - - websocketClient.isClosedConnection = true - - isConnected := websocketClient.IsConnected() - assert.False(t, isConnected) - }) -} - -func TestClient_Disconnect(t *testing.T) { - _, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - - t.Run("should disconnect and indicate a closed connection", func(t *testing.T) { - err := websocketClient.Disconnect() - assert.NoError(t, err) - assert.Equal(t, true, websocketClient.isClosedConnection) - }) -} - -func TestClient_DisconnectWithReason(t *testing.T) { - t.Run("disconnect with invalid reason", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - serverResponseChan := make(chan testServerWebsocketResponse) - - go readServerResponse(serverResponseChan, connToServer) - - go func() { - err := websocketClient.DisconnectWithReason( - "invalid reason", - ) - assert.NoError(t, err) - }() - - assert.Eventually(t, func() bool { - actualServerResult := <-serverResponseChan - assert.NoError(t, actualServerResult.err) - assert.Equal(t, ws.OpClose, actualServerResult.opCode) - assert.Equal(t, ws.StatusCode(4400), actualServerResult.statusCode) - assert.Equal(t, "unknown reason", actualServerResult.closeReason) - assert.Equal(t, false, websocketClient.IsConnected()) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - - t.Run("disconnect with reason", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - serverResponseChan := make(chan testServerWebsocketResponse) - - go readServerResponse(serverResponseChan, connToServer) - - go func() { - err := websocketClient.DisconnectWithReason( - NewCloseReason(4400, "error occurred"), - ) - assert.NoError(t, err) - }() - - assert.Eventually(t, func() bool { - actualServerResult := <-serverResponseChan - assert.NoError(t, actualServerResult.err) - assert.Equal(t, ws.OpClose, actualServerResult.opCode) - assert.Equal(t, ws.StatusCode(4400), actualServerResult.statusCode) - assert.Equal(t, "error occurred", actualServerResult.closeReason) - assert.Equal(t, false, websocketClient.IsConnected()) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - - t.Run("disconnect with compiled reason", func(t *testing.T) { - connToServer, connToClient := net.Pipe() - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - serverResponseChan := make(chan testServerWebsocketResponse) - - go readServerResponse(serverResponseChan, connToServer) - - go func() { - err := websocketClient.DisconnectWithReason( - CompiledCloseReasonNormal, - ) - assert.NoError(t, err) - }() - - assert.Eventually(t, func() bool { - actualServerResult := <-serverResponseChan - assert.NoError(t, actualServerResult.err) - assert.Equal(t, ws.OpClose, actualServerResult.opCode) - assert.Equal(t, ws.StatusCode(1000), actualServerResult.statusCode) - assert.Equal(t, "Normal Closure", actualServerResult.closeReason) - assert.Equal(t, false, websocketClient.IsConnected()) - return true - }, 1*time.Second, 2*time.Millisecond) - }) -} - -func TestClient_isClosedConnectionError(t *testing.T) { - _, connToClient := net.Pipe() - - t.Run("should not close connection when it is not a closed connection error", func(t *testing.T) { - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - require.False(t, websocketClient.isClosedConnection) - - isClosedConnectionError := websocketClient.isClosedConnectionError(errors.New("no closed connection err")) - assert.False(t, isClosedConnectionError) - }) - - t.Run("should close connection when it is a closed connection error", func(t *testing.T) { - websocketClient := NewClient(abstractlogger.NoopLogger, connToClient) - require.False(t, websocketClient.isClosedConnection) - - isClosedConnectionError := websocketClient.isClosedConnectionError(wsutil.ClosedError{}) - assert.True(t, isClosedConnectionError) - websocketClient.isClosedConnection = false - - require.False(t, websocketClient.isClosedConnection) - isClosedConnectionError = websocketClient.isClosedConnectionError(wsutil.ClosedError{ - Code: ws.StatusNormalClosure, - Reason: "Normal Closure", - }) - assert.True(t, isClosedConnectionError) - }) -} - -type TestClient struct { - connectionMutex *sync.RWMutex - messageFromClient chan []byte - messageToClient chan []byte - isConnected bool - shouldFail bool -} - -func NewTestClient(shouldFail bool) *TestClient { - return &TestClient{ - connectionMutex: &sync.RWMutex{}, - messageFromClient: make(chan []byte, 1), - messageToClient: make(chan []byte, 1), - isConnected: true, - shouldFail: shouldFail, - } -} - -func (t *TestClient) ReadBytesFromClient() ([]byte, error) { - if t.shouldFail { - return nil, errors.New("shouldFail is true") - } - return <-t.messageFromClient, nil -} - -func (t *TestClient) WriteBytesToClient(message []byte) error { - if t.shouldFail { - return errors.New("shouldFail is true") - } - t.messageToClient <- message - return nil -} - -func (t *TestClient) IsConnected() bool { - t.connectionMutex.RLock() - defer t.connectionMutex.RUnlock() - return t.isConnected -} - -func (t *TestClient) Disconnect() error { - t.connectionMutex.Lock() - defer t.connectionMutex.Unlock() - t.isConnected = false - return nil -} - -func (t *TestClient) DisconnectWithReason(reason interface{}) error { - t.connectionMutex.Lock() - defer t.connectionMutex.Unlock() - t.isConnected = false - return nil -} - -func (t *TestClient) readMessageToClient() []byte { - return <-t.messageToClient -} - -func (t *TestClient) writeMessageFromClient(message []byte) { - t.messageFromClient <- message -} - -type FakeConn struct { - readReturnN int - readReturnErr error - writeReturnN int - writeReturnErr error -} - -func (f *FakeConn) setReadReturns(n int, err error) { - f.readReturnN = n - f.readReturnErr = err -} - -func (f *FakeConn) Read(b []byte) (n int, err error) { - return f.readReturnN, f.readReturnErr -} - -func (f *FakeConn) setWriteReturns(n int, err error) { - f.writeReturnN = n - f.writeReturnErr = err -} - -func (f *FakeConn) Write(b []byte) (n int, err error) { - return f.writeReturnN, f.writeReturnErr -} - -func (f *FakeConn) Close() error { - panic("implement me") -} - -func (f *FakeConn) LocalAddr() net.Addr { - panic("implement me") -} - -func (f *FakeConn) RemoteAddr() net.Addr { - panic("implement me") -} - -func (f *FakeConn) SetDeadline(t time.Time) error { - panic("implement me") -} - -func (f *FakeConn) SetReadDeadline(t time.Time) error { - panic("implement me") -} - -func (f *FakeConn) SetWriteDeadline(t time.Time) error { - panic("implement me") -} - -func readServerResponse(responseChan chan testServerWebsocketResponse, connToServer net.Conn) { - var statusCode ws.StatusCode - var closeReason string - frame, err := ws.ReadFrame(connToServer) - if err == nil { - statusCode, closeReason = ws.ParseCloseFrameData(frame.Payload) - } - - response := testServerWebsocketResponse{ - data: frame.Payload, - opCode: frame.Header.OpCode, - statusCode: statusCode, - closeReason: closeReason, - err: err, - } - - responseChan <- response -} diff --git a/pkg/subscription/websocket/engine_mock_test.go b/pkg/subscription/websocket/engine_mock_test.go deleted file mode 100644 index da14ffc45..000000000 --- a/pkg/subscription/websocket/engine_mock_test.go +++ /dev/null @@ -1,78 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/wundergraph/graphql-go-tools/pkg/subscription (interfaces: Engine) - -// Package websocket is a generated GoMock package. -package websocket - -import ( - context "context" - reflect "reflect" - - gomock "github.com/golang/mock/gomock" - subscription "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -// MockEngine is a mock of Engine interface. -type MockEngine struct { - ctrl *gomock.Controller - recorder *MockEngineMockRecorder -} - -// MockEngineMockRecorder is the mock recorder for MockEngine. -type MockEngineMockRecorder struct { - mock *MockEngine -} - -// NewMockEngine creates a new mock instance. -func NewMockEngine(ctrl *gomock.Controller) *MockEngine { - mock := &MockEngine{ctrl: ctrl} - mock.recorder = &MockEngineMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockEngine) EXPECT() *MockEngineMockRecorder { - return m.recorder -} - -// StartOperation mocks base method. -func (m *MockEngine) StartOperation(arg0 context.Context, arg1 string, arg2 []byte, arg3 subscription.EventHandler) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartOperation", arg0, arg1, arg2, arg3) - ret0, _ := ret[0].(error) - return ret0 -} - -// StartOperation indicates an expected call of StartOperation. -func (mr *MockEngineMockRecorder) StartOperation(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartOperation", reflect.TypeOf((*MockEngine)(nil).StartOperation), arg0, arg1, arg2, arg3) -} - -// StopSubscription mocks base method. -func (m *MockEngine) StopSubscription(arg0 string, arg1 subscription.EventHandler) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StopSubscription", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// StopSubscription indicates an expected call of StopSubscription. -func (mr *MockEngineMockRecorder) StopSubscription(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopSubscription", reflect.TypeOf((*MockEngine)(nil).StopSubscription), arg0, arg1) -} - -// TerminateAllSubscriptions mocks base method. -func (m *MockEngine) TerminateAllSubscriptions(arg0 subscription.EventHandler) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "TerminateAllSubscriptions", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// TerminateAllSubscriptions indicates an expected call of TerminateAllSubscriptions. -func (mr *MockEngineMockRecorder) TerminateAllSubscriptions(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TerminateAllSubscriptions", reflect.TypeOf((*MockEngine)(nil).TerminateAllSubscriptions), arg0) -} diff --git a/pkg/subscription/websocket/handler.go b/pkg/subscription/websocket/handler.go deleted file mode 100644 index 226b8753e..000000000 --- a/pkg/subscription/websocket/handler.go +++ /dev/null @@ -1,228 +0,0 @@ -package websocket - -import ( - "context" - "net" - "net/http" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -const ( - DefaultConnectionInitTimeOut = "15s" - - HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol" -) - -// Protocol defines the protocol names as type. -type Protocol string - -const ( - ProtocolUndefined Protocol = "" - ProtocolGraphQLWS Protocol = "graphql-ws" - ProtocolGraphQLTransportWS Protocol = "graphql-transport-ws" -) - -var DefaultProtocol = ProtocolGraphQLTransportWS - -// HandleOptions can be used to pass options to the websocket handler. -type HandleOptions struct { - Logger abstractlogger.Logger - Protocol Protocol - WebSocketInitFunc InitFunc - CustomClient subscription.TransportClient - CustomKeepAliveInterval time.Duration - CustomSubscriptionUpdateInterval time.Duration - CustomConnectionInitTimeOut time.Duration - CustomReadErrorTimeOut time.Duration - CustomSubscriptionEngine subscription.Engine -} - -// HandleOptionFunc can be used to define option functions. -type HandleOptionFunc func(opts *HandleOptions) - -// WithLogger is a function that sets a logger for the websocket handler. -func WithLogger(logger abstractlogger.Logger) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.Logger = logger - } -} - -// WithInitFunc is a function that sets the init function for the websocket handler. -func WithInitFunc(initFunc InitFunc) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.WebSocketInitFunc = initFunc - } -} - -// WithCustomClient is a function that set a custom transport client for the websocket handler. -func WithCustomClient(client subscription.TransportClient) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.CustomClient = client - } -} - -// WithCustomKeepAliveInterval is a function that sets a custom keep-alive interval for the websocket handler. -func WithCustomKeepAliveInterval(keepAliveInterval time.Duration) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.CustomKeepAliveInterval = keepAliveInterval - } -} - -// WithCustomSubscriptionUpdateInterval is a function that sets a custom subscription update interval for the -// websocket handler. -func WithCustomSubscriptionUpdateInterval(subscriptionUpdateInterval time.Duration) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.CustomSubscriptionUpdateInterval = subscriptionUpdateInterval - } -} - -// WithCustomConnectionInitTimeOut is a function that sets a custom connection init time out. -func WithCustomConnectionInitTimeOut(connectionInitTimeOut time.Duration) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.CustomConnectionInitTimeOut = connectionInitTimeOut - } -} - -// WithCustomReadErrorTimeOut is a function that sets a custom read error time out for the -// websocket handler. -func WithCustomReadErrorTimeOut(readErrorTimeOut time.Duration) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.CustomReadErrorTimeOut = readErrorTimeOut - } -} - -// WithCustomSubscriptionEngine is a function that sets a custom subscription engine for the websocket handler. -func WithCustomSubscriptionEngine(subscriptionEngine subscription.Engine) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.CustomSubscriptionEngine = subscriptionEngine - } -} - -// WithProtocol is a function that sets the protocol. -func WithProtocol(protocol Protocol) HandleOptionFunc { - return func(opts *HandleOptions) { - opts.Protocol = protocol - } -} - -// WithProtocolFromRequestHeaders is a function that sets the protocol based on the request headers. -// It fallbacks to the DefaultProtocol if the header can't be found, the value is invalid or no request -// was provided. -func WithProtocolFromRequestHeaders(req *http.Request) HandleOptionFunc { - return func(opts *HandleOptions) { - if req == nil { - opts.Protocol = DefaultProtocol - return - } - - protocolHeaderValue := req.Header.Get(HeaderSecWebSocketProtocol) - switch Protocol(protocolHeaderValue) { - case ProtocolGraphQLWS: - opts.Protocol = ProtocolGraphQLWS - case ProtocolGraphQLTransportWS: - opts.Protocol = ProtocolGraphQLTransportWS - default: - opts.Protocol = DefaultProtocol - } - } -} - -// Handle will handle the websocket subscription. It can take optional option functions to customize the handler. -// behavior. By default, it uses the 'graphql-transport-ws' protocol. -func Handle(done chan bool, errChan chan error, conn net.Conn, executorPool subscription.ExecutorPool, options ...HandleOptionFunc) { - definedOptions := HandleOptions{ - Logger: abstractlogger.Noop{}, - Protocol: DefaultProtocol, - } - - for _, optionFunc := range options { - optionFunc(&definedOptions) - } - - HandleWithOptions(done, errChan, conn, executorPool, definedOptions) -} - -// HandleWithOptions will handle the websocket connection. It requires an option struct to define the behavior. -func HandleWithOptions(done chan bool, errChan chan error, conn net.Conn, executorPool subscription.ExecutorPool, options HandleOptions) { - // Use noop logger to prevent nil pointers if none was provided - if options.Logger == nil { - options.Logger = abstractlogger.Noop{} - } - - defer func() { - if err := conn.Close(); err != nil { - options.Logger.Error("websocket.HandleWithOptions: on deferred closing connection", - abstractlogger.String("message", "could not close connection to client"), - abstractlogger.Error(err), - ) - } - }() - - var client subscription.TransportClient - if options.CustomClient != nil { - client = options.CustomClient - } else { - client = NewClient(options.Logger, conn) - } - - protocolHandler, err := createProtocolHandler(options, client) - if err != nil { - options.Logger.Error("websocket.HandleWithOptions: on protocol handler creation", - abstractlogger.String("message", "could not create protocol handler"), - abstractlogger.String("protocol", string(DefaultProtocol)), - abstractlogger.Error(err), - ) - - errChan <- err - return - } - - subscriptionHandler, err := subscription.NewUniversalProtocolHandlerWithOptions(client, protocolHandler, executorPool, subscription.UniversalProtocolHandlerOptions{ - Logger: options.Logger, - CustomSubscriptionUpdateInterval: options.CustomSubscriptionUpdateInterval, - CustomReadErrorTimeOut: options.CustomReadErrorTimeOut, - CustomEngine: options.CustomSubscriptionEngine, - }) - if err != nil { - options.Logger.Error("websocket.HandleWithOptions: on subscription handler creation", - abstractlogger.String("message", "could not create subscription handler"), - abstractlogger.String("protocol", string(DefaultProtocol)), - abstractlogger.Error(err), - ) - - errChan <- err - return - } - - close(done) - subscriptionHandler.Handle(context.Background()) // Blocking -} - -func createProtocolHandler(handleOptions HandleOptions, client subscription.TransportClient) (protocolHandler subscription.Protocol, err error) { - protocol := handleOptions.Protocol - if protocol == ProtocolUndefined { - protocol = DefaultProtocol - } - - switch protocol { - case ProtocolGraphQLWS: - protocolHandler, err = NewProtocolGraphQLWSHandlerWithOptions(client, ProtocolGraphQLWSHandlerOptions{ - Logger: handleOptions.Logger, - WebSocketInitFunc: handleOptions.WebSocketInitFunc, - CustomKeepAliveInterval: handleOptions.CustomKeepAliveInterval, - }) - default: - protocolHandler, err = NewProtocolGraphQLTransportWSHandlerWithOptions(client, ProtocolGraphQLTransportWSHandlerOptions{ - Logger: handleOptions.Logger, - WebSocketInitFunc: handleOptions.WebSocketInitFunc, - CustomKeepAliveInterval: handleOptions.CustomKeepAliveInterval, - CustomInitTimeOutDuration: handleOptions.CustomConnectionInitTimeOut, - }) - } - - return protocolHandler, err -} diff --git a/pkg/subscription/websocket/handler_test.go b/pkg/subscription/websocket/handler_test.go deleted file mode 100644 index cc4fc8a84..000000000 --- a/pkg/subscription/websocket/handler_test.go +++ /dev/null @@ -1,344 +0,0 @@ -package websocket - -import ( - "bytes" - "context" - "errors" - "net" - "net/http" - "net/http/httptest" - "testing" - "time" - - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/httpclient" - "github.com/wundergraph/graphql-go-tools/pkg/engine/plan" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" - "github.com/wundergraph/graphql-go-tools/pkg/testing/subscriptiontesting" -) - -func TestHandleWithOptions(t *testing.T) { - t.Run("should handle protocol graphql-ws", func(t *testing.T) { - chatServer := httptest.NewServer(subscriptiontesting.ChatGraphQLEndpointHandler()) - defer chatServer.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - executorPoolV2 := setupExecutorPoolV2(t, ctx, chatServer.URL, nil) - serverConn, _ := net.Pipe() - testClient := NewTestClient(false) - - done := make(chan bool) - errChan := make(chan error) - go Handle( - done, - errChan, - serverConn, - executorPoolV2, - WithProtocol(ProtocolGraphQLWS), - WithCustomClient(testClient), - WithCustomSubscriptionUpdateInterval(50*time.Millisecond), - WithCustomKeepAliveInterval(3600*time.Second), // keep_alive should not intervene with our tests, so make it high - ) - - require.Eventually(t, func() bool { - <-done - return true - }, 1*time.Second, 2*time.Millisecond) - - testClient.writeMessageFromClient([]byte(`{"type":"connection_init"}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"type":"connection_ack"}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 1*time.Second, 2*time.Millisecond, "never satisfied on connection_init") - - testClient.writeMessageFromClient([]byte(`{"id":"1","type":"start","payload":{"query":"{ room(name:\"#my_room\") { name } }"}}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"id":"1","type":"data","payload":{"data":{"room":{"name":"#my_room"}}}}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - expectedMessage = []byte(`{"id":"1","type":"complete"}`) - actualMessage = testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on start non-subscription") - - testClient.writeMessageFromClient([]byte(`{"id":"2","type":"start","payload":{"query":"subscription { messageAdded(roomName:\"#my_room\") { text } }"}}`)) - time.Sleep(15 * time.Millisecond) - testClient.writeMessageFromClient([]byte(`{"id":"3","type":"start","payload":{"query":"mutation { post(text: \"hello\", username: \"me\", roomName: \"#my_room\") { text } }"}}`)) - assert.Eventually(t, func() bool { - expectedMessages := []string{ - `{"id":"3","type":"data","payload":{"data":{"post":{"text":"hello"}}}}`, - `{"id":"3","type":"complete"}`, - `{"id":"2","type":"data","payload":{"data":{"messageAdded":{"text":"hello"}}}}`, - } - actualMessage := testClient.readMessageToClient() - assert.Contains(t, expectedMessages, string(actualMessage)) - actualMessage = testClient.readMessageToClient() - assert.Contains(t, expectedMessages, string(actualMessage)) - actualMessage = testClient.readMessageToClient() - assert.Contains(t, expectedMessages, string(actualMessage)) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on start subscription") - - testClient.writeMessageFromClient([]byte(`{"id":"2","type":"stop"}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"id":"2","type":"complete"}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on stop subscription") - }) - - t.Run("should handle protocol graphql-transport-ws", func(t *testing.T) { - chatServer := httptest.NewServer(subscriptiontesting.ChatGraphQLEndpointHandler()) - defer chatServer.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - executorPoolV2 := setupExecutorPoolV2(t, ctx, chatServer.URL, nil) - serverConn, _ := net.Pipe() - testClient := NewTestClient(false) - - done := make(chan bool) - errChan := make(chan error) - go Handle( - done, - errChan, - serverConn, - executorPoolV2, - WithProtocol(ProtocolGraphQLTransportWS), - WithCustomClient(testClient), - WithCustomSubscriptionUpdateInterval(50*time.Millisecond), - WithCustomKeepAliveInterval(3600*time.Second), // keep_alive should not intervene with our tests, so make it high - ) - - require.Eventually(t, func() bool { - <-done - return true - }, 1*time.Second, 2*time.Millisecond) - - testClient.writeMessageFromClient([]byte(`{"type":"connection_init"}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"type":"connection_ack"}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 1*time.Second, 2*time.Millisecond, "never satisfied on connection_init") - - testClient.writeMessageFromClient([]byte(`{"id":"1","type":"subscribe","payload":{"query":"{ room(name:\"#my_room\") { name } }"}}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"id":"1","type":"next","payload":{"data":{"room":{"name":"#my_room"}}}}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - expectedMessage = []byte(`{"id":"1","type":"complete"}`) - actualMessage = testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on start non-subscription") - - testClient.writeMessageFromClient([]byte(`{"id":"2","type":"subscribe","payload":{"query":"subscription { messageAdded(roomName:\"#my_room\") { text } }"}}`)) - time.Sleep(15 * time.Millisecond) - testClient.writeMessageFromClient([]byte(`{"id":"3","type":"subscribe","payload":{"query":"mutation { post(text: \"hello\", username: \"me\", roomName: \"#my_room\") { text } }"}}`)) - assert.Eventually(t, func() bool { - expectedMessages := []string{ - `{"id":"3","type":"next","payload":{"data":{"post":{"text":"hello"}}}}`, - `{"id":"3","type":"complete"}`, - `{"id":"2","type":"next","payload":{"data":{"messageAdded":{"text":"hello"}}}}`, - } - actualMessage := testClient.readMessageToClient() - assert.Contains(t, expectedMessages, string(actualMessage)) - actualMessage = testClient.readMessageToClient() - assert.Contains(t, expectedMessages, string(actualMessage)) - actualMessage = testClient.readMessageToClient() - assert.Contains(t, expectedMessages, string(actualMessage)) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on start subscription") - - testClient.writeMessageFromClient([]byte(`{"id":"2","type":"complete"}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"id":"2","type":"complete"}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on stop subscription") - }) - - t.Run("should handle on before start error", func(t *testing.T) { - chatServer := httptest.NewServer(subscriptiontesting.ChatGraphQLEndpointHandler()) - defer chatServer.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - executorPoolV2 := setupExecutorPoolV2(t, ctx, chatServer.URL, &FailingOnBeforeStartHook{}) - serverConn, _ := net.Pipe() - testClient := NewTestClient(false) - - done := make(chan bool) - errChan := make(chan error) - go Handle( - done, - errChan, - serverConn, - executorPoolV2, - WithProtocol(ProtocolGraphQLTransportWS), - WithCustomClient(testClient), - WithCustomSubscriptionUpdateInterval(50*time.Millisecond), - WithCustomKeepAliveInterval(3600*time.Second), // keep_alive should not intervene with our tests, so make it high - ) - - require.Eventually(t, func() bool { - <-done - return true - }, 1*time.Second, 2*time.Millisecond) - - testClient.writeMessageFromClient([]byte(`{"type":"connection_init"}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"type":"connection_ack"}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 1*time.Second, 2*time.Millisecond, "never satisfied on connection_init") - - testClient.writeMessageFromClient([]byte(`{"id":"1","type":"subscribe","payload":{"query":"{ room(name:\"#my_room\") { name } }"}}`)) - assert.Eventually(t, func() bool { - expectedMessage := []byte(`{"id":"1","type":"error","payload":[{"message":"on before start error"}]}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - return true - }, 2*time.Second, 2*time.Millisecond, "never satisfied on before start error") - }) -} - -func TestWithProtocolFromRequestHeaders(t *testing.T) { - runTest := func(headerKey string, headerValue string, expectedProtocol Protocol) func(t *testing.T) { - return func(t *testing.T) { - request, err := http.NewRequest("", "", nil) - require.NoError(t, err) - request.Header.Set(headerKey, headerValue) - - options := &HandleOptions{} - optionFunc := WithProtocolFromRequestHeaders(request) - optionFunc(options) - - assert.Equal(t, expectedProtocol, options.Protocol) - } - } - - t.Run("should detect graphql-ws", runTest(HeaderSecWebSocketProtocol, "graphql-ws", ProtocolGraphQLWS)) - t.Run("should detect graphql-transport-ws", runTest(HeaderSecWebSocketProtocol, "graphql-transport-ws", ProtocolGraphQLTransportWS)) - t.Run("should fallback to default protocol", runTest(HeaderSecWebSocketProtocol, "something-else", DefaultProtocol)) - t.Run("should fallback to default protocol when header is missing", runTest("Different-Header-Key", "missing-header", DefaultProtocol)) - t.Run("should fallback to default protocol when request is nil", func(t *testing.T) { - options := &HandleOptions{} - optionFunc := WithProtocolFromRequestHeaders(nil) - optionFunc(options) - assert.Equal(t, DefaultProtocol, options.Protocol) - }) -} - -func setupExecutorPoolV2(t *testing.T, ctx context.Context, chatServerURL string, onBeforeStartHook graphql.WebsocketBeforeStartHook) *subscription.ExecutorV2Pool { - chatSchemaBytes, err := subscriptiontesting.LoadSchemaFromExamplesDirectoryWithinPkg() - require.NoError(t, err) - - chatSchema, err := graphql.NewSchemaFromReader(bytes.NewBuffer(chatSchemaBytes)) - require.NoError(t, err) - - engineConf := graphql.NewEngineV2Configuration(chatSchema) - engineConf.SetWebsocketBeforeStartHook(onBeforeStartHook) - engineConf.SetDataSources([]plan.DataSourceConfiguration{ - { - RootNodes: []plan.TypeField{ - {TypeName: "Query", FieldNames: []string{"room"}}, - {TypeName: "Mutation", FieldNames: []string{"post"}}, - {TypeName: "Subscription", FieldNames: []string{"messageAdded"}}, - }, - ChildNodes: []plan.TypeField{ - {TypeName: "Chatroom", FieldNames: []string{"name", "messages"}}, - {TypeName: "Message", FieldNames: []string{"text", "createdBy"}}, - }, - Factory: &graphql_datasource.Factory{ - HTTPClient: httpclient.DefaultNetHttpClient, - }, - Custom: graphql_datasource.ConfigJson(graphql_datasource.Configuration{ - Fetch: graphql_datasource.FetchConfiguration{ - URL: chatServerURL, - Method: http.MethodPost, - Header: nil, - }, - Subscription: graphql_datasource.SubscriptionConfiguration{ - URL: chatServerURL, - }, - }), - }, - }) - engineConf.SetFieldConfigurations([]plan.FieldConfiguration{ - { - TypeName: "Query", - FieldName: "room", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "name", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Mutation", - FieldName: "post", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "roomName", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "username", - SourceType: plan.FieldArgumentSource, - }, - { - Name: "text", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - { - TypeName: "Subscription", - FieldName: "messageAdded", - Arguments: []plan.ArgumentConfiguration{ - { - Name: "roomName", - SourceType: plan.FieldArgumentSource, - }, - }, - }, - }) - - req, err := http.NewRequestWithContext(ctx, http.MethodPost, "http://localhost:8080", nil) - require.NoError(t, err) - - req.Header.Set("X-Other-Key", "x-other-value") - - initCtx := subscription.NewInitialHttpRequestContext(req) - - engine, err := graphql.NewExecutionEngineV2(initCtx, abstractlogger.NoopLogger, engineConf) - require.NoError(t, err) - - executorPool := subscription.NewExecutorV2Pool(engine, ctx) - return executorPool -} - -type FailingOnBeforeStartHook struct{} - -func (f *FailingOnBeforeStartHook) OnBeforeStart(reqCtx context.Context, operation *graphql.Request) error { - return errors.New("on before start error") -} diff --git a/pkg/subscription/websocket/init.go b/pkg/subscription/websocket/init.go deleted file mode 100644 index 224695479..000000000 --- a/pkg/subscription/websocket/init.go +++ /dev/null @@ -1,47 +0,0 @@ -package websocket - -import ( - "context" - "encoding/json" -) - -// InitFunc is called when the server receives connection init message from the client. -// This can be used to check initial payload to see whether to accept the websocket connection. -type InitFunc func(ctx context.Context, initPayload InitPayload) (context.Context, error) - -// InitPayload is a structure that is parsed from the websocket init message payload. -type InitPayload json.RawMessage - -// GetString safely gets a string value from the payload. It returns an empty string if the -// payload is nil or the value isn't set. -func (p InitPayload) GetString(key string) string { - if p == nil { - return "" - } - - var payload map[string]interface{} - if err := json.Unmarshal(p, &payload); err != nil { - return "" - } - - if value, ok := payload[key]; ok { - res, _ := value.(string) - return res - } - - return "" -} - -// Authorization is a shorthand for getting the Authorization header from the -// payload. -func (p InitPayload) Authorization() string { - if value := p.GetString("Authorization"); value != "" { - return value - } - - if value := p.GetString("authorization"); value != "" { - return value - } - - return "" -} diff --git a/pkg/subscription/websocket/protocol_graphql_transport_ws.go b/pkg/subscription/websocket/protocol_graphql_transport_ws.go deleted file mode 100644 index 7ecc17b56..000000000 --- a/pkg/subscription/websocket/protocol_graphql_transport_ws.go +++ /dev/null @@ -1,524 +0,0 @@ -package websocket - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "sync" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -// GraphQLTransportWSMessageType is a type that defines graphql-transport-ws message type names. -type GraphQLTransportWSMessageType string - -const ( - GraphQLTransportWSMessageTypeConnectionInit GraphQLTransportWSMessageType = "connection_init" - GraphQLTransportWSMessageTypeConnectionAck GraphQLTransportWSMessageType = "connection_ack" - GraphQLTransportWSMessageTypePing GraphQLTransportWSMessageType = "ping" - GraphQLTransportWSMessageTypePong GraphQLTransportWSMessageType = "pong" - GraphQLTransportWSMessageTypeSubscribe GraphQLTransportWSMessageType = "subscribe" - GraphQLTransportWSMessageTypeNext GraphQLTransportWSMessageType = "next" - GraphQLTransportWSMessageTypeError GraphQLTransportWSMessageType = "error" - GraphQLTransportWSMessageTypeComplete GraphQLTransportWSMessageType = "complete" -) - -const ( - GraphQLTransportWSHeartbeatPayload = `{"type":"heartbeat"}` -) - -// GraphQLTransportWSMessage is a struct that can be (de)serialized to graphql-transport-ws message format. -type GraphQLTransportWSMessage struct { - Id string `json:"id,omitempty"` - Type GraphQLTransportWSMessageType `json:"type"` - Payload json.RawMessage `json:"payload,omitempty"` -} - -// GraphQLTransportWSMessageSubscribePayload is a struct that can be (de)serialized to graphql-transport-ws message payload format. -type GraphQLTransportWSMessageSubscribePayload struct { - OperationName string `json:"operationName,omitempty"` - Query string `json:"query"` - Variables json.RawMessage `json:"variables,omitempty"` - Extensions json.RawMessage `json:"extensions,omitempty"` -} - -// GraphQLTransportWSMessageReader can be used to read graphql-transport-ws messages. -type GraphQLTransportWSMessageReader struct { - logger abstractlogger.Logger -} - -// Read deserializes a byte slice to the GraphQLTransportWSMessage struct. -func (g *GraphQLTransportWSMessageReader) Read(data []byte) (*GraphQLTransportWSMessage, error) { - var message GraphQLTransportWSMessage - err := json.Unmarshal(data, &message) - if err != nil { - g.logger.Error("websocket.GraphQLTransportWSMessageReader.Read: on json unmarshal", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - ) - - return nil, err - } - return &message, nil -} - -// DeserializeSubscribePayload deserialized the subscribe payload from a graphql-transport-ws message. -func (g *GraphQLTransportWSMessageReader) DeserializeSubscribePayload(message *GraphQLTransportWSMessage) (*GraphQLTransportWSMessageSubscribePayload, error) { - var deserializedPayload GraphQLTransportWSMessageSubscribePayload - err := json.Unmarshal(message.Payload, &deserializedPayload) - if err != nil { - g.logger.Error("websocket.GraphQLTransportWSMessageReader.DeserializeSubscribePayload: on subscribe payload deserialization", - abstractlogger.Error(err), - abstractlogger.ByteString("payload", message.Payload), - ) - return nil, err - } - - return &deserializedPayload, nil -} - -// GraphQLTransportWSMessageWriter can be used to write graphql-transport-ws messages to a transport client. -type GraphQLTransportWSMessageWriter struct { - logger abstractlogger.Logger - mu *sync.Mutex - Client subscription.TransportClient -} - -// WriteConnectionAck writes a message of type 'connection_ack' to the transport client. -func (g *GraphQLTransportWSMessageWriter) WriteConnectionAck() error { - message := &GraphQLTransportWSMessage{ - Type: GraphQLTransportWSMessageTypeConnectionAck, - } - return g.write(message) -} - -// WritePing writes a message of type 'ping' to the transport client. Payload is optional. -func (g *GraphQLTransportWSMessageWriter) WritePing(payload []byte) error { - message := &GraphQLTransportWSMessage{ - Type: GraphQLTransportWSMessageTypePing, - Payload: payload, - } - return g.write(message) -} - -// WritePong writes a message of type 'pong' to the transport client. Payload is optional. -func (g *GraphQLTransportWSMessageWriter) WritePong(payload []byte) error { - message := &GraphQLTransportWSMessage{ - Type: GraphQLTransportWSMessageTypePong, - Payload: payload, - } - return g.write(message) -} - -// WriteNext writes a message of type 'next' to the transport client including the execution result as payload. -func (g *GraphQLTransportWSMessageWriter) WriteNext(id string, executionResult []byte) error { - message := &GraphQLTransportWSMessage{ - Id: id, - Type: GraphQLTransportWSMessageTypeNext, - Payload: executionResult, - } - return g.write(message) -} - -// WriteError writes a message of type 'error' to the transport client including the graphql errors as payload. -func (g *GraphQLTransportWSMessageWriter) WriteError(id string, graphqlErrors graphql.RequestErrors) error { - payloadBytes, err := json.Marshal(graphqlErrors) - if err != nil { - return err - } - message := &GraphQLTransportWSMessage{ - Id: id, - Type: GraphQLTransportWSMessageTypeError, - Payload: payloadBytes, - } - return g.write(message) -} - -// WriteComplete writes a message of type 'complete' to the transport client. -func (g *GraphQLTransportWSMessageWriter) WriteComplete(id string) error { - message := &GraphQLTransportWSMessage{ - Id: id, - Type: GraphQLTransportWSMessageTypeComplete, - } - return g.write(message) -} - -func (g *GraphQLTransportWSMessageWriter) write(message *GraphQLTransportWSMessage) error { - jsonData, err := json.Marshal(message) - if err != nil { - g.logger.Error("websocket.GraphQLTransportWSMessageWriter.write: on json marshal", - abstractlogger.Error(err), - abstractlogger.String("id", message.Id), - abstractlogger.String("type", string(message.Type)), - abstractlogger.Any("payload", message.Payload), - ) - return err - } - g.mu.Lock() - defer g.mu.Unlock() - return g.Client.WriteBytesToClient(jsonData) -} - -// GraphQLTransportWSEventHandler can be used to handle subscription events and forward them to a GraphQLTransportWSMessageWriter. -type GraphQLTransportWSEventHandler struct { - logger abstractlogger.Logger - Writer GraphQLTransportWSMessageWriter - OnConnectionOpened func() -} - -// Emit is an implementation of subscription.EventHandler. It forwards some events to the HandleWriteEvent. -func (g *GraphQLTransportWSEventHandler) Emit(eventType subscription.EventType, id string, data []byte, err error) { - messageType := GraphQLTransportWSMessageType("") - switch eventType { - case subscription.EventTypeOnSubscriptionCompleted: - messageType = GraphQLTransportWSMessageTypeComplete - case subscription.EventTypeOnSubscriptionData: - messageType = GraphQLTransportWSMessageTypeNext - case subscription.EventTypeOnNonSubscriptionExecutionResult: - g.HandleWriteEvent(GraphQLTransportWSMessageTypeNext, id, data, err) - g.HandleWriteEvent(GraphQLTransportWSMessageTypeComplete, id, data, err) - return - case subscription.EventTypeOnError: - messageType = GraphQLTransportWSMessageTypeError - case subscription.EventTypeOnConnectionOpened: - if g.OnConnectionOpened != nil { - g.OnConnectionOpened() - } - return - case subscription.EventTypeOnDuplicatedSubscriberID: - err = g.Writer.Client.DisconnectWithReason( - NewCloseReason(4409, fmt.Sprintf("Subscriber for %s already exists", id)), - ) - - if err != nil { - g.logger.Error("websocket.GraphQLTransportWSEventHandler.Emit: on duplicate subscriber id handling", - abstractlogger.Error(err), - abstractlogger.String("id", id), - abstractlogger.String("type", string(messageType)), - abstractlogger.ByteString("payload", data), - ) - } - return - default: - return - } - g.HandleWriteEvent(messageType, id, data, err) -} - -// HandleWriteEvent forwards messages to the underlying writer. -func (g *GraphQLTransportWSEventHandler) HandleWriteEvent(messageType GraphQLTransportWSMessageType, id string, data []byte, providedErr error) { - var err error - switch messageType { - case GraphQLTransportWSMessageTypeComplete: - err = g.Writer.WriteComplete(id) - case GraphQLTransportWSMessageTypeNext: - err = g.Writer.WriteNext(id, data) - case GraphQLTransportWSMessageTypeError: - err = g.Writer.WriteError(id, graphql.RequestErrorsFromError(providedErr)) - case GraphQLTransportWSMessageTypeConnectionAck: - err = g.Writer.WriteConnectionAck() - case GraphQLTransportWSMessageTypePing: - err = g.Writer.WritePing(data) - case GraphQLTransportWSMessageTypePong: - err = g.Writer.WritePong(data) - default: - g.logger.Warn("websocket.GraphQLTransportWSEventHandler.HandleWriteEvent: on write event handling with unexpected message type", - abstractlogger.Error(err), - abstractlogger.String("id", id), - abstractlogger.String("type", string(messageType)), - abstractlogger.ByteString("payload", data), - abstractlogger.Error(providedErr), - ) - err = g.Writer.Client.DisconnectWithReason( - NewCloseReason( - 4400, - fmt.Sprintf("invalid type '%s'", string(messageType)), - ), - ) - if err != nil { - g.logger.Error("websocket.GraphQLTransportWSEventHandler.HandleWriteEvent: after disconnecting on write event handling with unexpected message type", - abstractlogger.Error(err), - abstractlogger.String("id", id), - abstractlogger.String("type", string(messageType)), - abstractlogger.ByteString("payload", data), - ) - } - return - } - if err != nil { - g.logger.Error("websocket.GraphQLTransportWSEventHandler.HandleWriteEvent: on write event handling", - abstractlogger.Error(err), - abstractlogger.String("id", id), - abstractlogger.String("type", string(messageType)), - abstractlogger.ByteString("payload", data), - abstractlogger.Error(providedErr), - ) - } -} - -// ProtocolGraphQLTransportWSHandlerOptions can be used to provide options to the graphql-transport-ws protocol handler. -type ProtocolGraphQLTransportWSHandlerOptions struct { - Logger abstractlogger.Logger - WebSocketInitFunc InitFunc - CustomKeepAliveInterval time.Duration - CustomInitTimeOutDuration time.Duration -} - -// ProtocolGraphQLTransportWSHandler is able to handle the graphql-transport-ws protocol. -type ProtocolGraphQLTransportWSHandler struct { - logger abstractlogger.Logger - reader GraphQLTransportWSMessageReader - eventHandler GraphQLTransportWSEventHandler - connectionInitialized bool - heartbeatInterval time.Duration - heartbeatStarted bool - initFunc InitFunc - connectionAcknowledged bool - connectionInitTimerStarted bool - connectionInitTimeOutCancel context.CancelFunc - connectionInitTimeOutDuration time.Duration -} - -// NewProtocolGraphQLTransportWSHandler creates a new ProtocolGraphQLTransportWSHandler with default options. -func NewProtocolGraphQLTransportWSHandler(client subscription.TransportClient) (*ProtocolGraphQLTransportWSHandler, error) { - return NewProtocolGraphQLTransportWSHandlerWithOptions(client, ProtocolGraphQLTransportWSHandlerOptions{}) -} - -// NewProtocolGraphQLTransportWSHandlerWithOptions creates a new ProtocolGraphQLTransportWSHandler. It requires an option struct. -func NewProtocolGraphQLTransportWSHandlerWithOptions(client subscription.TransportClient, opts ProtocolGraphQLTransportWSHandlerOptions) (*ProtocolGraphQLTransportWSHandler, error) { - protocolHandler := &ProtocolGraphQLTransportWSHandler{ - logger: abstractlogger.Noop{}, - reader: GraphQLTransportWSMessageReader{ - logger: abstractlogger.Noop{}, - }, - eventHandler: GraphQLTransportWSEventHandler{ - logger: abstractlogger.Noop{}, - Writer: GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: client, - mu: &sync.Mutex{}, - }, - }, - initFunc: opts.WebSocketInitFunc, - } - - if opts.Logger != nil { - protocolHandler.logger = opts.Logger - protocolHandler.reader.logger = opts.Logger - protocolHandler.eventHandler.logger = opts.Logger - protocolHandler.eventHandler.Writer.logger = opts.Logger - } - - if opts.CustomKeepAliveInterval != 0 { - protocolHandler.heartbeatInterval = opts.CustomKeepAliveInterval - } else { - parsedKeepAliveInterval, err := time.ParseDuration(subscription.DefaultKeepAliveInterval) - if err != nil { - return nil, err - } - protocolHandler.heartbeatInterval = parsedKeepAliveInterval - } - - if opts.CustomInitTimeOutDuration != 0 { - protocolHandler.connectionInitTimeOutDuration = opts.CustomInitTimeOutDuration - } else { - timeOutDuration, err := time.ParseDuration(DefaultConnectionInitTimeOut) - if err != nil { - return nil, err - } - protocolHandler.connectionInitTimeOutDuration = timeOutDuration - } - - // Pass event functions - protocolHandler.eventHandler.OnConnectionOpened = protocolHandler.startConnectionInitTimer - - return protocolHandler, nil -} - -// Handle will handle the actual graphql-transport-ws protocol messages. It's an implementation of subscription.Protocol. -func (p *ProtocolGraphQLTransportWSHandler) Handle(ctx context.Context, engine subscription.Engine, data []byte) error { - if !p.connectionAcknowledged && !p.connectionInitTimerStarted { - p.startConnectionInitTimer() - } - - message, err := p.reader.Read(data) - if err != nil { - var jsonSyntaxError *json.SyntaxError - if errors.As(err, &jsonSyntaxError) { - p.closeConnectionWithReason(NewCloseReason(4400, "JSON syntax error")) - return nil - } - p.logger.Error("websocket.ProtocolGraphQLTransportWSHandler.Handle: on message reading", - abstractlogger.Error(err), - abstractlogger.ByteString("payload", data), - ) - return err - } - switch message.Type { - case GraphQLTransportWSMessageTypeConnectionInit: - ctx, err = p.handleInit(ctx, message.Payload) - if err != nil { - p.logger.Error("websocket.ProtocolGraphQLTransportWSHandler.Handle: on handling init", - abstractlogger.Error(err), - ) - p.closeConnectionWithReason( - CompiledCloseReasonInternalServerError, - ) - } - p.startHeartbeat(ctx) - case GraphQLTransportWSMessageTypePing: - p.handlePing(message.Payload) - case GraphQLTransportWSMessageTypePong: - return nil // no need to act on pong currently (this may change in future for heartbeat checks) - case GraphQLTransportWSMessageTypeSubscribe: - return p.handleSubscribe(ctx, engine, message) - case GraphQLTransportWSMessageTypeComplete: - return p.handleComplete(engine, message.Id) - default: - p.closeConnectionWithReason( - NewCloseReason(4400, fmt.Sprintf("Invalid type '%s'", string(message.Type))), - ) - } - - return nil -} - -// EventHandler returns the underlying graphql-transport-ws event handler. It's an implementation of subscription.Protocol. -func (p *ProtocolGraphQLTransportWSHandler) EventHandler() subscription.EventHandler { - return &p.eventHandler -} - -func (p *ProtocolGraphQLTransportWSHandler) startConnectionInitTimer() { - if p.connectionInitTimerStarted { - return - } - - timeOutContext, timeOutContextCancel := context.WithCancel(context.Background()) - p.connectionInitTimeOutCancel = timeOutContextCancel - p.connectionInitTimerStarted = true - timeOutParams := subscription.TimeOutParams{ - Name: "connection init time out", - Logger: p.logger, - TimeOutContext: timeOutContext, - TimeOutAction: func() { - p.closeConnectionWithReason( - NewCloseReason(4408, "Connection initialisation timeout"), - ) - }, - TimeOutDuration: p.connectionInitTimeOutDuration, - } - go subscription.TimeOutChecker(timeOutParams) -} - -func (p *ProtocolGraphQLTransportWSHandler) stopConnectionInitTimer() bool { - if p.connectionInitTimeOutCancel == nil { - return false - } - - p.connectionInitTimeOutCancel() - p.connectionInitTimeOutCancel = nil - return true -} - -func (p *ProtocolGraphQLTransportWSHandler) startHeartbeat(ctx context.Context) { - if p.heartbeatStarted { - return - } - - p.heartbeatStarted = true - go p.heartbeat(ctx) -} - -func (p *ProtocolGraphQLTransportWSHandler) heartbeat(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case <-time.After(p.heartbeatInterval): - p.eventHandler.HandleWriteEvent(GraphQLTransportWSMessageTypePong, "", []byte(GraphQLTransportWSHeartbeatPayload), nil) - } - } -} - -func (p *ProtocolGraphQLTransportWSHandler) handleInit(ctx context.Context, payload []byte) (context.Context, error) { - if p.connectionInitialized { - p.closeConnectionWithReason( - NewCloseReason(4429, "Too many initialisation requests"), - ) - return ctx, nil - } - - initCtx := ctx - if p.initFunc != nil && len(payload) > 0 { - // check initial payload to see whether to accept the websocket connection - var err error - if initCtx, err = p.initFunc(ctx, payload); err != nil { - return initCtx, err - } - } - - if p.stopConnectionInitTimer() { - p.eventHandler.HandleWriteEvent(GraphQLTransportWSMessageTypeConnectionAck, "", nil, nil) - } else { - p.closeConnectionWithReason(CompiledCloseReasonInternalServerError) - } - p.connectionInitialized = true - return initCtx, nil -} - -func (p *ProtocolGraphQLTransportWSHandler) handlePing(payload []byte) { - // Pong should return the same payload as ping. - // https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#pings_and_pongs_the_heartbeat_of_websockets - p.eventHandler.HandleWriteEvent(GraphQLTransportWSMessageTypePong, "", payload, nil) -} - -func (p *ProtocolGraphQLTransportWSHandler) handleSubscribe(ctx context.Context, engine subscription.Engine, message *GraphQLTransportWSMessage) error { - if !p.connectionInitialized { - p.closeConnectionWithReason( - NewCloseReason(4401, "Unauthorized"), - ) - return nil - } - - subscribePayload, err := p.reader.DeserializeSubscribePayload(message) - if err != nil { - return err - } - - enginePayload := graphql.Request{ - OperationName: subscribePayload.OperationName, - Query: subscribePayload.Query, - Variables: subscribePayload.Variables, - } - - enginePayloadBytes, err := json.Marshal(enginePayload) - if err != nil { - return err - } - - return engine.StartOperation(ctx, message.Id, enginePayloadBytes, &p.eventHandler) -} - -func (p *ProtocolGraphQLTransportWSHandler) handleComplete(engine subscription.Engine, id string) error { - return engine.StopSubscription(id, &p.eventHandler) -} - -func (p *ProtocolGraphQLTransportWSHandler) closeConnectionWithReason(reason interface{}) { - err := p.eventHandler.Writer.Client.DisconnectWithReason( - reason, - ) - if err != nil { - p.logger.Error("websocket.ProtocolGraphQLTransportWSHandler.closeConnectionWithReason: after trying to disconnect with reason", - abstractlogger.Error(err), - ) - } -} - -// Interface guards -var _ subscription.EventHandler = (*GraphQLTransportWSEventHandler)(nil) -var _ subscription.Protocol = (*ProtocolGraphQLTransportWSHandler)(nil) diff --git a/pkg/subscription/websocket/protocol_graphql_transport_ws_test.go b/pkg/subscription/websocket/protocol_graphql_transport_ws_test.go deleted file mode 100644 index 5fe382f8d..000000000 --- a/pkg/subscription/websocket/protocol_graphql_transport_ws_test.go +++ /dev/null @@ -1,572 +0,0 @@ -package websocket - -import ( - "context" - "errors" - "runtime" - "sync" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -func TestGraphQLTransportWSMessageReader_Read(t *testing.T) { - t.Run("should read a minimal message", func(t *testing.T) { - data := []byte(`{ "type": "connection_init" }`) - expectedMessage := &GraphQLTransportWSMessage{ - Type: "connection_init", - } - - reader := GraphQLTransportWSMessageReader{ - logger: abstractlogger.Noop{}, - } - message, err := reader.Read(data) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, message) - }) - - t.Run("should message with json payload", func(t *testing.T) { - data := []byte(`{ "id": "1", "type": "connection_init", "payload": { "Authorization": "Bearer ey123" } }`) - expectedMessage := &GraphQLTransportWSMessage{ - Id: "1", - Type: "connection_init", - Payload: []byte(`{ "Authorization": "Bearer ey123" }`), - } - - reader := GraphQLTransportWSMessageReader{ - logger: abstractlogger.Noop{}, - } - message, err := reader.Read(data) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, message) - }) - - t.Run("should read and deserialize subscribe message", func(t *testing.T) { - data := []byte(`{ - "id": "1", - "type": "subscribe", - "payload": { - "operationName": "MyQuery", - "query": "query MyQuery($name: String) { hello(name: $name) }", - "variables": { "name": "Udo" }, - "extensions": { "Authorization": "Bearer ey123" } - } -}`) - expectedMessage := &GraphQLTransportWSMessage{ - Id: "1", - Type: "subscribe", - Payload: []byte(`{ - "operationName": "MyQuery", - "query": "query MyQuery($name: String) { hello(name: $name) }", - "variables": { "name": "Udo" }, - "extensions": { "Authorization": "Bearer ey123" } - }`), - } - - reader := GraphQLTransportWSMessageReader{ - logger: abstractlogger.Noop{}, - } - message, err := reader.Read(data) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, message) - - expectedPayload := &GraphQLTransportWSMessageSubscribePayload{ - OperationName: "MyQuery", - Query: "query MyQuery($name: String) { hello(name: $name) }", - Variables: []byte(`{ "name": "Udo" }`), - Extensions: []byte(`{ "Authorization": "Bearer ey123" }`), - } - actualPayload, err := reader.DeserializeSubscribePayload(message) - assert.NoError(t, err) - assert.Equal(t, expectedPayload, actualPayload) - }) -} - -func TestGraphQLTransportWSMessageWriter_WriteConnectionAck(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteConnectionAck() - assert.Error(t, err) - }) - t.Run("should successfully write ack message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"connection_ack"}`) - err := writer.WriteConnectionAck() - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLTransportWSMessageWriter_WritePing(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WritePing(nil) - assert.Error(t, err) - }) - t.Run("should successfully write ping message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"ping"}`) - err := writer.WritePing(nil) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should successfully write ping message with payload to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"ping","payload":{"connected_since":"10min"}}`) - err := writer.WritePing([]byte(`{"connected_since":"10min"}`)) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLTransportWSMessageWriter_WritePong(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WritePong(nil) - assert.Error(t, err) - }) - t.Run("should successfully write pong message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"pong"}`) - err := writer.WritePong(nil) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should successfully write pong message with payload to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"pong","payload":{"connected_since":"10min"}}`) - err := writer.WritePong([]byte(`{"connected_since":"10min"}`)) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLTransportWSMessageWriter_WriteNext(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteNext("1", nil) - assert.Error(t, err) - }) - t.Run("should successfully write next message with payload to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"id":"1","type":"next","payload":{"data":{"hello":"world"}}}`) - err := writer.WriteNext("1", []byte(`{"data":{"hello":"world"}}`)) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLTransportWSMessageWriter_WriteError(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteError("1", nil) - assert.Error(t, err) - }) - t.Run("should successfully write error message with payload to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"id":"1","type":"error","payload":[{"message":"request error"}]}`) - requestErrors := graphql.RequestErrorsFromError(errors.New("request error")) - err := writer.WriteError("1", requestErrors) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLTransportWSMessageWriter_WriteComplete(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteComplete("1") - assert.Error(t, err) - }) - t.Run("should successfully write complete message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"id":"1","type":"complete"}`) - err := writer.WriteComplete("1") - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLTransportWSEventHandler_Emit(t *testing.T) { - t.Run("should write on completed", func(t *testing.T) { - testClient := NewTestClient(false) - eventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - eventHandler.Emit(subscription.EventTypeOnSubscriptionCompleted, "1", nil, nil) - expectedMessage := []byte(`{"id":"1","type":"complete"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on data", func(t *testing.T) { - testClient := NewTestClient(false) - eventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - eventHandler.Emit(subscription.EventTypeOnSubscriptionData, "1", []byte(`{ "data": { "hello": "world" } }`), nil) - expectedMessage := []byte(`{"id":"1","type":"next","payload":{"data":{"hello":"world"}}}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on non-subscription execution result", func(t *testing.T) { - testClient := NewTestClient(false) - eventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - go func() { - eventHandler.Emit(subscription.EventTypeOnNonSubscriptionExecutionResult, "1", []byte(`{ "data": { "hello": "world" } }`), nil) - }() - - assert.Eventually(t, func() bool { - expectedDataMessage := []byte(`{"id":"1","type":"next","payload":{"data":{"hello":"world"}}}`) - actualDataMessage := testClient.readMessageToClient() - assert.Equal(t, expectedDataMessage, actualDataMessage) - expectedCompleteMessage := []byte(`{"id":"1","type":"complete"}`) - actualCompleteMessage := testClient.readMessageToClient() - assert.Equal(t, expectedCompleteMessage, actualCompleteMessage) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - t.Run("should write on error", func(t *testing.T) { - testClient := NewTestClient(false) - eventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - eventHandler.Emit(subscription.EventTypeOnError, "1", nil, errors.New("error occurred")) - expectedMessage := []byte(`{"id":"1","type":"error","payload":[{"message":"error occurred"}]}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should execute the OnConnectionOpened event function", func(t *testing.T) { - counter := 0 - testClient := NewTestClient(false) - eventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - eventHandler.OnConnectionOpened = func() { - counter++ - } - eventHandler.Emit(subscription.EventTypeOnConnectionOpened, "", nil, nil) - assert.Equal(t, counter, 1) - }) - t.Run("should disconnect on duplicated subscriber id", func(t *testing.T) { - testClient := NewTestClient(false) - eventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - eventHandler.Emit(subscription.EventTypeOnDuplicatedSubscriberID, "1", nil, errors.New("subscriber already exists")) - assert.False(t, testClient.IsConnected()) - }) -} - -func TestGraphQLTransportWSWriteEventHandler_HandleWriteEvent(t *testing.T) { - t.Run("should write connection_ack", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - writeEventHandler.HandleWriteEvent(GraphQLTransportWSMessageTypeConnectionAck, "", nil, nil) - expectedMessage := []byte(`{"type":"connection_ack"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write ping", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - writeEventHandler.HandleWriteEvent(GraphQLTransportWSMessageTypePing, "", nil, nil) - expectedMessage := []byte(`{"type":"ping"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write pong", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - writeEventHandler.HandleWriteEvent(GraphQLTransportWSMessageTypePong, "", nil, nil) - expectedMessage := []byte(`{"type":"pong"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should close connection on invalid type", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLTransportWSEventHandler(testClient) - writeEventHandler.HandleWriteEvent(GraphQLTransportWSMessageType("invalid"), "", nil, nil) - assert.False(t, writeEventHandler.Writer.Client.IsConnected()) - }) -} - -func TestProtocolGraphQLTransportWSHandler_Handle(t *testing.T) { - t.Run("should close connection when an unexpected message type is used", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"something"}`)) - assert.NoError(t, err) - assert.False(t, testClient.IsConnected()) - }) - - t.Run("for connection_init", func(t *testing.T) { - t.Run("should time out if no connection_init message is sent", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("this test fails on Windows due to different timings than unix, consider fixing it at some point") - } - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - protocol.connectionInitTimeOutDuration = 2 * time.Millisecond - protocol.eventHandler.OnConnectionOpened = protocol.startConnectionInitTimer - - protocol.eventHandler.Emit(subscription.EventTypeOnConnectionOpened, "", nil, nil) - time.Sleep(10 * time.Millisecond) - assert.True(t, protocol.connectionInitTimerStarted) - assert.False(t, protocol.eventHandler.Writer.Client.IsConnected()) - }) - - t.Run("should close connection after multiple connection_init messages", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - protocol.connectionInitTimeOutDuration = 50 * time.Millisecond - protocol.eventHandler.OnConnectionOpened = protocol.startConnectionInitTimer - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - protocol.eventHandler.Emit(subscription.EventTypeOnConnectionOpened, "", nil, nil) - assert.Eventually(t, func() bool { - expectedAckMessage := []byte(`{"type":"connection_ack"}`) - time.Sleep(5 * time.Millisecond) - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"connection_init"}`)) - assert.NoError(t, err) - assert.Equal(t, expectedAckMessage, testClient.readMessageToClient()) - time.Sleep(1 * time.Millisecond) - err = protocol.Handle(ctx, mockEngine, []byte(`{"type":"connection_init"}`)) - assert.NoError(t, err) - assert.False(t, protocol.eventHandler.Writer.Client.IsConnected()) - return true - }, 1*time.Second, 2*time.Millisecond) - - }) - - t.Run("should not time out if connection_init message is sent before time out", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("this test fails on Windows due to different timings than unix, consider fixing it at some point") - } - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - protocol.heartbeatInterval = 4 * time.Millisecond - protocol.connectionInitTimeOutDuration = 25 * time.Millisecond - protocol.eventHandler.OnConnectionOpened = protocol.startConnectionInitTimer - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - protocol.eventHandler.Emit(subscription.EventTypeOnConnectionOpened, "", nil, nil) - assert.Eventually(t, func() bool { - expectedAckMessage := []byte(`{"type":"connection_ack"}`) - expectedHeartbeatMessage := []byte(`{"type":"pong","payload":{"type":"heartbeat"}}`) - time.Sleep(1 * time.Millisecond) - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"connection_init"}`)) - assert.NoError(t, err) - assert.Equal(t, expectedAckMessage, testClient.readMessageToClient()) - time.Sleep(6 * time.Millisecond) - assert.Equal(t, expectedHeartbeatMessage, testClient.readMessageToClient()) - time.Sleep(50 * time.Millisecond) - assert.True(t, protocol.eventHandler.Writer.Client.IsConnected()) - assert.True(t, protocol.connectionInitTimerStarted) - assert.Nil(t, protocol.connectionInitTimeOutCancel) - return true - }, 1*time.Second, 2*time.Millisecond) - - }) - }) - - t.Run("should return pong on ping", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - assert.Eventually(t, func() bool { - inputMessage := []byte(`{"type":"ping","payload":{"status":"ok"}}`) - expectedMessage := []byte(`{"type":"pong","payload":{"status":"ok"}}`) - err := protocol.Handle(ctx, mockEngine, inputMessage) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - - t.Run("should handle subscribe", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - operation := []byte(`{"operationName":"Hello","query":"query Hello { hello }"}`) - ctrl := gomock.NewController(t) - defer ctrl.Finish() - mockEngine := NewMockEngine(ctrl) - mockEngine.EXPECT().StartOperation(gomock.Eq(ctx), gomock.Eq("2"), gomock.Eq(operation), gomock.Eq(&protocol.eventHandler)) - - assert.Eventually(t, func() bool { - initMessage := []byte(`{"id":"1","type":"connection_init"}`) - err := protocol.Handle(ctx, mockEngine, initMessage) - assert.NoError(t, err) - subscribeMessage := []byte(`{"id":"2","type":"subscribe","payload":` + string(operation) + `}`) - err2 := protocol.Handle(ctx, mockEngine, subscribeMessage) - assert.NoError(t, err2) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - - t.Run("should handle complete", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - mockEngine.EXPECT().StopSubscription(gomock.Eq("1"), gomock.Eq(&protocol.eventHandler)) - - assert.Eventually(t, func() bool { - inputMessage := []byte(`{"id":"1","type":"complete"}`) - err := protocol.Handle(ctx, mockEngine, inputMessage) - assert.NoError(t, err) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - - t.Run("should allow pong messages from client", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - assert.Eventually(t, func() bool { - inputMessage := []byte(`{"type":"pong"}`) - err := protocol.Handle(ctx, mockEngine, inputMessage) - assert.NoError(t, err) - assert.True(t, testClient.IsConnected()) - return true - }, 1*time.Second, 2*time.Millisecond) - }) - - t.Run("should not panic on broken input", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLTransportWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - assert.Eventually(t, func() bool { - inputMessage := []byte(`{"type":"connection_init","payload":{something}}`) - err := protocol.Handle(ctx, mockEngine, inputMessage) - assert.NoError(t, err) - assert.False(t, testClient.IsConnected()) - return true - }, 1*time.Second, 2*time.Millisecond) - }) -} - -func NewTestGraphQLTransportWSEventHandler(testClient subscription.TransportClient) GraphQLTransportWSEventHandler { - return GraphQLTransportWSEventHandler{ - logger: abstractlogger.Noop{}, - Writer: GraphQLTransportWSMessageWriter{ - logger: abstractlogger.Noop{}, - mu: &sync.Mutex{}, - Client: testClient, - }, - } -} - -func NewTestProtocolGraphQLTransportWSHandler(testClient subscription.TransportClient) *ProtocolGraphQLTransportWSHandler { - return &ProtocolGraphQLTransportWSHandler{ - logger: abstractlogger.Noop{}, - reader: GraphQLTransportWSMessageReader{ - logger: abstractlogger.Noop{}, - }, - eventHandler: NewTestGraphQLTransportWSEventHandler(testClient), - heartbeatInterval: 30, - connectionInitTimeOutDuration: 10 * time.Second, - } -} diff --git a/pkg/subscription/websocket/protocol_graphql_ws.go b/pkg/subscription/websocket/protocol_graphql_ws.go deleted file mode 100644 index 8d16d17f7..000000000 --- a/pkg/subscription/websocket/protocol_graphql_ws.go +++ /dev/null @@ -1,359 +0,0 @@ -package websocket - -import ( - "context" - "encoding/json" - "errors" - "fmt" - "sync" - "time" - - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -// GraphQLWSMessageType is a type that defines graphql-ws message type names. -type GraphQLWSMessageType string - -const ( - GraphQLWSMessageTypeConnectionInit GraphQLWSMessageType = "connection_init" - GraphQLWSMessageTypeConnectionAck GraphQLWSMessageType = "connection_ack" - GraphQLWSMessageTypeConnectionError GraphQLWSMessageType = "connection_error" - GraphQLWSMessageTypeConnectionTerminate GraphQLWSMessageType = "connection_terminate" - GraphQLWSMessageTypeConnectionKeepAlive GraphQLWSMessageType = "ka" - GraphQLWSMessageTypeStart GraphQLWSMessageType = "start" - GraphQLWSMessageTypeStop GraphQLWSMessageType = "stop" - GraphQLWSMessageTypeData GraphQLWSMessageType = "data" - GraphQLWSMessageTypeError GraphQLWSMessageType = "error" - GraphQLWSMessageTypeComplete GraphQLWSMessageType = "complete" -) - -var ErrGraphQLWSUnexpectedMessageType = errors.New("unexpected message type") - -// GraphQLWSMessage is a struct that can be (de)serialized to graphql-ws message format. -type GraphQLWSMessage struct { - Id string `json:"id,omitempty"` - Type GraphQLWSMessageType `json:"type"` - Payload json.RawMessage `json:"payload,omitempty"` -} - -// GraphQLWSMessageReader can be used to read graphql-ws messages. -type GraphQLWSMessageReader struct { - logger abstractlogger.Logger -} - -// Read deserializes a byte slice to the GraphQLWSMessage struct. -func (g *GraphQLWSMessageReader) Read(data []byte) (*GraphQLWSMessage, error) { - var message GraphQLWSMessage - err := json.Unmarshal(data, &message) - if err != nil { - g.logger.Error("websocket.GraphQLWSMessageReader.Read: on json unmarshal", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - ) - - return nil, err - } - return &message, nil -} - -// GraphQLWSMessageWriter can be used to write graphql-ws messages to a transport client. -type GraphQLWSMessageWriter struct { - logger abstractlogger.Logger - mu *sync.Mutex - Client subscription.TransportClient -} - -// WriteData writes a message of type 'data' to the transport client. -func (g *GraphQLWSMessageWriter) WriteData(id string, responseData []byte) error { - message := &GraphQLWSMessage{ - Id: id, - Type: GraphQLWSMessageTypeData, - Payload: responseData, - } - return g.write(message) -} - -// WriteComplete writes a message of type 'complete' to the transport client. -func (g *GraphQLWSMessageWriter) WriteComplete(id string) error { - message := &GraphQLWSMessage{ - Id: id, - Type: GraphQLWSMessageTypeComplete, - Payload: nil, - } - return g.write(message) -} - -// WriteKeepAlive writes a message of type 'ka' to the transport client. -func (g *GraphQLWSMessageWriter) WriteKeepAlive() error { - message := &GraphQLWSMessage{ - Type: GraphQLWSMessageTypeConnectionKeepAlive, - Payload: nil, - } - return g.write(message) -} - -// WriteTerminate writes a message of type 'connection_terminate' to the transport client. -func (g *GraphQLWSMessageWriter) WriteTerminate(reason string) error { - payloadBytes, err := json.Marshal(reason) - if err != nil { - return err - } - message := &GraphQLWSMessage{ - Type: GraphQLWSMessageTypeConnectionTerminate, - Payload: payloadBytes, - } - return g.write(message) -} - -// WriteConnectionError writes a message of type 'connection_error' to the transport client. -func (g *GraphQLWSMessageWriter) WriteConnectionError(reason string) error { - payloadBytes, err := json.Marshal(reason) - if err != nil { - return err - } - message := &GraphQLWSMessage{ - Type: GraphQLWSMessageTypeConnectionError, - Payload: payloadBytes, - } - return g.write(message) -} - -// WriteError writes a message of type 'error' to the transport client. -func (g *GraphQLWSMessageWriter) WriteError(id string, errors graphql.RequestErrors) error { - payloadBytes, err := json.Marshal(errors) - if err != nil { - return err - } - message := &GraphQLWSMessage{ - Id: id, - Type: GraphQLWSMessageTypeError, - Payload: payloadBytes, - } - return g.write(message) -} - -// WriteAck writes a message of type 'connection_ack' to the transport client. -func (g *GraphQLWSMessageWriter) WriteAck() error { - message := &GraphQLWSMessage{ - Type: GraphQLWSMessageTypeConnectionAck, - } - return g.write(message) -} - -func (g *GraphQLWSMessageWriter) write(message *GraphQLWSMessage) error { - jsonData, err := json.Marshal(message) - if err != nil { - g.logger.Error("websocket.GraphQLWSMessageWriter.write: on json marshal", - abstractlogger.Error(err), - abstractlogger.String("id", message.Id), - abstractlogger.String("type", string(message.Type)), - abstractlogger.ByteString("payload", message.Payload), - ) - return err - } - g.mu.Lock() - defer g.mu.Unlock() - return g.Client.WriteBytesToClient(jsonData) -} - -// GraphQLWSWriteEventHandler can be used to handle subscription events and forward them to a GraphQLWSMessageWriter. -type GraphQLWSWriteEventHandler struct { - logger abstractlogger.Logger - Writer GraphQLWSMessageWriter -} - -// Emit is an implementation of subscription.EventHandler. It forwards events to the HandleWriteEvent. -func (g *GraphQLWSWriteEventHandler) Emit(eventType subscription.EventType, id string, data []byte, err error) { - messageType := GraphQLWSMessageType("") - switch eventType { - case subscription.EventTypeOnSubscriptionCompleted: - messageType = GraphQLWSMessageTypeComplete - case subscription.EventTypeOnSubscriptionData: - messageType = GraphQLWSMessageTypeData - case subscription.EventTypeOnNonSubscriptionExecutionResult: - g.HandleWriteEvent(GraphQLWSMessageTypeData, id, data, err) - g.HandleWriteEvent(GraphQLWSMessageTypeComplete, id, data, err) - return - case subscription.EventTypeOnError: - messageType = GraphQLWSMessageTypeError - case subscription.EventTypeOnDuplicatedSubscriberID: - messageType = GraphQLWSMessageTypeError - case subscription.EventTypeOnConnectionError: - messageType = GraphQLWSMessageTypeConnectionError - default: - return - } - - g.HandleWriteEvent(messageType, id, data, err) -} - -// HandleWriteEvent forwards messages to the underlying writer. -func (g *GraphQLWSWriteEventHandler) HandleWriteEvent(messageType GraphQLWSMessageType, id string, data []byte, providedErr error) { - var err error - switch messageType { - case GraphQLWSMessageTypeComplete: - err = g.Writer.WriteComplete(id) - case GraphQLWSMessageTypeData: - err = g.Writer.WriteData(id, data) - case GraphQLWSMessageTypeError: - err = g.Writer.WriteError(id, graphql.RequestErrorsFromError(providedErr)) - case GraphQLWSMessageTypeConnectionError: - err = g.Writer.WriteConnectionError(providedErr.Error()) - case GraphQLWSMessageTypeConnectionKeepAlive: - err = g.Writer.WriteKeepAlive() - case GraphQLWSMessageTypeConnectionAck: - err = g.Writer.WriteAck() - default: - g.logger.Warn("websocket.GraphQLWSWriteEventHandler.HandleWriteEvent: on write event handling with unexpected message type", - abstractlogger.Error(err), - abstractlogger.String("id", id), - abstractlogger.String("type", string(messageType)), - abstractlogger.ByteString("payload", data), - abstractlogger.Error(providedErr), - ) - return - } - if err != nil { - g.logger.Error("websocket.GraphQLWSWriteEventHandler.HandleWriteEvent: on write event handling", - abstractlogger.Error(err), - abstractlogger.String("id", id), - abstractlogger.String("type", string(messageType)), - abstractlogger.ByteString("payload", data), - abstractlogger.Error(providedErr), - ) - } -} - -// ProtocolGraphQLWSHandlerOptions can be used to provide options to the graphql-ws protocol handler. -type ProtocolGraphQLWSHandlerOptions struct { - Logger abstractlogger.Logger - WebSocketInitFunc InitFunc - CustomKeepAliveInterval time.Duration -} - -// ProtocolGraphQLWSHandler is able to handle the graphql-ws protocol. -type ProtocolGraphQLWSHandler struct { - logger abstractlogger.Logger - reader GraphQLWSMessageReader - writeEventHandler GraphQLWSWriteEventHandler - keepAliveInterval time.Duration - initFunc InitFunc -} - -// NewProtocolGraphQLWSHandler creates a new ProtocolGraphQLWSHandler with default options. -func NewProtocolGraphQLWSHandler(client subscription.TransportClient) (*ProtocolGraphQLWSHandler, error) { - return NewProtocolGraphQLWSHandlerWithOptions(client, ProtocolGraphQLWSHandlerOptions{}) -} - -// NewProtocolGraphQLWSHandlerWithOptions creates a new ProtocolGraphQLWSHandler. It requires an option struct. -func NewProtocolGraphQLWSHandlerWithOptions(client subscription.TransportClient, opts ProtocolGraphQLWSHandlerOptions) (*ProtocolGraphQLWSHandler, error) { - protocolHandler := &ProtocolGraphQLWSHandler{ - logger: abstractlogger.Noop{}, - reader: GraphQLWSMessageReader{ - logger: abstractlogger.Noop{}, - }, - writeEventHandler: GraphQLWSWriteEventHandler{ - logger: abstractlogger.Noop{}, - Writer: GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: client, - mu: &sync.Mutex{}, - }, - }, - initFunc: opts.WebSocketInitFunc, - } - - if opts.Logger != nil { - protocolHandler.logger = opts.Logger - protocolHandler.reader.logger = opts.Logger - protocolHandler.writeEventHandler.logger = opts.Logger - protocolHandler.writeEventHandler.Writer.logger = opts.Logger - } - - if opts.CustomKeepAliveInterval != 0 { - protocolHandler.keepAliveInterval = opts.CustomKeepAliveInterval - } else { - parsedKeepAliveInterval, err := time.ParseDuration(subscription.DefaultKeepAliveInterval) - if err != nil { - return nil, err - } - protocolHandler.keepAliveInterval = parsedKeepAliveInterval - } - - return protocolHandler, nil -} - -// Handle will handle the actual graphql-ws protocol messages. It's an implementation of subscription.Protocol. -func (p *ProtocolGraphQLWSHandler) Handle(ctx context.Context, engine subscription.Engine, data []byte) error { - message, err := p.reader.Read(data) - if err != nil { - var jsonSyntaxError *json.SyntaxError - if errors.As(err, &jsonSyntaxError) { - p.writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeError, "", nil, errors.New("json syntax error")) - return nil - } - p.logger.Error("websocket.ProtocolGraphQLWSHandler.Handle: on message reading", - abstractlogger.Error(err), - abstractlogger.ByteString("payload", data), - ) - return err - } - - switch message.Type { - case GraphQLWSMessageTypeConnectionInit: - ctx, err = p.handleInit(ctx, message.Payload) - if err != nil { - p.writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeConnectionError, "", nil, errors.New("failed to accept the websocket connection")) - return engine.TerminateAllSubscriptions(&p.writeEventHandler) - } - - go p.handleKeepAlive(ctx) - case GraphQLWSMessageTypeStart: - return engine.StartOperation(ctx, message.Id, message.Payload, &p.writeEventHandler) - case GraphQLWSMessageTypeStop: - return engine.StopSubscription(message.Id, &p.writeEventHandler) - case GraphQLWSMessageTypeConnectionTerminate: - return engine.TerminateAllSubscriptions(&p.writeEventHandler) - default: - p.writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeConnectionError, message.Id, nil, fmt.Errorf("%s: %s", ErrGraphQLWSUnexpectedMessageType.Error(), message.Type)) - } - - return nil -} - -// EventHandler returns the underlying graphql-ws event handler. It's an implementation of subscription.Protocol. -func (p *ProtocolGraphQLWSHandler) EventHandler() subscription.EventHandler { - return &p.writeEventHandler -} - -func (p *ProtocolGraphQLWSHandler) handleInit(ctx context.Context, payload []byte) (context.Context, error) { - initCtx := ctx - if p.initFunc != nil && len(payload) > 0 { - // check initial payload to see whether to accept the websocket connection - var err error - if initCtx, err = p.initFunc(ctx, payload); err != nil { - return initCtx, err - } - } - - p.writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeConnectionAck, "", nil, nil) - return initCtx, nil -} - -func (p *ProtocolGraphQLWSHandler) handleKeepAlive(ctx context.Context) { - for { - select { - case <-ctx.Done(): - return - case <-time.After(p.keepAliveInterval): - p.writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeConnectionKeepAlive, "", nil, nil) - } - } -} - -// Interface guards -var _ subscription.EventHandler = (*GraphQLWSWriteEventHandler)(nil) -var _ subscription.Protocol = (*ProtocolGraphQLWSHandler)(nil) diff --git a/pkg/subscription/websocket/protocol_graphql_ws_test.go b/pkg/subscription/websocket/protocol_graphql_ws_test.go deleted file mode 100644 index 4c1420a6a..000000000 --- a/pkg/subscription/websocket/protocol_graphql_ws_test.go +++ /dev/null @@ -1,411 +0,0 @@ -package websocket - -import ( - "context" - "encoding/json" - "errors" - "sync" - "testing" - "time" - - "github.com/golang/mock/gomock" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -func TestGraphQLWSMessageReader_Read(t *testing.T) { - data := []byte(`{ "id": "1", "type": "connection_init", "payload": { "headers": { "key": "value" } } }`) - expectedMessage := &GraphQLWSMessage{ - Id: "1", - Type: "connection_init", - Payload: json.RawMessage(`{ "headers": { "key": "value" } }`), - } - - reader := GraphQLWSMessageReader{ - logger: abstractlogger.Noop{}, - } - message, err := reader.Read(data) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, message) -} - -func TestGraphQLWSMessageWriter_WriteData(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteData("1", nil) - assert.Error(t, err) - }) - t.Run("should successfully write message data to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"id":"1","type":"data","payload":{"data":{"hello":"world"}}}`) - err := writer.WriteData("1", []byte(`{"data":{"hello":"world"}}`)) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSMessageWriter_WriteComplete(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteComplete("1") - assert.Error(t, err) - }) - t.Run("should successfully write complete message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"id":"1","type":"complete"}`) - err := writer.WriteComplete("1") - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSMessageWriter_WriteKeepAlive(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteKeepAlive() - assert.Error(t, err) - }) - t.Run("should successfully write keep-alive (ka) message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"ka"}`) - err := writer.WriteKeepAlive() - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSMessageWriter_WriteTerminate(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteTerminate(`failed to accept the websocket connection`) - assert.Error(t, err) - }) - t.Run("should successfully write terminate message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"connection_terminate","payload":"failed to accept the websocket connection"}`) - err := writer.WriteTerminate(`failed to accept the websocket connection`) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSMessageWriter_WriteConnectionError(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteConnectionError(`could not read message from client`) - assert.Error(t, err) - }) - t.Run("should successfully write connection error message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"connection_error","payload":"could not read message from client"}`) - err := writer.WriteConnectionError(`could not read message from client`) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSMessageWriter_WriteError(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - requestErrors := graphql.RequestErrorsFromError(errors.New("request error")) - err := writer.WriteError("1", requestErrors) - assert.Error(t, err) - }) - t.Run("should successfully write error message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"id":"1","type":"error","payload":[{"message":"request error"}]}`) - requestErrors := graphql.RequestErrorsFromError(errors.New("request error")) - err := writer.WriteError("1", requestErrors) - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSMessageWriter_WriteAck(t *testing.T) { - t.Run("should return error when error occurs on underlying call", func(t *testing.T) { - testClient := NewTestClient(true) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - err := writer.WriteAck() - assert.Error(t, err) - }) - t.Run("should successfully write ack message to client", func(t *testing.T) { - testClient := NewTestClient(false) - writer := GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - Client: testClient, - mu: &sync.Mutex{}, - } - expectedMessage := []byte(`{"type":"connection_ack"}`) - err := writer.WriteAck() - assert.NoError(t, err) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestGraphQLWSWriteEventHandler_Emit(t *testing.T) { - t.Run("should write on completed", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.Emit(subscription.EventTypeOnSubscriptionCompleted, "1", nil, nil) - expectedMessage := []byte(`{"id":"1","type":"complete"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on data", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.Emit(subscription.EventTypeOnSubscriptionData, "1", []byte(`{ "data": { "hello": "world" } }`), nil) - expectedMessage := []byte(`{"id":"1","type":"data","payload":{"data":{"hello":"world"}}}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on error", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.Emit(subscription.EventTypeOnError, "1", nil, errors.New("error occurred")) - expectedMessage := []byte(`{"id":"1","type":"error","payload":[{"message":"error occurred"}]}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on duplicated subscriber id", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.Emit(subscription.EventTypeOnDuplicatedSubscriberID, "1", nil, subscription.ErrSubscriberIDAlreadyExists) - expectedMessage := []byte(`{"id":"1","type":"error","payload":[{"message":"subscriber id already exists"}]}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on connection_error", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.Emit(subscription.EventTypeOnConnectionError, "", nil, errors.New("connection error occurred")) - expectedMessage := []byte(`{"type":"connection_error","payload":"connection error occurred"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write on non-subscription execution result", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - go func() { - writeEventHandler.Emit(subscription.EventTypeOnNonSubscriptionExecutionResult, "1", []byte(`{ "data": { "hello": "world" } }`), nil) - }() - - assert.Eventually(t, func() bool { - expectedDataMessage := []byte(`{"id":"1","type":"data","payload":{"data":{"hello":"world"}}}`) - actualDataMessage := testClient.readMessageToClient() - assert.Equal(t, expectedDataMessage, actualDataMessage) - expectedCompleteMessage := []byte(`{"id":"1","type":"complete"}`) - actualCompleteMessage := testClient.readMessageToClient() - assert.Equal(t, expectedCompleteMessage, actualCompleteMessage) - return true - }, 1*time.Second, 2*time.Millisecond) - }) -} - -func TestGraphQLWSWriteEventHandler_HandleWriteEvent(t *testing.T) { - t.Run("should write keep_alive", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeConnectionKeepAlive, "", nil, nil) - expectedMessage := []byte(`{"type":"ka"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) - t.Run("should write ack", func(t *testing.T) { - testClient := NewTestClient(false) - writeEventHandler := NewTestGraphQLWSWriteEventHandler(testClient) - writeEventHandler.HandleWriteEvent(GraphQLWSMessageTypeConnectionAck, "", nil, nil) - expectedMessage := []byte(`{"type":"connection_ack"}`) - assert.Equal(t, expectedMessage, testClient.readMessageToClient()) - }) -} - -func TestProtocolGraphQLWSHandler_Handle(t *testing.T) { - t.Run("should return connection_error when an unexpected message type is used", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLWSHandler(testClient) - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - expectedMessage := []byte(`{"type":"connection_error","payload":"unexpected message type: something"}`) - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"something"}`)) - assert.NoError(t, err) - assert.Equal(t, testClient.readMessageToClient(), expectedMessage) - }) - - t.Run("should terminate connections on connection_terminate from client", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLWSHandler(testClient) - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - mockEngine.EXPECT().TerminateAllSubscriptions(gomock.Eq(protocol.EventHandler())) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"connection_terminate"}`)) - assert.NoError(t, err) - }) - - t.Run("should init connection and respond with ack and ka", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLWSHandler(testClient) - protocol.keepAliveInterval = 5 * time.Millisecond - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - ctx, cancelFunc := context.WithCancel(context.Background()) - - assert.Eventually(t, func() bool { - expectedMessageAck := []byte(`{"type":"connection_ack"}`) - expectedMessageKeepAlive := []byte(`{"type":"ka"}`) - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"connection_init"}`)) - assert.NoError(t, err) - assert.Equal(t, expectedMessageAck, testClient.readMessageToClient()) - - time.Sleep(8 * time.Millisecond) - assert.Equal(t, expectedMessageKeepAlive, testClient.readMessageToClient()) - cancelFunc() - - return true - }, 1*time.Second, 5*time.Millisecond) - - }) - - t.Run("should start an operation on start from client", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - mockEngine.EXPECT().StartOperation(gomock.Eq(ctx), "1", []byte(`{"query":"{ hello }"}`), gomock.Eq(protocol.EventHandler())) - - err := protocol.Handle(ctx, mockEngine, []byte(`{"id":"1","type":"start","payload":{"query":"{ hello }"}}`)) - assert.NoError(t, err) - }) - - t.Run("should stop a subscription on stop from client", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - mockEngine.EXPECT().StopSubscription("1", gomock.Eq(protocol.EventHandler())) - - err := protocol.Handle(ctx, mockEngine, []byte(`{"id":"1","type":"stop"}`)) - assert.NoError(t, err) - }) - - t.Run("should not panic on broken input", func(t *testing.T) { - testClient := NewTestClient(false) - protocol := NewTestProtocolGraphQLWSHandler(testClient) - - ctx, cancelFunc := context.WithCancel(context.Background()) - defer cancelFunc() - - ctrl := gomock.NewController(t) - mockEngine := NewMockEngine(ctrl) - - err := protocol.Handle(ctx, mockEngine, []byte(`{"type":"connection_init","payload":{something}}`)) - assert.NoError(t, err) - - expectedMessage := []byte(`{"type":"error","payload":[{"message":"json syntax error"}]}`) - actualMessage := testClient.readMessageToClient() - assert.Equal(t, expectedMessage, actualMessage) - }) -} - -func NewTestGraphQLWSWriteEventHandler(testClient subscription.TransportClient) GraphQLWSWriteEventHandler { - return GraphQLWSWriteEventHandler{ - logger: abstractlogger.Noop{}, - Writer: GraphQLWSMessageWriter{ - logger: abstractlogger.Noop{}, - mu: &sync.Mutex{}, - Client: testClient, - }, - } -} - -func NewTestProtocolGraphQLWSHandler(testClient subscription.TransportClient) *ProtocolGraphQLWSHandler { - return &ProtocolGraphQLWSHandler{ - logger: abstractlogger.Noop{}, - reader: GraphQLWSMessageReader{ - logger: abstractlogger.Noop{}, - }, - writeEventHandler: NewTestGraphQLWSWriteEventHandler(testClient), - keepAliveInterval: 30, - } -} diff --git a/pkg/testing/federationtesting/accounts/gqlgen.yml b/pkg/testing/federationtesting/accounts/gqlgen.yml deleted file mode 100644 index 8796f5679..000000000 --- a/pkg/testing/federationtesting/accounts/gqlgen.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Where are all the schema files located? globs are supported eg src/**/*.graphqls -schema: - - graph/*.graphqls - -# Where should the generated server code go? -exec: - filename: graph/generated/generated.go - package: generated - -federation: - filename: graph/generated/federation.go - package: generated - -# Where should any generated models go? -model: - filename: graph/model/models_gen.go - package: model - -# Where should the resolver implementations go? -resolver: - layout: follow-schema - dir: graph - package: graph - -# Optional: turn on use `gqlgen:"fieldName"` tags in your models -# struct_tag: json - -# Optional: turn on to use []Thing instead of []*Thing -# omit_slice_element_pointers: false - -# Optional: set to speed up generation time by not performing a final validation pass. -# skip_validation: true - -# gqlgen will search for any type names in the schema in these go packages -# if they match it will use them, otherwise it will generate them. -#autobind: -# - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" - -# This section declares type mapping between the GraphQL and go type systems -# -# The first line in each type will be used as defaults for resolver arguments and -# modelgen, the others will be allowed when binding to fields. Configure them to -# your liking -models: - ID: - model: - - github.com/99designs/gqlgen/graphql.ID - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 - Int: - model: - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 diff --git a/pkg/testing/federationtesting/accounts/graph/entity.resolvers.go b/pkg/testing/federationtesting/accounts/graph/entity.resolvers.go deleted file mode 100644 index 29d10cd41..000000000 --- a/pkg/testing/federationtesting/accounts/graph/entity.resolvers.go +++ /dev/null @@ -1,31 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.22 - -import ( - "context" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/generated" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" -) - -// FindUserByID is the resolver for the findUserByID field. -func (r *entityResolver) FindUserByID(ctx context.Context, id string) (*model.User, error) { - name := "User " + id - if id == "1234" { - name = "Me" - } - - return &model.User{ - ID: id, - Username: name, - History: histories, - }, nil -} - -// Entity returns generated.EntityResolver implementation. -func (r *Resolver) Entity() generated.EntityResolver { return &entityResolver{r} } - -type entityResolver struct{ *Resolver } diff --git a/pkg/testing/federationtesting/accounts/graph/generated/federation.go b/pkg/testing/federationtesting/accounts/graph/generated/federation.go deleted file mode 100644 index 49d54ae0d..000000000 --- a/pkg/testing/federationtesting/accounts/graph/generated/federation.go +++ /dev/null @@ -1,187 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package generated - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - - "github.com/99designs/gqlgen/plugin/federation/fedruntime" -) - -var ( - ErrUnknownType = errors.New("unknown type") - ErrTypeNotFound = errors.New("type not found") -) - -func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) { - if ec.DisableIntrospection { - return fedruntime.Service{}, errors.New("federated introspection disabled") - } - - var sdl []string - - for _, src := range sources { - if src.BuiltIn { - continue - } - sdl = append(sdl, src.Input) - } - - return fedruntime.Service{ - SDL: strings.Join(sdl, "\n"), - }, nil -} - -func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) []fedruntime.Entity { - list := make([]fedruntime.Entity, len(representations)) - - repsMap := map[string]struct { - i []int - r []map[string]interface{} - }{} - - // We group entities by typename so that we can parallelize their resolution. - // This is particularly helpful when there are entity groups in multi mode. - buildRepresentationGroups := func(reps []map[string]interface{}) { - for i, rep := range reps { - typeName, ok := rep["__typename"].(string) - if !ok { - // If there is no __typename, we just skip the representation; - // we just won't be resolving these unknown types. - ec.Error(ctx, errors.New("__typename must be an existing string")) - continue - } - - _r := repsMap[typeName] - _r.i = append(_r.i, i) - _r.r = append(_r.r, rep) - repsMap[typeName] = _r - } - } - - isMulti := func(typeName string) bool { - switch typeName { - default: - return false - } - } - - resolveEntity := func(ctx context.Context, typeName string, rep map[string]interface{}, idx []int, i int) (err error) { - // we need to do our own panic handling, because we may be called in a - // goroutine, where the usual panic handling can't catch us - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - } - }() - - switch typeName { - case "User": - resolverName, err := entityResolverNameForUser(ctx, rep) - if err != nil { - return fmt.Errorf(`finding resolver for Entity "User": %w`, err) - } - switch resolverName { - - case "findUserByID": - id0, err := ec.unmarshalNID2string(ctx, rep["id"]) - if err != nil { - return fmt.Errorf(`unmarshalling param 0 for findUserByID(): %w`, err) - } - entity, err := ec.resolvers.Entity().FindUserByID(ctx, id0) - if err != nil { - return fmt.Errorf(`resolving Entity "User": %w`, err) - } - - list[idx[i]] = entity - return nil - } - - } - return fmt.Errorf("%w: %s", ErrUnknownType, typeName) - } - - resolveManyEntities := func(ctx context.Context, typeName string, reps []map[string]interface{}, idx []int) (err error) { - // we need to do our own panic handling, because we may be called in a - // goroutine, where the usual panic handling can't catch us - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - } - }() - - switch typeName { - - default: - return errors.New("unknown type: " + typeName) - } - } - - resolveEntityGroup := func(typeName string, reps []map[string]interface{}, idx []int) { - if isMulti(typeName) { - err := resolveManyEntities(ctx, typeName, reps, idx) - if err != nil { - ec.Error(ctx, err) - } - } else { - // if there are multiple entities to resolve, parallelize (similar to - // graphql.FieldSet.Dispatch) - var e sync.WaitGroup - e.Add(len(reps)) - for i, rep := range reps { - i, rep := i, rep - go func(i int, rep map[string]interface{}) { - err := resolveEntity(ctx, typeName, rep, idx, i) - if err != nil { - ec.Error(ctx, err) - } - e.Done() - }(i, rep) - } - e.Wait() - } - } - buildRepresentationGroups(representations) - - switch len(repsMap) { - case 0: - return list - case 1: - for typeName, reps := range repsMap { - resolveEntityGroup(typeName, reps.r, reps.i) - } - return list - default: - var g sync.WaitGroup - g.Add(len(repsMap)) - for typeName, reps := range repsMap { - go func(typeName string, reps []map[string]interface{}, idx []int) { - resolveEntityGroup(typeName, reps, idx) - g.Done() - }(typeName, reps.r, reps.i) - } - g.Wait() - return list - } -} - -func entityResolverNameForUser(ctx context.Context, rep map[string]interface{}) (string, error) { - for { - var ( - m map[string]interface{} - val interface{} - ok bool - ) - _ = val - m = rep - if _, ok = m["id"]; !ok { - break - } - return "findUserByID", nil - } - return "", fmt.Errorf("%w for User", ErrTypeNotFound) -} diff --git a/pkg/testing/federationtesting/accounts/graph/generated/generated.go b/pkg/testing/federationtesting/accounts/graph/generated/generated.go deleted file mode 100644 index b5b5c25af..000000000 --- a/pkg/testing/federationtesting/accounts/graph/generated/generated.go +++ /dev/null @@ -1,5456 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package generated - -import ( - "bytes" - "context" - "errors" - "fmt" - "strconv" - "sync" - "sync/atomic" - - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/introspection" - "github.com/99designs/gqlgen/plugin/federation/fedruntime" - gqlparser "github.com/vektah/gqlparser/v2" - "github.com/vektah/gqlparser/v2/ast" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" -) - -// region ************************** generated!.gotpl ************************** - -// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. -func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { - return &executableSchema{ - resolvers: cfg.Resolvers, - directives: cfg.Directives, - complexity: cfg.Complexity, - } -} - -type Config struct { - Resolvers ResolverRoot - Directives DirectiveRoot - Complexity ComplexityRoot -} - -type ResolverRoot interface { - Entity() EntityResolver - Query() QueryResolver -} - -type DirectiveRoot struct { -} - -type ComplexityRoot struct { - Cat struct { - Name func(childComplexity int) int - } - - Entity struct { - FindUserByID func(childComplexity int, id string) int - } - - Product struct { - Upc func(childComplexity int) int - } - - Purchase struct { - Product func(childComplexity int) int - Quantity func(childComplexity int) int - Wallet func(childComplexity int) int - } - - Query struct { - Cat func(childComplexity int) int - Histories func(childComplexity int) int - Identifiable func(childComplexity int) int - Me func(childComplexity int) int - __resolve__service func(childComplexity int) int - __resolve_entities func(childComplexity int, representations []map[string]interface{}) int - } - - Sale struct { - Location func(childComplexity int) int - Product func(childComplexity int) int - Rating func(childComplexity int) int - } - - User struct { - History func(childComplexity int) int - ID func(childComplexity int) int - RealName func(childComplexity int) int - Username func(childComplexity int) int - } - - WalletType1 struct { - Amount func(childComplexity int) int - Currency func(childComplexity int) int - SpecialField1 func(childComplexity int) int - } - - WalletType2 struct { - Amount func(childComplexity int) int - Currency func(childComplexity int) int - SpecialField2 func(childComplexity int) int - } - - _Service struct { - SDL func(childComplexity int) int - } -} - -type EntityResolver interface { - FindUserByID(ctx context.Context, id string) (*model.User, error) -} -type QueryResolver interface { - Me(ctx context.Context) (*model.User, error) - Identifiable(ctx context.Context) (model.Identifiable, error) - Histories(ctx context.Context) ([]model.History, error) - Cat(ctx context.Context) (*model.Cat, error) -} - -type executableSchema struct { - resolvers ResolverRoot - directives DirectiveRoot - complexity ComplexityRoot -} - -func (e *executableSchema) Schema() *ast.Schema { - return parsedSchema -} - -func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { - ec := executionContext{nil, e} - _ = ec - switch typeName + "." + field { - - case "Cat.name": - if e.complexity.Cat.Name == nil { - break - } - - return e.complexity.Cat.Name(childComplexity), true - - case "Entity.findUserByID": - if e.complexity.Entity.FindUserByID == nil { - break - } - - args, err := ec.field_Entity_findUserByID_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Entity.FindUserByID(childComplexity, args["id"].(string)), true - - case "Product.upc": - if e.complexity.Product.Upc == nil { - break - } - - return e.complexity.Product.Upc(childComplexity), true - - case "Purchase.product": - if e.complexity.Purchase.Product == nil { - break - } - - return e.complexity.Purchase.Product(childComplexity), true - - case "Purchase.quantity": - if e.complexity.Purchase.Quantity == nil { - break - } - - return e.complexity.Purchase.Quantity(childComplexity), true - - case "Purchase.wallet": - if e.complexity.Purchase.Wallet == nil { - break - } - - return e.complexity.Purchase.Wallet(childComplexity), true - - case "Query.cat": - if e.complexity.Query.Cat == nil { - break - } - - return e.complexity.Query.Cat(childComplexity), true - - case "Query.histories": - if e.complexity.Query.Histories == nil { - break - } - - return e.complexity.Query.Histories(childComplexity), true - - case "Query.identifiable": - if e.complexity.Query.Identifiable == nil { - break - } - - return e.complexity.Query.Identifiable(childComplexity), true - - case "Query.me": - if e.complexity.Query.Me == nil { - break - } - - return e.complexity.Query.Me(childComplexity), true - - case "Query._service": - if e.complexity.Query.__resolve__service == nil { - break - } - - return e.complexity.Query.__resolve__service(childComplexity), true - - case "Query._entities": - if e.complexity.Query.__resolve_entities == nil { - break - } - - args, err := ec.field_Query__entities_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Query.__resolve_entities(childComplexity, args["representations"].([]map[string]interface{})), true - - case "Sale.location": - if e.complexity.Sale.Location == nil { - break - } - - return e.complexity.Sale.Location(childComplexity), true - - case "Sale.product": - if e.complexity.Sale.Product == nil { - break - } - - return e.complexity.Sale.Product(childComplexity), true - - case "Sale.rating": - if e.complexity.Sale.Rating == nil { - break - } - - return e.complexity.Sale.Rating(childComplexity), true - - case "User.history": - if e.complexity.User.History == nil { - break - } - - return e.complexity.User.History(childComplexity), true - - case "User.id": - if e.complexity.User.ID == nil { - break - } - - return e.complexity.User.ID(childComplexity), true - - case "User.realName": - if e.complexity.User.RealName == nil { - break - } - - return e.complexity.User.RealName(childComplexity), true - - case "User.username": - if e.complexity.User.Username == nil { - break - } - - return e.complexity.User.Username(childComplexity), true - - case "WalletType1.amount": - if e.complexity.WalletType1.Amount == nil { - break - } - - return e.complexity.WalletType1.Amount(childComplexity), true - - case "WalletType1.currency": - if e.complexity.WalletType1.Currency == nil { - break - } - - return e.complexity.WalletType1.Currency(childComplexity), true - - case "WalletType1.specialField1": - if e.complexity.WalletType1.SpecialField1 == nil { - break - } - - return e.complexity.WalletType1.SpecialField1(childComplexity), true - - case "WalletType2.amount": - if e.complexity.WalletType2.Amount == nil { - break - } - - return e.complexity.WalletType2.Amount(childComplexity), true - - case "WalletType2.currency": - if e.complexity.WalletType2.Currency == nil { - break - } - - return e.complexity.WalletType2.Currency(childComplexity), true - - case "WalletType2.specialField2": - if e.complexity.WalletType2.SpecialField2 == nil { - break - } - - return e.complexity.WalletType2.SpecialField2(childComplexity), true - - case "_Service.sdl": - if e.complexity._Service.SDL == nil { - break - } - - return e.complexity._Service.SDL(childComplexity), true - - } - return 0, false -} - -func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { - rc := graphql.GetOperationContext(ctx) - ec := executionContext{rc, e} - inputUnmarshalMap := graphql.BuildUnmarshalerMap() - first := true - - switch rc.Operation.Operation { - case ast.Query: - return func(ctx context.Context) *graphql.Response { - if !first { - return nil - } - first = false - ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Query(ctx, rc.Operation.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - - default: - return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) - } -} - -type executionContext struct { - *graphql.OperationContext - *executableSchema -} - -func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapSchema(parsedSchema), nil -} - -func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil -} - -var sources = []*ast.Source{ - {Name: "../schema.graphqls", Input: `extend type Query { - me: User - identifiable: Identifiable - histories: [History] - cat: Cat -} - -type Cat { - name: String! -} - -interface Identifiable { - id: ID! -} - -type User implements Identifiable @key(fields: "id") { - id: ID! - username: String! - history: [History!]! - realName: String! -} - -extend type Product @key(fields: "upc") { - upc: String! @external -} - -union History = Purchase | Sale - -interface Info { - quantity: Int! -} - -type Purchase implements Info { - product: Product! - wallet: Wallet - quantity: Int! -} - -interface Store { - location: String! -} - -type Sale implements Store { - product: Product! - rating: Int! - location: String! -} - -interface Wallet { - currency: String! - amount: Float! -} - -type WalletType1 implements Wallet { - currency: String! - amount: Float! - specialField1: String! -} - -type WalletType2 implements Wallet { - currency: String! - amount: Float! - specialField2: String! -}`, BuiltIn: false}, - {Name: "../../federation/directives.graphql", Input: ` - scalar _Any - scalar _FieldSet - - directive @external on FIELD_DEFINITION - directive @requires(fields: _FieldSet!) on FIELD_DEFINITION - directive @provides(fields: _FieldSet!) on FIELD_DEFINITION - directive @extends on OBJECT | INTERFACE - - directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE -`, BuiltIn: true}, - {Name: "../../federation/entity.graphql", Input: ` -# a union of all types that use the @key directive -union _Entity = Product | User - -# fake type to build resolver interfaces for users to implement -type Entity { - findUserByID(id: ID!,): User! - -} - -type _Service { - sdl: String -} - -extend type Query { - _entities(representations: [_Any!]!): [_Entity]! - _service: _Service! -} -`, BuiltIn: true}, -} -var parsedSchema = gqlparser.MustLoadSchema(sources...) - -// endregion ************************** generated!.gotpl ************************** - -// region ***************************** args.gotpl ***************************** - -func (ec *executionContext) field_Entity_findUserByID_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["id"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["name"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query__entities_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 []map[string]interface{} - if tmp, ok := rawArgs["representations"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("representations")) - arg0, err = ec.unmarshalN_Any2ᚕmapᚄ(ctx, tmp) - if err != nil { - return nil, err - } - } - args["representations"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -// endregion ***************************** args.gotpl ***************************** - -// region ************************** directives.gotpl ************************** - -// endregion ************************** directives.gotpl ************************** - -// region **************************** field.gotpl ***************************** - -func (ec *executionContext) _Cat_name(ctx context.Context, field graphql.CollectedField, obj *model.Cat) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Cat_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Cat_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Cat", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Entity_findUserByID(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Entity_findUserByID(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Entity().FindUserByID(rctx, fc.Args["id"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Entity_findUserByID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Entity", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "history": - return ec.fieldContext_User_history(ctx, field) - case "realName": - return ec.fieldContext_User_realName(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Entity_findUserByID_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Product_upc(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_upc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Upc, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_upc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Purchase_product(ctx context.Context, field graphql.CollectedField, obj *model.Purchase) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Purchase_product(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Product, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Product) - fc.Result = res - return ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Purchase_product(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Purchase", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Purchase_wallet(ctx context.Context, field graphql.CollectedField, obj *model.Purchase) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Purchase_wallet(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Wallet, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(model.Wallet) - fc.Result = res - return ec.marshalOWallet2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐWallet(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Purchase_wallet(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Purchase", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") - }, - } - return fc, nil -} - -func (ec *executionContext) _Purchase_quantity(ctx context.Context, field graphql.CollectedField, obj *model.Purchase) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Purchase_quantity(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Quantity, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(int) - fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Purchase_quantity(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Purchase", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_me(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_me(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Me(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalOUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_me(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "history": - return ec.fieldContext_User_history(ctx, field) - case "realName": - return ec.fieldContext_User_realName(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_identifiable(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_identifiable(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Identifiable(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(model.Identifiable) - fc.Result = res - return ec.marshalOIdentifiable2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐIdentifiable(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_identifiable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_histories(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_histories(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Histories(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]model.History) - fc.Result = res - return ec.marshalOHistory2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistory(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_histories(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type History does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_cat(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_cat(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Cat(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*model.Cat) - fc.Result = res - return ec.marshalOCat2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐCat(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_cat(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext_Cat_name(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Cat", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query__entities(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__entities(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.__resolve_entities(ctx, fc.Args["representations"].([]map[string]interface{})), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]fedruntime.Entity) - fc.Result = res - return ec.marshalN_Entity2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__entities(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type _Entity does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__entities_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query__service(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__service(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.__resolve__service(ctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(fedruntime.Service) - fc.Result = res - return ec.marshalN_Service2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐService(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__service(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "sdl": - return ec.fieldContext__Service_sdl(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type _Service", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectType(fc.Args["name"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___schema(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectSchema() - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Schema) - fc.Result = res - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "description": - return ec.fieldContext___Schema_description(ctx, field) - case "types": - return ec.fieldContext___Schema_types(ctx, field) - case "queryType": - return ec.fieldContext___Schema_queryType(ctx, field) - case "mutationType": - return ec.fieldContext___Schema_mutationType(ctx, field) - case "subscriptionType": - return ec.fieldContext___Schema_subscriptionType(ctx, field) - case "directives": - return ec.fieldContext___Schema_directives(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Sale_product(ctx context.Context, field graphql.CollectedField, obj *model.Sale) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Sale_product(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Product, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Product) - fc.Result = res - return ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Sale_product(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Sale", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Sale_rating(ctx context.Context, field graphql.CollectedField, obj *model.Sale) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Sale_rating(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Rating, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(int) - fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Sale_rating(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Sale", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Sale_location(ctx context.Context, field graphql.CollectedField, obj *model.Sale) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Sale_location(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Location, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Sale_location(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Sale", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_id(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.ID, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_username(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_username(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Username, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_username(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_history(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_history(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.History, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]model.History) - fc.Result = res - return ec.marshalNHistory2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistoryᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_history(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type History does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_realName(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_realName(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.RealName, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_realName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _WalletType1_currency(ctx context.Context, field graphql.CollectedField, obj *model.WalletType1) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_WalletType1_currency(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Currency, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_WalletType1_currency(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "WalletType1", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _WalletType1_amount(ctx context.Context, field graphql.CollectedField, obj *model.WalletType1) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_WalletType1_amount(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Amount, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(float64) - fc.Result = res - return ec.marshalNFloat2float64(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_WalletType1_amount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "WalletType1", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Float does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _WalletType1_specialField1(ctx context.Context, field graphql.CollectedField, obj *model.WalletType1) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_WalletType1_specialField1(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SpecialField1, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_WalletType1_specialField1(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "WalletType1", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _WalletType2_currency(ctx context.Context, field graphql.CollectedField, obj *model.WalletType2) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_WalletType2_currency(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Currency, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_WalletType2_currency(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "WalletType2", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _WalletType2_amount(ctx context.Context, field graphql.CollectedField, obj *model.WalletType2) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_WalletType2_amount(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Amount, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(float64) - fc.Result = res - return ec.marshalNFloat2float64(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_WalletType2_amount(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "WalletType2", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Float does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _WalletType2_specialField2(ctx context.Context, field graphql.CollectedField, obj *model.WalletType2) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_WalletType2_specialField2(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SpecialField2, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_WalletType2_specialField2(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "WalletType2", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) __Service_sdl(ctx context.Context, field graphql.CollectedField, obj *fedruntime.Service) (ret graphql.Marshaler) { - fc, err := ec.fieldContext__Service_sdl(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SDL, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalOString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext__Service_sdl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "_Service", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_locations(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Locations, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]string) - fc.Result = res - return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __DirectiveLocation does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsRepeatable, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_types(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Types(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_queryType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.QueryType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_mutationType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.MutationType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SubscriptionType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_directives(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Directives(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Directive) - fc.Result = res - return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Directive_name(ctx, field) - case "description": - return ec.fieldContext___Directive_description(ctx, field) - case "locations": - return ec.fieldContext___Directive_locations(ctx, field) - case "args": - return ec.fieldContext___Directive_args(ctx, field) - case "isRepeatable": - return ec.fieldContext___Directive_isRepeatable(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_kind(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Kind(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalN__TypeKind2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __TypeKind does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_fields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Field) - fc.Result = res - return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Field_name(ctx, field) - case "description": - return ec.fieldContext___Field_description(ctx, field) - case "args": - return ec.fieldContext___Field_args(ctx, field) - case "type": - return ec.fieldContext___Field_type(ctx, field) - case "isDeprecated": - return ec.fieldContext___Field_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___Field_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_interfaces(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Interfaces(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_possibleTypes(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.PossibleTypes(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_enumValues(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.EnumValue) - fc.Result = res - return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___EnumValue_name(ctx, field) - case "description": - return ec.fieldContext___EnumValue_description(ctx, field) - case "isDeprecated": - return ec.fieldContext___EnumValue_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___EnumValue_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_inputFields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.InputFields(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_ofType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.OfType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SpecifiedByURL(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -// endregion **************************** field.gotpl ***************************** - -// region **************************** input.gotpl ***************************** - -// endregion **************************** input.gotpl ***************************** - -// region ************************** interface.gotpl *************************** - -func (ec *executionContext) _History(ctx context.Context, sel ast.SelectionSet, obj model.History) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Purchase: - return ec._Purchase(ctx, sel, &obj) - case *model.Purchase: - if obj == nil { - return graphql.Null - } - return ec._Purchase(ctx, sel, obj) - case model.Sale: - return ec._Sale(ctx, sel, &obj) - case *model.Sale: - if obj == nil { - return graphql.Null - } - return ec._Sale(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) _Identifiable(ctx context.Context, sel ast.SelectionSet, obj model.Identifiable) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.User: - return ec._User(ctx, sel, &obj) - case *model.User: - if obj == nil { - return graphql.Null - } - return ec._User(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) _Info(ctx context.Context, sel ast.SelectionSet, obj model.Info) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Purchase: - return ec._Purchase(ctx, sel, &obj) - case *model.Purchase: - if obj == nil { - return graphql.Null - } - return ec._Purchase(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) _Store(ctx context.Context, sel ast.SelectionSet, obj model.Store) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Sale: - return ec._Sale(ctx, sel, &obj) - case *model.Sale: - if obj == nil { - return graphql.Null - } - return ec._Sale(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) _Wallet(ctx context.Context, sel ast.SelectionSet, obj model.Wallet) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.WalletType1: - return ec._WalletType1(ctx, sel, &obj) - case *model.WalletType1: - if obj == nil { - return graphql.Null - } - return ec._WalletType1(ctx, sel, obj) - case model.WalletType2: - return ec._WalletType2(ctx, sel, &obj) - case *model.WalletType2: - if obj == nil { - return graphql.Null - } - return ec._WalletType2(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, obj fedruntime.Entity) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Product: - return ec._Product(ctx, sel, &obj) - case *model.Product: - if obj == nil { - return graphql.Null - } - return ec._Product(ctx, sel, obj) - case model.User: - return ec._User(ctx, sel, &obj) - case *model.User: - if obj == nil { - return graphql.Null - } - return ec._User(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -// endregion ************************** interface.gotpl *************************** - -// region **************************** object.gotpl **************************** - -var catImplementors = []string{"Cat"} - -func (ec *executionContext) _Cat(ctx context.Context, sel ast.SelectionSet, obj *model.Cat) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, catImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Cat") - case "name": - - out.Values[i] = ec._Cat_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var entityImplementors = []string{"Entity"} - -func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, entityImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Entity", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Entity") - case "findUserByID": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Entity_findUserByID(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var productImplementors = []string{"Product", "_Entity"} - -func (ec *executionContext) _Product(ctx context.Context, sel ast.SelectionSet, obj *model.Product) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, productImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Product") - case "upc": - - out.Values[i] = ec._Product_upc(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var purchaseImplementors = []string{"Purchase", "History", "Info"} - -func (ec *executionContext) _Purchase(ctx context.Context, sel ast.SelectionSet, obj *model.Purchase) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, purchaseImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Purchase") - case "product": - - out.Values[i] = ec._Purchase_product(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "wallet": - - out.Values[i] = ec._Purchase_wallet(ctx, field, obj) - - case "quantity": - - out.Values[i] = ec._Purchase_quantity(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var queryImplementors = []string{"Query"} - -func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Query", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Query") - case "me": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_me(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "identifiable": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_identifiable(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "histories": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_histories(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "cat": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_cat(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "_entities": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query__entities(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "_service": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query__service(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "__type": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___type(ctx, field) - }) - - case "__schema": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___schema(ctx, field) - }) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var saleImplementors = []string{"Sale", "History", "Store"} - -func (ec *executionContext) _Sale(ctx context.Context, sel ast.SelectionSet, obj *model.Sale) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, saleImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Sale") - case "product": - - out.Values[i] = ec._Sale_product(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "rating": - - out.Values[i] = ec._Sale_rating(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "location": - - out.Values[i] = ec._Sale_location(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var userImplementors = []string{"User", "Identifiable", "_Entity"} - -func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *model.User) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("User") - case "id": - - out.Values[i] = ec._User_id(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "username": - - out.Values[i] = ec._User_username(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "history": - - out.Values[i] = ec._User_history(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "realName": - - out.Values[i] = ec._User_realName(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var walletType1Implementors = []string{"WalletType1", "Wallet"} - -func (ec *executionContext) _WalletType1(ctx context.Context, sel ast.SelectionSet, obj *model.WalletType1) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, walletType1Implementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("WalletType1") - case "currency": - - out.Values[i] = ec._WalletType1_currency(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "amount": - - out.Values[i] = ec._WalletType1_amount(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "specialField1": - - out.Values[i] = ec._WalletType1_specialField1(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var walletType2Implementors = []string{"WalletType2", "Wallet"} - -func (ec *executionContext) _WalletType2(ctx context.Context, sel ast.SelectionSet, obj *model.WalletType2) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, walletType2Implementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("WalletType2") - case "currency": - - out.Values[i] = ec._WalletType2_currency(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "amount": - - out.Values[i] = ec._WalletType2_amount(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "specialField2": - - out.Values[i] = ec._WalletType2_specialField2(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var _ServiceImplementors = []string{"_Service"} - -func (ec *executionContext) __Service(ctx context.Context, sel ast.SelectionSet, obj *fedruntime.Service) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, _ServiceImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("_Service") - case "sdl": - - out.Values[i] = ec.__Service_sdl(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __DirectiveImplementors = []string{"__Directive"} - -func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Directive") - case "name": - - out.Values[i] = ec.___Directive_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Directive_description(ctx, field, obj) - - case "locations": - - out.Values[i] = ec.___Directive_locations(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "args": - - out.Values[i] = ec.___Directive_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isRepeatable": - - out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __EnumValueImplementors = []string{"__EnumValue"} - -func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__EnumValue") - case "name": - - out.Values[i] = ec.___EnumValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___EnumValue_description(ctx, field, obj) - - case "isDeprecated": - - out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __FieldImplementors = []string{"__Field"} - -func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Field") - case "name": - - out.Values[i] = ec.___Field_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Field_description(ctx, field, obj) - - case "args": - - out.Values[i] = ec.___Field_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "type": - - out.Values[i] = ec.___Field_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isDeprecated": - - out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __InputValueImplementors = []string{"__InputValue"} - -func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__InputValue") - case "name": - - out.Values[i] = ec.___InputValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___InputValue_description(ctx, field, obj) - - case "type": - - out.Values[i] = ec.___InputValue_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "defaultValue": - - out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __SchemaImplementors = []string{"__Schema"} - -func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Schema") - case "description": - - out.Values[i] = ec.___Schema_description(ctx, field, obj) - - case "types": - - out.Values[i] = ec.___Schema_types(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "queryType": - - out.Values[i] = ec.___Schema_queryType(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "mutationType": - - out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) - - case "subscriptionType": - - out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) - - case "directives": - - out.Values[i] = ec.___Schema_directives(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __TypeImplementors = []string{"__Type"} - -func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Type") - case "kind": - - out.Values[i] = ec.___Type_kind(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "name": - - out.Values[i] = ec.___Type_name(ctx, field, obj) - - case "description": - - out.Values[i] = ec.___Type_description(ctx, field, obj) - - case "fields": - - out.Values[i] = ec.___Type_fields(ctx, field, obj) - - case "interfaces": - - out.Values[i] = ec.___Type_interfaces(ctx, field, obj) - - case "possibleTypes": - - out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) - - case "enumValues": - - out.Values[i] = ec.___Type_enumValues(ctx, field, obj) - - case "inputFields": - - out.Values[i] = ec.___Type_inputFields(ctx, field, obj) - - case "ofType": - - out.Values[i] = ec.___Type_ofType(ctx, field, obj) - - case "specifiedByURL": - - out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -// endregion **************************** object.gotpl **************************** - -// region ***************************** type.gotpl ***************************** - -func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { - res, err := graphql.UnmarshalFloatContext(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.SelectionSet, v float64) graphql.Marshaler { - res := graphql.MarshalFloatContext(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return graphql.WrapContextMarshaler(ctx, res) -} - -func (ec *executionContext) marshalNHistory2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistory(ctx context.Context, sel ast.SelectionSet, v model.History) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._History(ctx, sel, v) -} - -func (ec *executionContext) marshalNHistory2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistoryᚄ(ctx context.Context, sel ast.SelectionSet, v []model.History) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNHistory2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistory(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalID(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalID(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { - res, err := graphql.UnmarshalInt(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { - res := graphql.MarshalInt(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v *model.Product) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._Product(ctx, sel, v) -} - -func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalNUser2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler { - return ec._User(ctx, sel, &v) -} - -func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._User(ctx, sel, v) -} - -func (ec *executionContext) unmarshalN_Any2map(ctx context.Context, v interface{}) (map[string]interface{}, error) { - res, err := graphql.UnmarshalMap(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN_Any2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - res := graphql.MarshalMap(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN_Any2ᚕmapᚄ(ctx context.Context, v interface{}) ([]map[string]interface{}, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]map[string]interface{}, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN_Any2map(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN_Any2ᚕmapᚄ(ctx context.Context, sel ast.SelectionSet, v []map[string]interface{}) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - for i := range v { - ret[i] = ec.marshalN_Any2map(ctx, sel, v[i]) - } - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN_Entity2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx context.Context, sel ast.SelectionSet, v []fedruntime.Entity) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalO_Entity2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) unmarshalN_FieldSet2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN_FieldSet2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalN_Service2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐService(ctx context.Context, sel ast.SelectionSet, v fedruntime.Service) graphql.Marshaler { - return ec.__Service(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { - return ec.___Directive(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]string, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { - return ec.___EnumValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { - return ec.___Field(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { - return ec.___InputValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { - return ec.___Type(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - return res -} - -func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalBoolean(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalBoolean(*v) - return res -} - -func (ec *executionContext) marshalOCat2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐCat(ctx context.Context, sel ast.SelectionSet, v *model.Cat) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Cat(ctx, sel, v) -} - -func (ec *executionContext) marshalOHistory2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistory(ctx context.Context, sel ast.SelectionSet, v model.History) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._History(ctx, sel, v) -} - -func (ec *executionContext) marshalOHistory2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistory(ctx context.Context, sel ast.SelectionSet, v []model.History) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalOHistory2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐHistory(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) marshalOIdentifiable2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐIdentifiable(ctx context.Context, sel ast.SelectionSet, v model.Identifiable) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Identifiable(ctx, sel, v) -} - -func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - return res -} - -func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalString(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalString(*v) - return res -} - -func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._User(ctx, sel, v) -} - -func (ec *executionContext) marshalOWallet2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋaccountsᚋgraphᚋmodelᚐWallet(ctx context.Context, sel ast.SelectionSet, v model.Wallet) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Wallet(ctx, sel, v) -} - -func (ec *executionContext) marshalO_Entity2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx context.Context, sel ast.SelectionSet, v fedruntime.Entity) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.__Entity(ctx, sel, v) -} - -func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Schema(ctx, sel, v) -} - -func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -// endregion ***************************** type.gotpl ***************************** diff --git a/pkg/testing/federationtesting/accounts/graph/handler.go b/pkg/testing/federationtesting/accounts/graph/handler.go deleted file mode 100644 index 0a9b43851..000000000 --- a/pkg/testing/federationtesting/accounts/graph/handler.go +++ /dev/null @@ -1,31 +0,0 @@ -package graph - -import ( - "net/http" - - "github.com/99designs/gqlgen/graphql/handler" - "github.com/99designs/gqlgen/graphql/handler/debug" - "github.com/99designs/gqlgen/graphql/handler/extension" - "github.com/99designs/gqlgen/graphql/handler/transport" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/generated" -) - -type EndpointOptions struct { - EnableDebug bool -} - -var TestOptions = EndpointOptions{ - EnableDebug: false, -} - -func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { - srv := handler.New(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) - srv.AddTransport(transport.POST{}) - srv.Use(extension.Introspection{}) - if opts.EnableDebug { - srv.Use(&debug.Tracer{}) - } - - return srv -} diff --git a/pkg/testing/federationtesting/accounts/graph/histories.go b/pkg/testing/federationtesting/accounts/graph/histories.go deleted file mode 100644 index de47d5e3a..000000000 --- a/pkg/testing/federationtesting/accounts/graph/histories.go +++ /dev/null @@ -1,56 +0,0 @@ -package graph - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" -) - -var histories = []model.History{ - &model.Purchase{ - Product: &model.Product{Upc: "top-1"}, - Wallet: walletOne, - Quantity: 1, - }, - &model.Sale{ - Product: &model.Product{Upc: "top-2"}, - Rating: 5, - Location: "Germany", - }, - &model.Purchase{ - Product: &model.Product{Upc: "top-3"}, - Wallet: walletTwo, - Quantity: 3, - }, -} - -var allHistories = []model.History{ - &model.Purchase{ - Product: &model.Product{Upc: "top-1"}, - Wallet: walletOne, - Quantity: 1, - }, - &model.Sale{ - Product: &model.Product{Upc: "top-1"}, - Rating: 1, - Location: "Germany", - }, - &model.Purchase{ - Product: &model.Product{Upc: "top-2"}, - Wallet: walletTwo, - Quantity: 2, - }, - &model.Sale{ - Product: &model.Product{Upc: "top-2"}, - Rating: 2, - Location: "UK", - }, - &model.Purchase{ - Product: &model.Product{Upc: "top-3"}, - Wallet: walletTwo, - Quantity: 3, - }, - &model.Sale{ - Product: &model.Product{Upc: "top-3"}, - Rating: 3, - Location: "Ukraine", - }, -} diff --git a/pkg/testing/federationtesting/accounts/graph/model/models_gen.go b/pkg/testing/federationtesting/accounts/graph/model/models_gen.go deleted file mode 100644 index 97d109395..000000000 --- a/pkg/testing/federationtesting/accounts/graph/model/models_gen.go +++ /dev/null @@ -1,92 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package model - -type History interface { - IsHistory() -} - -type Identifiable interface { - IsIdentifiable() - GetID() string -} - -type Info interface { - IsInfo() - GetQuantity() int -} - -type Store interface { - IsStore() - GetLocation() string -} - -type Wallet interface { - IsWallet() - GetCurrency() string - GetAmount() float64 -} - -type Cat struct { - Name string `json:"name"` -} - -type Product struct { - Upc string `json:"upc"` -} - -func (Product) IsEntity() {} - -type Purchase struct { - Product *Product `json:"product"` - Wallet Wallet `json:"wallet"` - Quantity int `json:"quantity"` -} - -func (Purchase) IsHistory() {} - -func (Purchase) IsInfo() {} -func (this Purchase) GetQuantity() int { return this.Quantity } - -type Sale struct { - Product *Product `json:"product"` - Rating int `json:"rating"` - Location string `json:"location"` -} - -func (Sale) IsHistory() {} - -func (Sale) IsStore() {} -func (this Sale) GetLocation() string { return this.Location } - -type User struct { - ID string `json:"id"` - Username string `json:"username"` - History []History `json:"history"` - RealName string `json:"realName"` -} - -func (User) IsIdentifiable() {} -func (this User) GetID() string { return this.ID } - -func (User) IsEntity() {} - -type WalletType1 struct { - Currency string `json:"currency"` - Amount float64 `json:"amount"` - SpecialField1 string `json:"specialField1"` -} - -func (WalletType1) IsWallet() {} -func (this WalletType1) GetCurrency() string { return this.Currency } -func (this WalletType1) GetAmount() float64 { return this.Amount } - -type WalletType2 struct { - Currency string `json:"currency"` - Amount float64 `json:"amount"` - SpecialField2 string `json:"specialField2"` -} - -func (WalletType2) IsWallet() {} -func (this WalletType2) GetCurrency() string { return this.Currency } -func (this WalletType2) GetAmount() float64 { return this.Amount } diff --git a/pkg/testing/federationtesting/accounts/graph/resolver.go b/pkg/testing/federationtesting/accounts/graph/resolver.go deleted file mode 100644 index 278fb7db6..000000000 --- a/pkg/testing/federationtesting/accounts/graph/resolver.go +++ /dev/null @@ -1,6 +0,0 @@ -// This file will not be regenerated automatically. -// -// It serves as dependency injection for your app, add any dependencies you require here. -package graph - -type Resolver struct{} diff --git a/pkg/testing/federationtesting/accounts/graph/schema.graphqls b/pkg/testing/federationtesting/accounts/graph/schema.graphqls deleted file mode 100644 index b10fb442d..000000000 --- a/pkg/testing/federationtesting/accounts/graph/schema.graphqls +++ /dev/null @@ -1,64 +0,0 @@ -extend type Query { - me: User - identifiable: Identifiable - histories: [History] - cat: Cat -} - -type Cat { - name: String! -} - -interface Identifiable { - id: ID! -} - -type User implements Identifiable @key(fields: "id") { - id: ID! - username: String! - history: [History!]! - realName: String! -} - -extend type Product @key(fields: "upc") { - upc: String! @external -} - -union History = Purchase | Sale - -interface Info { - quantity: Int! -} - -type Purchase implements Info { - product: Product! - wallet: Wallet - quantity: Int! -} - -interface Store { - location: String! -} - -type Sale implements Store { - product: Product! - rating: Int! - location: String! -} - -interface Wallet { - currency: String! - amount: Float! -} - -type WalletType1 implements Wallet { - currency: String! - amount: Float! - specialField1: String! -} - -type WalletType2 implements Wallet { - currency: String! - amount: Float! - specialField2: String! -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/accounts/graph/schema.resolvers.go b/pkg/testing/federationtesting/accounts/graph/schema.resolvers.go deleted file mode 100644 index 3acd3f6da..000000000 --- a/pkg/testing/federationtesting/accounts/graph/schema.resolvers.go +++ /dev/null @@ -1,49 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.22 - -import ( - "context" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/generated" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" -) - -// Me is the resolver for the me field. -func (r *queryResolver) Me(ctx context.Context) (*model.User, error) { - return &model.User{ - ID: "1234", - Username: "Me", - History: histories, - RealName: "User Usington", - }, nil -} - -// Identifiable is the resolver for the identifiable field. -func (r *queryResolver) Identifiable(ctx context.Context) (model.Identifiable, error) { - return &model.User{ - ID: "1234", - Username: "Me", - History: histories, - RealName: "User Usington", - }, nil -} - -// Histories is the resolver for the histories field. -func (r *queryResolver) Histories(ctx context.Context) ([]model.History, error) { - return allHistories, nil -} - -// Cat is the resolver for the cat field. -func (r *queryResolver) Cat(ctx context.Context) (*model.Cat, error) { - return &model.Cat{ - Name: "Pepper", - }, nil -} - -// Query returns generated.QueryResolver implementation. -func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } - -type queryResolver struct{ *Resolver } diff --git a/pkg/testing/federationtesting/accounts/graph/wallets.go b/pkg/testing/federationtesting/accounts/graph/wallets.go deleted file mode 100644 index 8153778a9..000000000 --- a/pkg/testing/federationtesting/accounts/graph/wallets.go +++ /dev/null @@ -1,15 +0,0 @@ -package graph - -import "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph/model" - -var walletOne = &model.WalletType1{ - Currency: "USD", - Amount: 123, - SpecialField1: "some special value 1", -} - -var walletTwo = &model.WalletType2{ - Currency: "USD", - Amount: 123, - SpecialField2: "some special value 2", -} diff --git a/pkg/testing/federationtesting/accounts/handler.go b/pkg/testing/federationtesting/accounts/handler.go deleted file mode 100644 index a844c93ad..000000000 --- a/pkg/testing/federationtesting/accounts/handler.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:generate go run -mod=mod github.com/99designs/gqlgen -package accounts - -import ( - "net/http" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph" -) - -func Handler() http.Handler { - return graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true}) -} diff --git a/pkg/testing/federationtesting/federation_integration_test.go b/pkg/testing/federationtesting/federation_integration_test.go deleted file mode 100644 index 8ea316da8..000000000 --- a/pkg/testing/federationtesting/federation_integration_test.go +++ /dev/null @@ -1,462 +0,0 @@ -//go:build !race - -package federationtesting - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "github.com/jensneuse/abstractlogger" - "github.com/stretchr/testify/assert" - "net/http" - "net/http/httptest" - "path" - "strings" - "testing" - "time" - - accounts "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/accounts/graph" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/gateway" - products "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph" - reviews "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph" -) - -func newFederationSetup() *federationSetup { - accountUpstreamServer := httptest.NewServer(accounts.GraphQLEndpointHandler(accounts.TestOptions)) - productsUpstreamServer := httptest.NewServer(products.GraphQLEndpointHandler(products.TestOptions)) - reviewsUpstreamServer := httptest.NewServer(reviews.GraphQLEndpointHandler(reviews.TestOptions)) - - httpClient := http.DefaultClient - - poller := gateway.NewDatasource([]gateway.ServiceConfig{ - {Name: "accounts", URL: accountUpstreamServer.URL}, - {Name: "products", URL: productsUpstreamServer.URL, WS: strings.ReplaceAll(productsUpstreamServer.URL, "http:", "ws:")}, - {Name: "reviews", URL: reviewsUpstreamServer.URL}, - }, httpClient) - - gtw := gateway.Handler(abstractlogger.NoopLogger, poller, httpClient) - - ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) - defer cancel() - - poller.Run(ctx) - gatewayServer := httptest.NewServer(gtw) - - return &federationSetup{ - accountsUpstreamServer: accountUpstreamServer, - productsUpstreamServer: productsUpstreamServer, - reviewsUpstreamServer: reviewsUpstreamServer, - gatewayServer: gatewayServer, - } -} - -type federationSetup struct { - accountsUpstreamServer *httptest.Server - productsUpstreamServer *httptest.Server - reviewsUpstreamServer *httptest.Server - gatewayServer *httptest.Server -} - -func (f *federationSetup) close() { - f.accountsUpstreamServer.Close() - f.productsUpstreamServer.Close() - f.reviewsUpstreamServer.Close() - f.gatewayServer.Close() -} - -// This tests produces data races in the generated gql code. Disable it when the race -// detector is enabled. -func TestFederationIntegrationTest(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - setup := newFederationSetup() - defer setup.close() - - gqlClient := NewGraphqlClient(http.DefaultClient) - - t.Run("single upstream query operation", func(t *testing.T) { - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/single_upstream.query"), nil, t) - assert.Equal(t, `{"data":{"me":{"id":"1234","username":"Me"}}}`, string(resp)) - }) - - t.Run("query spans multiple federated servers", func(t *testing.T) { - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/multiple_upstream.query"), nil, t) - assert.Equal(t, `{"data":{"topProducts":[{"name":"Trilby","reviews":[{"body":"A highly effective form of birth control.","author":{"username":"Me"}}]},{"name":"Fedora","reviews":[{"body":"Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.","author":{"username":"Me"}}]},{"name":"Boater","reviews":[{"body":"This is the last straw. Hat you will wear. 11/10","author":{"username":"User 7777"}}]}]}}`, string(resp)) - }) - - t.Run("mutation operation with variables", func(t *testing.T) { - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "mutations/mutation_with_variables.query"), queryVariables{ - "authorID": "3210", - "upc": "top-1", - "review": "This is the last straw. Hat you will wear. 11/10", - }, t) - assert.Equal(t, `{"data":{"addReview":{"body":"This is the last straw. Hat you will wear. 11/10","author":{"username":"User 3210"}}}}`, string(resp)) - }) - - t.Run("union query", func(t *testing.T) { - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/union.query"), nil, t) - assert.Equal(t, `{"data":{"me":{"username":"Me","history":[{"__typename":"Purchase","wallet":{"amount":123}},{"__typename":"Sale","rating":5},{"__typename":"Purchase","wallet":{"amount":123}}]}}}`, string(resp)) - }) - - t.Run("interface query", func(t *testing.T) { - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/interface.query"), nil, t) - assert.Equal(t, `{"data":{"me":{"username":"Me","history":[{"wallet":{"amount":123,"specialField1":"some special value 1"}},{"rating":5},{"wallet":{"amount":123,"specialField2":"some special value 2"}}]}}}`, string(resp)) - }) - - t.Run("subscription query through WebSocket transport", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - // Reset the products slice to the original state - defer products.Reset() - - wsAddr := strings.ReplaceAll(setup.gatewayServer.URL, "http://", "ws://") - fmt.Println("setup.gatewayServer.URL", wsAddr) - messages := gqlClient.Subscription(ctx, wsAddr, path.Join("testdata", "subscriptions/subscription.query"), queryVariables{ - "upc": "top-1", - }, t) - - assert.Equal(t, `{"id":"1","type":"data","payload":{"data":{"updateProductPrice":{"upc":"top-1","name":"Trilby","price":1}}}}`, string(<-messages)) - assert.Equal(t, `{"id":"1","type":"data","payload":{"data":{"updateProductPrice":{"upc":"top-1","name":"Trilby","price":2}}}}`, string(<-messages)) - }) - - t.Run("Multiple queries and nested fragments", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/multiple_queries_with_nested_fragments.query"), nil, t) - expected := ` -{ - "data": { - "topProducts": [ - { - "__typename": "Product", - "price": 11, - "upc": "top-1" - }, - { - "__typename": "Product", - "price": 22, - "upc": "top-2" - }, - { - "__typename": "Product", - "price": 33, - "upc": "top-3" - } - ], - "me": { - "__typename": "User", - "id": "1234", - "username": "Me", - "reviews": [ - { - "__typename": "Review", - "product": { - "__typename": "Product", - "price": 11, - "upc": "top-1" - } - }, - { - "__typename": "Review", - "product": { - "__typename": "Product", - "price": 22, - "upc": "top-2" - } - } - ] - } - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) - - t.Run("Multiple queries with __typename", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/multiple_queries.query"), nil, t) - expected := ` -{ - "data": { - "topProducts": [ - { - "__typename": "Product", - "price": 11, - "upc": "top-1" - }, - { - "__typename": "Product", - "price": 22, - "upc": "top-2" - }, - { - "__typename": "Product", - "price": 33, - "upc": "top-3" - } - ], - "me": { - "__typename": "User", - "id": "1234", - "username": "Me" - } - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) - - t.Run("Query that returns union", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/multiple_queries_with_union_return.query"), nil, t) - expected := ` -{ - "data": { - "me": { - "__typename": "User", - "id": "1234", - "username": "Me" - }, - "histories": [ - { - "__typename": "Purchase", - "product": { - "__typename": "Product", - "upc": "top-1" - }, - "wallet": { - "__typename": "WalletType1", - "currency": "USD" - } - }, - { - "__typename": "Sale", - "product": { - "__typename": "Product", - "upc": "top-1" - }, - "rating": 1 - }, - { - "__typename": "Purchase", - "product": { - "__typename": "Product", - "upc": "top-2" - }, - "wallet": { - "__typename": "WalletType2", - "currency": "USD" - } - }, - { - "__typename": "Sale", - "product": { - "__typename": "Product", - "upc": "top-2" - }, - "rating": 2 - }, - { - "__typename": "Purchase", - "product": { - "__typename": "Product", - "upc": "top-3" - }, - "wallet": { - "__typename": "WalletType2", - "currency": "USD" - } - }, - { - "__typename": "Sale", - "product": { - "__typename": "Product", - "upc": "top-3" - }, - "rating": 3 - } - ] - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) - - t.Run("Object response type with interface and object fragment", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/interface_fragment_on_object.graphql"), nil, t) - expected := ` -{ - "data": { - "me": { - "id": "1234", - "username": "Me" - } - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) - - t.Run("Interface response type with object fragment", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/object_fragment_on_interface.graphql"), nil, t) - expected := ` -{ - "data": { - "identifiable": { - "__typename": "User", - "id": "1234", - "username": "Me" - } - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) - - t.Run("Union response type with interface fragments", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/interface_fragments_on_union.graphql"), nil, t) - expected := ` -{ - "data": { - "histories": [ - { - "__typename": "Purchase", - "quantity": 1 - }, - { - "__typename": "Sale", - "location": "Germany" - }, - { - "__typename": "Purchase", - "quantity": 2 - }, - { - "__typename": "Sale", - "location": "UK" - }, - { - "__typename": "Purchase", - "quantity": 3 - }, - { - "__typename": "Sale", - "location": "Ukraine" - } - ] - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) - - // This response data of this test returns location twice: from the interface selection and from the type fragment - // Duplicated properties (and therefore invalid JSON) are usually removed during normalization processes. - // It is not yet decided whether this should be addressed before these normalization processes. - t.Run("Complex nesting", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/complex_nesting.graphql"), nil, t) - expected := ` -{ - "data": { - "me": { - "id": "1234", - "username": "Me", - "history": [ - { - "wallet": { - "currency": "USD" - } - }, - { - "location": "Germany", - "location": "Germany", - "product": { - "upc": "top-2", - "name": "Fedora" - } - }, - { - "wallet": { - "currency": "USD" - } - } - ], - "reviews": [ - { - "__typename": "Review", - "attachments": [ - { - "upc": "top-1", - "body": "How do I turn it on?" - } - ] - }, - { - "__typename": "Review", - "attachments": [ - { - "upc": "top-2", - "body": "The best hat I have ever bought in my life." - }, - { - "upc": "top-2", - "size": 13.37 - } - ] - } - ] - } - } -} -` - assert.Equal(t, compact(expected), string(resp)) - }) - - t.Run("Merged fields are still resolved", func(t *testing.T) { - ctx, cancel := context.WithCancel(ctx) - defer cancel() - resp := gqlClient.Query(ctx, setup.gatewayServer.URL, path.Join("testdata", "queries/merged_field.graphql"), nil, t) - expected := ` -{ - "data": { - "cat": { - "name": "Pepper" - }, - "me": { - "id": "1234", - "username": "Me", - "realName": "User Usington", - "reviews": [ - { - "body": "A highly effective form of birth control." - }, - { - "body": "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits." - } - ], - "history": [ - { - "rating": 5 - } - ] - } - } -}` - assert.Equal(t, compact(expected), string(resp)) - }) -} - -func compact(input string) string { - var out bytes.Buffer - err := json.Compact(&out, []byte(input)) - if err != nil { - return "" - } - return out.String() -} diff --git a/pkg/testing/federationtesting/gateway/datasource_poller.go b/pkg/testing/federationtesting/gateway/datasource_poller.go deleted file mode 100644 index c1cf1f9dc..000000000 --- a/pkg/testing/federationtesting/gateway/datasource_poller.go +++ /dev/null @@ -1,213 +0,0 @@ -package gateway - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - "log" - "net/http" - "strings" - "sync" - "time" - - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" -) - -type ServiceConfig struct { - Name string - URL string - WS string -} - -type DatasourcePollerConfig struct { - Services []ServiceConfig - PollingInterval time.Duration -} - -const ServiceDefinitionQuery = ` - { - "query": "query __ApolloGetServiceDefinition__ { _service { sdl } }", - "operationName": "__ApolloGetServiceDefinition__", - "variables": {} - }` - -type GQLErr []struct { - Message string `json:"message"` -} - -func (g GQLErr) Error() string { - var builder strings.Builder - for _, m := range g { - _ = builder.WriteByte('\t') - _, _ = builder.WriteString(m.Message) - } - - return builder.String() -} - -func NewDatasourcePoller( - httpClient *http.Client, - config DatasourcePollerConfig, -) *DatasourcePollerPoller { - return &DatasourcePollerPoller{ - httpClient: httpClient, - config: config, - sdlMap: make(map[string]string), - } -} - -type DatasourcePollerPoller struct { - httpClient *http.Client - - config DatasourcePollerConfig - sdlMap map[string]string - - updateDatasourceObservers []DataSourceObserver -} - -func (d *DatasourcePollerPoller) Register(updateDatasourceObserver DataSourceObserver) { - d.updateDatasourceObservers = append(d.updateDatasourceObservers, updateDatasourceObserver) -} - -func (d *DatasourcePollerPoller) Run(ctx context.Context) { - d.updateSDLs(ctx) - - if d.config.PollingInterval == 0 { - <-ctx.Done() - return - } - - ticker := time.NewTicker(d.config.PollingInterval) - defer ticker.Stop() - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - d.updateSDLs(ctx) - } - } -} - -func (d *DatasourcePollerPoller) updateSDLs(ctx context.Context) { - d.sdlMap = make(map[string]string) - - var wg sync.WaitGroup - resultCh := make(chan struct { - name string - sdl string - }) - - for _, serviceConf := range d.config.Services { - serviceConf := serviceConf // Create new instance of serviceConf for the goroutine. - wg.Add(1) - go func() { - defer wg.Done() - - sdl, err := d.fetchServiceSDL(ctx, serviceConf.URL) - if err != nil { - log.Printf("Failed to get sdl for service: %s, err: %s\n", serviceConf.Name, err) - return - } - - select { - case <-ctx.Done(): - case resultCh <- struct { - name string - sdl string - }{name: serviceConf.Name, sdl: sdl}: - } - }() - } - - go func() { - wg.Wait() - close(resultCh) - }() - - for result := range resultCh { - d.sdlMap[result.name] = result.sdl - } - - d.updateObservers() -} - -func (d *DatasourcePollerPoller) updateObservers() { - dataSourceConfigs := d.createDatasourceConfig() - - for i := range d.updateDatasourceObservers { - d.updateDatasourceObservers[i].UpdateDataSources(dataSourceConfigs) - } -} - -func (d *DatasourcePollerPoller) createDatasourceConfig() []graphqlDataSource.Configuration { - dataSourceConfigs := make([]graphqlDataSource.Configuration, 0, len(d.config.Services)) - - for _, serviceConfig := range d.config.Services { - sdl, exists := d.sdlMap[serviceConfig.Name] - if !exists { - continue - } - - dataSourceConfig := graphqlDataSource.Configuration{ - Fetch: graphqlDataSource.FetchConfiguration{ - URL: serviceConfig.URL, - Method: http.MethodPost, - }, - Subscription: graphqlDataSource.SubscriptionConfiguration{ - URL: serviceConfig.WS, - }, - Federation: graphqlDataSource.FederationConfiguration{ - Enabled: true, - ServiceSDL: sdl, - }, - } - - dataSourceConfigs = append(dataSourceConfigs, dataSourceConfig) - } - - return dataSourceConfigs -} - -func (d *DatasourcePollerPoller) fetchServiceSDL(ctx context.Context, serviceURL string) (string, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodPost, serviceURL, bytes.NewReader([]byte(ServiceDefinitionQuery))) - req.Header.Add("Content-Type", "application/json") - - if err != nil { - return "", fmt.Errorf("create request: %v", err) - } - - resp, err := d.httpClient.Do(req) - if err != nil { - return "", fmt.Errorf("do request: %v", err) - } - - defer resp.Body.Close() - - var result struct { - Data struct { - Service struct { - SDL string `json:"sdl"` - } `json:"_service"` - } `json:"data"` - Errors GQLErr `json:"errors,omitempty"` - } - - bs, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("read bytes: %v", err) - } - - if err = json.NewDecoder(bytes.NewReader(bs)).Decode(&result); err != nil { - return "", fmt.Errorf("decode response: %v", err) - } - - if result.Errors != nil { - return "", fmt.Errorf("response error:%v", result.Errors) - } - - return result.Data.Service.SDL, nil -} diff --git a/pkg/testing/federationtesting/gateway/gateway.go b/pkg/testing/federationtesting/gateway/gateway.go deleted file mode 100644 index 8d20ae3de..000000000 --- a/pkg/testing/federationtesting/gateway/gateway.go +++ /dev/null @@ -1,104 +0,0 @@ -package gateway - -import ( - "context" - "net/http" - "sync" - - log "github.com/jensneuse/abstractlogger" - - graphqlDataSource "github.com/wundergraph/graphql-go-tools/pkg/engine/datasource/graphql_datasource" - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -type DataSourceObserver interface { - UpdateDataSources(dataSourceConfig []graphqlDataSource.Configuration) -} - -type DataSourceSubject interface { - Register(observer DataSourceObserver) -} - -type HandlerFactory interface { - Make(schema *graphql.Schema, engine *graphql.ExecutionEngineV2) http.Handler -} - -type HandlerFactoryFn func(schema *graphql.Schema, engine *graphql.ExecutionEngineV2) http.Handler - -func (h HandlerFactoryFn) Make(schema *graphql.Schema, engine *graphql.ExecutionEngineV2) http.Handler { - return h(schema, engine) -} - -func NewGateway( - gqlHandlerFactory HandlerFactory, - httpClient *http.Client, - logger log.Logger, -) *Gateway { - return &Gateway{ - gqlHandlerFactory: gqlHandlerFactory, - httpClient: httpClient, - logger: logger, - - mu: &sync.Mutex{}, - readyCh: make(chan struct{}), - readyOnce: &sync.Once{}, - } -} - -type Gateway struct { - gqlHandlerFactory HandlerFactory - httpClient *http.Client - logger log.Logger - - gqlHandler http.Handler - mu *sync.Mutex - - readyCh chan struct{} - readyOnce *sync.Once -} - -func (g *Gateway) ServeHTTP(w http.ResponseWriter, r *http.Request) { - g.mu.Lock() - handler := g.gqlHandler - g.mu.Unlock() - - handler.ServeHTTP(w, r) -} - -func (g *Gateway) Ready() { - <-g.readyCh -} - -// Error handling is not finished. -func (g *Gateway) UpdateDataSources(newDataSourcesConfig []graphqlDataSource.Configuration) { - ctx := context.Background() - engineConfigFactory := graphql.NewFederationEngineConfigFactory( - newDataSourcesConfig, - graphqlDataSource.NewBatchFactory(), - graphql.WithFederationHttpClient(g.httpClient), - ) - - schema, err := engineConfigFactory.MergedSchema() - if err != nil { - g.logger.Error("get schema:", log.Error(err)) - return - } - - datasourceConfig, err := engineConfigFactory.EngineV2Configuration() - if err != nil { - g.logger.Error("get engine config: %v", log.Error(err)) - return - } - - engine, err := graphql.NewExecutionEngineV2(ctx, g.logger, datasourceConfig) - if err != nil { - g.logger.Error("create engine: %v", log.Error(err)) - return - } - - g.mu.Lock() - g.gqlHandler = g.gqlHandlerFactory.Make(schema, engine) - g.mu.Unlock() - - g.readyOnce.Do(func() { close(g.readyCh) }) -} diff --git a/pkg/testing/federationtesting/gateway/http/handler.go b/pkg/testing/federationtesting/gateway/http/handler.go deleted file mode 100644 index a76b70789..000000000 --- a/pkg/testing/federationtesting/gateway/http/handler.go +++ /dev/null @@ -1,68 +0,0 @@ -package http - -import ( - "net/http" - - "github.com/gobwas/ws" - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -const ( - httpHeaderUpgrade string = "Upgrade" -) - -func NewGraphqlHTTPHandler( - schema *graphql.Schema, - engine *graphql.ExecutionEngineV2, - upgrader *ws.HTTPUpgrader, - logger log.Logger, -) http.Handler { - return &GraphQLHTTPRequestHandler{ - schema: schema, - engine: engine, - wsUpgrader: upgrader, - log: logger, - } -} - -type GraphQLHTTPRequestHandler struct { - log log.Logger - wsUpgrader *ws.HTTPUpgrader - engine *graphql.ExecutionEngineV2 - schema *graphql.Schema -} - -func (g *GraphQLHTTPRequestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - isUpgrade := g.isWebsocketUpgrade(r) - if isUpgrade { - err := g.upgradeWithNewGoroutine(w, r) - if err != nil { - g.log.Error("GraphQLHTTPRequestHandler.ServeHTTP", - log.Error(err), - ) - w.WriteHeader(http.StatusBadRequest) - } - return - } - g.handleHTTP(w, r) -} - -func (g *GraphQLHTTPRequestHandler) upgradeWithNewGoroutine(w http.ResponseWriter, r *http.Request) error { - conn, _, _, err := g.wsUpgrader.Upgrade(r, w) - if err != nil { - return err - } - g.handleWebsocket(r.Context(), conn) - return nil -} - -func (g *GraphQLHTTPRequestHandler) isWebsocketUpgrade(r *http.Request) bool { - for _, header := range r.Header[httpHeaderUpgrade] { - if header == "websocket" { - return true - } - } - return false -} diff --git a/pkg/testing/federationtesting/gateway/http/http.go b/pkg/testing/federationtesting/gateway/http/http.go deleted file mode 100644 index a29a4091c..000000000 --- a/pkg/testing/federationtesting/gateway/http/http.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package http handles GraphQL HTTP Requests including WebSocket Upgrades. -package http - -import ( - "bytes" - "net/http" - - log "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -const ( - httpHeaderContentType string = "Content-Type" - httpContentTypeApplicationJson string = "application/json" -) - -func (g *GraphQLHTTPRequestHandler) handleHTTP(w http.ResponseWriter, r *http.Request) { - var err error - - var gqlRequest graphql.Request - if err = graphql.UnmarshalHttpRequest(r, &gqlRequest); err != nil { - g.log.Error("UnmarshalHttpRequest", log.Error(err)) - w.WriteHeader(http.StatusBadRequest) - return - } - - buf := bytes.NewBuffer(make([]byte, 0, 4096)) - resultWriter := graphql.NewEngineResultWriterFromBuffer(buf) - if err = g.engine.Execute(r.Context(), &gqlRequest, &resultWriter); err != nil { - g.log.Error("engine.Execute", log.Error(err)) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Add(httpHeaderContentType, httpContentTypeApplicationJson) - w.WriteHeader(http.StatusOK) - if _, err = w.Write(buf.Bytes()); err != nil { - g.log.Error("write response", log.Error(err)) - return - } -} diff --git a/pkg/testing/federationtesting/gateway/http/ws.go b/pkg/testing/federationtesting/gateway/http/ws.go deleted file mode 100644 index 3181b3f28..000000000 --- a/pkg/testing/federationtesting/gateway/http/ws.go +++ /dev/null @@ -1,160 +0,0 @@ -package http - -import ( - "context" - "encoding/json" - "net" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/jensneuse/abstractlogger" - - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -// WebsocketSubscriptionClient is an actual implementation of the subscription client interface. -type WebsocketSubscriptionClient struct { - logger abstractlogger.Logger - // clientConn holds the actual connection to the client. - clientConn net.Conn - // isClosedConnection indicates if the websocket connection is closed. - isClosedConnection bool -} - -// NewWebsocketSubscriptionClient will create a new websocket subscription client. -func NewWebsocketSubscriptionClient(logger abstractlogger.Logger, clientConn net.Conn) *WebsocketSubscriptionClient { - return &WebsocketSubscriptionClient{ - logger: logger, - clientConn: clientConn, - } -} - -// ReadFromClient will read a subscription message from the websocket client. -func (w *WebsocketSubscriptionClient) ReadFromClient() (message *subscription.Message, err error) { - var data []byte - var opCode ws.OpCode - - data, opCode, err = wsutil.ReadClientData(w.clientConn) - if err != nil { - if w.isClosedConnectionError(err) { - return message, nil - } - - w.logger.Error("http.WebsocketSubscriptionClient.ReadFromClient()", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - abstractlogger.Any("opCode", opCode), - ) - - w.isClosedConnectionError(err) - - return nil, err - } - - err = json.Unmarshal(data, &message) - if err != nil { - w.logger.Error("http.WebsocketSubscriptionClient.ReadFromClient()", - abstractlogger.Error(err), - abstractlogger.ByteString("data", data), - abstractlogger.Any("opCode", opCode), - ) - - return nil, err - } - - return message, nil -} - -// WriteToClient will write a subscription message to the websocket client. -func (w *WebsocketSubscriptionClient) WriteToClient(message subscription.Message) error { - if w.isClosedConnection { - return nil - } - - messageBytes, err := json.Marshal(message) - if err != nil { - w.logger.Error("http.WebsocketSubscriptionClient.WriteToClient()", - abstractlogger.Error(err), - abstractlogger.Any("message", message), - ) - - return err - } - - err = wsutil.WriteServerMessage(w.clientConn, ws.OpText, messageBytes) - if err != nil { - w.logger.Error("http.WebsocketSubscriptionClient.WriteToClient()", - abstractlogger.Error(err), - abstractlogger.ByteString("messageBytes", messageBytes), - ) - - return err - } - - return nil -} - -// IsConnected will indicate if the websocket connection is still established. -func (w *WebsocketSubscriptionClient) IsConnected() bool { - return !w.isClosedConnection -} - -// Disconnect will close the websocket connection. -func (w *WebsocketSubscriptionClient) Disconnect() error { - w.logger.Debug("http.GraphQLHTTPRequestHandler.Disconnect()", - abstractlogger.String("message", "disconnecting client"), - ) - w.isClosedConnection = true - return w.clientConn.Close() -} - -// isClosedConnectionError will indicate if the given error is a connection closed error. -func (w *WebsocketSubscriptionClient) isClosedConnectionError(err error) bool { - if _, ok := err.(wsutil.ClosedError); ok { - w.isClosedConnection = true - } - - return w.isClosedConnection -} - -func HandleWebsocket(done chan bool, errChan chan error, conn net.Conn, executorPool subscription.ExecutorPool, logger abstractlogger.Logger) { - defer func() { - if err := conn.Close(); err != nil { - logger.Error("http.HandleWebsocket()", - abstractlogger.String("message", "could not close connection to client"), - abstractlogger.Error(err), - ) - } - }() - - websocketClient := NewWebsocketSubscriptionClient(logger, conn) - subscriptionHandler, err := subscription.NewHandler(logger, websocketClient, executorPool) - if err != nil { - logger.Error("http.HandleWebsocket()", - abstractlogger.String("message", "could not create subscriptionHandler"), - abstractlogger.Error(err), - ) - - errChan <- err - return - } - - close(done) - subscriptionHandler.Handle(context.Background()) // Blocking -} - -// handleWebsocket will handle the websocket connection. -func (g *GraphQLHTTPRequestHandler) handleWebsocket(connInitReqCtx context.Context, conn net.Conn) { - done := make(chan bool) - errChan := make(chan error) - - executorPool := subscription.NewExecutorV2Pool(g.engine, connInitReqCtx) - go HandleWebsocket(done, errChan, conn, executorPool, g.log) - select { - case err := <-errChan: - g.log.Error("http.GraphQLHTTPRequestHandler.handleWebsocket()", - abstractlogger.Error(err), - ) - case <-done: - } -} diff --git a/pkg/testing/federationtesting/gateway/main.go b/pkg/testing/federationtesting/gateway/main.go deleted file mode 100644 index c5e0aa5c5..000000000 --- a/pkg/testing/federationtesting/gateway/main.go +++ /dev/null @@ -1,42 +0,0 @@ -package gateway - -import ( - "net/http" - "time" - - "github.com/gobwas/ws" - log "github.com/jensneuse/abstractlogger" - - http2 "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/gateway/http" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" -) - -func NewDatasource(serviceConfig []ServiceConfig, httpClient *http.Client) *DatasourcePollerPoller { - return NewDatasourcePoller(httpClient, DatasourcePollerConfig{ - Services: serviceConfig, - PollingInterval: 30 * time.Second, - }) -} - -func Handler( - logger log.Logger, - datasourcePoller *DatasourcePollerPoller, - httpClient *http.Client, -) *Gateway { - upgrader := &ws.DefaultHTTPUpgrader - upgrader.Header = http.Header{} - //upgrader.Header.Add("Sec-Websocket-Protocol", "graphql-ws") - - datasourceWatcher := datasourcePoller - - var gqlHandlerFactory HandlerFactoryFn = func(schema *graphql.Schema, engine *graphql.ExecutionEngineV2) http.Handler { - return http2.NewGraphqlHTTPHandler(schema, engine, upgrader, logger) - } - - gateway := NewGateway(gqlHandlerFactory, httpClient, logger) - - datasourceWatcher.Register(gateway) - - return gateway -} diff --git a/pkg/testing/federationtesting/graphql_client_test.go b/pkg/testing/federationtesting/graphql_client_test.go deleted file mode 100644 index 777646819..000000000 --- a/pkg/testing/federationtesting/graphql_client_test.go +++ /dev/null @@ -1,138 +0,0 @@ -package federationtesting - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net" - "net/http" - "os" - "testing" - - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/wundergraph/graphql-go-tools/pkg/graphql" - "github.com/wundergraph/graphql-go-tools/pkg/subscription" -) - -type queryVariables map[string]interface{} - -func requestBody(t *testing.T, query string, variables queryVariables) []byte { - var variableJsonBytes []byte - if len(variables) > 0 { - var err error - variableJsonBytes, err = json.Marshal(variables) - require.NoError(t, err) - } - - body := graphql.Request{ - OperationName: "", - Variables: variableJsonBytes, - Query: query, - } - - jsonBytes, err := json.Marshal(body) - require.NoError(t, err) - - return jsonBytes -} - -func loadQuery(t *testing.T, filePath string, variables queryVariables) []byte { - query, err := os.ReadFile(filePath) - require.NoError(t, err) - - return requestBody(t, string(query), variables) -} - -func NewGraphqlClient(httpClient *http.Client) *GraphqlClient { - return &GraphqlClient{ - httpClient: httpClient, - } -} - -type GraphqlClient struct { - httpClient *http.Client -} - -func (g *GraphqlClient) Query(ctx context.Context, addr, queryFilePath string, variables queryVariables, t *testing.T) []byte { - reqBody := loadQuery(t, queryFilePath, variables) - req, err := http.NewRequest(http.MethodPost, addr, bytes.NewBuffer(reqBody)) - require.NoError(t, err) - req = req.WithContext(ctx) - resp, err := g.httpClient.Do(req) - require.NoError(t, err) - responseBodyBytes, err := io.ReadAll(resp.Body) - require.NoError(t, err) - assert.Equal(t, http.StatusOK, resp.StatusCode) - assert.Contains(t, resp.Header.Get("Content-Type"), "application/json") - - return responseBodyBytes -} - -func (g *GraphqlClient) Subscription(ctx context.Context, addr, queryFilePath string, variables queryVariables, t *testing.T) chan []byte { - messageCh := make(chan []byte) - - conn, _, _, err := ws.Dial(ctx, addr) - require.NoError(t, err) - // 1. send connection init - initialClientMessage := subscription.Message{ - Id: "", - Type: subscription.MessageTypeConnectionInit, - Payload: nil, - } - - err = g.sendMessageToServer(conn, initialClientMessage) - require.NoError(t, err) - // 2. receive connection ack - serverMessage := g.readMessageFromServer(t, conn) - assert.Equal(t, `{"id":"","type":"connection_ack","payload":null}`, string(serverMessage)) - // 3. send `start` message with subscription operation - startSubscriptionMessage := subscription.Message{ - Id: "1", - Type: subscription.MessageTypeStart, - Payload: loadQuery(t, queryFilePath, variables), - } - - err = g.sendMessageToServer(conn, startSubscriptionMessage) - require.NoError(t, err) - - // 4. start receiving messages from subscription - - go func() { - defer conn.Close() - defer close(messageCh) - - for { - msgBytes, _, err := wsutil.ReadServerData(conn) - require.NoError(t, err) - - messageCh <- msgBytes - } - }() - - return messageCh -} - -func (g *GraphqlClient) sendMessageToServer(clientConn net.Conn, message subscription.Message) error { - messageBytes, err := json.Marshal(message) - if err != nil { - return err - } - - if err = wsutil.WriteClientText(clientConn, messageBytes); err != nil { - return err - } - - return nil -} - -func (g *GraphqlClient) readMessageFromServer(t *testing.T, clientConn net.Conn) []byte { - msgBytes, _, err := wsutil.ReadServerData(clientConn) - require.NoError(t, err) - - return msgBytes -} diff --git a/pkg/testing/federationtesting/products/gqlgen.yml b/pkg/testing/federationtesting/products/gqlgen.yml deleted file mode 100644 index a3d448b1b..000000000 --- a/pkg/testing/federationtesting/products/gqlgen.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Where are all the schema files located? globs are supported eg src/**/*.graphqls -schema: - - graph/*.graphqls - -# Where should the generated server code go? -exec: - filename: graph/generated/generated.go - package: generated - -federation: - filename: graph/generated/federation.go - package: generated - -# Where should any generated models go? -model: - filename: graph/model/models_gen.go - package: model - -# Where should the resolver implementations go? -resolver: - layout: follow-schema - dir: graph - package: graph - -# Optional: turn on use `gqlgen:"fieldName"` tags in your models -# struct_tag: json - -# Optional: turn on to use []Thing instead of []*Thing -# omit_slice_element_pointers: false - -# Optional: set to speed up generation time by not performing a final validation pass. -# skip_validation: true - -# gqlgen will search for any type names in the schema in these go packages -# if they match it will use them, otherwise it will generate them. -#autobind: -# - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/model" - -# This section declares type mapping between the GraphQL and go type systems -# -# The first line in each type will be used as defaults for resolver arguments and -# modelgen, the others will be allowed when binding to fields. Configure them to -# your liking -models: - ID: - model: - - github.com/99designs/gqlgen/graphql.ID - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 - Int: - model: - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 diff --git a/pkg/testing/federationtesting/products/graph/entity.resolvers.go b/pkg/testing/federationtesting/products/graph/entity.resolvers.go deleted file mode 100644 index f1d439952..000000000 --- a/pkg/testing/federationtesting/products/graph/entity.resolvers.go +++ /dev/null @@ -1,27 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.22 - -import ( - "context" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/generated" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/model" -) - -// FindProductByUpc is the resolver for the findProductByUpc field. -func (r *entityResolver) FindProductByUpc(ctx context.Context, upc string) (*model.Product, error) { - for _, h := range hats { - if h.Upc == upc { - return h, nil - } - } - return nil, nil -} - -// Entity returns generated.EntityResolver implementation. -func (r *Resolver) Entity() generated.EntityResolver { return &entityResolver{r} } - -type entityResolver struct{ *Resolver } diff --git a/pkg/testing/federationtesting/products/graph/generated/federation.go b/pkg/testing/federationtesting/products/graph/generated/federation.go deleted file mode 100644 index 21f304603..000000000 --- a/pkg/testing/federationtesting/products/graph/generated/federation.go +++ /dev/null @@ -1,187 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package generated - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - - "github.com/99designs/gqlgen/plugin/federation/fedruntime" -) - -var ( - ErrUnknownType = errors.New("unknown type") - ErrTypeNotFound = errors.New("type not found") -) - -func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) { - if ec.DisableIntrospection { - return fedruntime.Service{}, errors.New("federated introspection disabled") - } - - var sdl []string - - for _, src := range sources { - if src.BuiltIn { - continue - } - sdl = append(sdl, src.Input) - } - - return fedruntime.Service{ - SDL: strings.Join(sdl, "\n"), - }, nil -} - -func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) []fedruntime.Entity { - list := make([]fedruntime.Entity, len(representations)) - - repsMap := map[string]struct { - i []int - r []map[string]interface{} - }{} - - // We group entities by typename so that we can parallelize their resolution. - // This is particularly helpful when there are entity groups in multi mode. - buildRepresentationGroups := func(reps []map[string]interface{}) { - for i, rep := range reps { - typeName, ok := rep["__typename"].(string) - if !ok { - // If there is no __typename, we just skip the representation; - // we just won't be resolving these unknown types. - ec.Error(ctx, errors.New("__typename must be an existing string")) - continue - } - - _r := repsMap[typeName] - _r.i = append(_r.i, i) - _r.r = append(_r.r, rep) - repsMap[typeName] = _r - } - } - - isMulti := func(typeName string) bool { - switch typeName { - default: - return false - } - } - - resolveEntity := func(ctx context.Context, typeName string, rep map[string]interface{}, idx []int, i int) (err error) { - // we need to do our own panic handling, because we may be called in a - // goroutine, where the usual panic handling can't catch us - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - } - }() - - switch typeName { - case "Product": - resolverName, err := entityResolverNameForProduct(ctx, rep) - if err != nil { - return fmt.Errorf(`finding resolver for Entity "Product": %w`, err) - } - switch resolverName { - - case "findProductByUpc": - id0, err := ec.unmarshalNString2string(ctx, rep["upc"]) - if err != nil { - return fmt.Errorf(`unmarshalling param 0 for findProductByUpc(): %w`, err) - } - entity, err := ec.resolvers.Entity().FindProductByUpc(ctx, id0) - if err != nil { - return fmt.Errorf(`resolving Entity "Product": %w`, err) - } - - list[idx[i]] = entity - return nil - } - - } - return fmt.Errorf("%w: %s", ErrUnknownType, typeName) - } - - resolveManyEntities := func(ctx context.Context, typeName string, reps []map[string]interface{}, idx []int) (err error) { - // we need to do our own panic handling, because we may be called in a - // goroutine, where the usual panic handling can't catch us - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - } - }() - - switch typeName { - - default: - return errors.New("unknown type: " + typeName) - } - } - - resolveEntityGroup := func(typeName string, reps []map[string]interface{}, idx []int) { - if isMulti(typeName) { - err := resolveManyEntities(ctx, typeName, reps, idx) - if err != nil { - ec.Error(ctx, err) - } - } else { - // if there are multiple entities to resolve, parallelize (similar to - // graphql.FieldSet.Dispatch) - var e sync.WaitGroup - e.Add(len(reps)) - for i, rep := range reps { - i, rep := i, rep - go func(i int, rep map[string]interface{}) { - err := resolveEntity(ctx, typeName, rep, idx, i) - if err != nil { - ec.Error(ctx, err) - } - e.Done() - }(i, rep) - } - e.Wait() - } - } - buildRepresentationGroups(representations) - - switch len(repsMap) { - case 0: - return list - case 1: - for typeName, reps := range repsMap { - resolveEntityGroup(typeName, reps.r, reps.i) - } - return list - default: - var g sync.WaitGroup - g.Add(len(repsMap)) - for typeName, reps := range repsMap { - go func(typeName string, reps []map[string]interface{}, idx []int) { - resolveEntityGroup(typeName, reps, idx) - g.Done() - }(typeName, reps.r, reps.i) - } - g.Wait() - return list - } -} - -func entityResolverNameForProduct(ctx context.Context, rep map[string]interface{}) (string, error) { - for { - var ( - m map[string]interface{} - val interface{} - ok bool - ) - _ = val - m = rep - if _, ok = m["upc"]; !ok { - break - } - return "findProductByUpc", nil - } - return "", fmt.Errorf("%w for Product", ErrTypeNotFound) -} diff --git a/pkg/testing/federationtesting/products/graph/generated/generated.go b/pkg/testing/federationtesting/products/graph/generated/generated.go deleted file mode 100644 index d96cb555d..000000000 --- a/pkg/testing/federationtesting/products/graph/generated/generated.go +++ /dev/null @@ -1,4276 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package generated - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "strconv" - "sync" - "sync/atomic" - - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/introspection" - "github.com/99designs/gqlgen/plugin/federation/fedruntime" - gqlparser "github.com/vektah/gqlparser/v2" - "github.com/vektah/gqlparser/v2/ast" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/model" -) - -// region ************************** generated!.gotpl ************************** - -// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. -func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { - return &executableSchema{ - resolvers: cfg.Resolvers, - directives: cfg.Directives, - complexity: cfg.Complexity, - } -} - -type Config struct { - Resolvers ResolverRoot - Directives DirectiveRoot - Complexity ComplexityRoot -} - -type ResolverRoot interface { - Entity() EntityResolver - Query() QueryResolver - Subscription() SubscriptionResolver -} - -type DirectiveRoot struct { -} - -type ComplexityRoot struct { - Entity struct { - FindProductByUpc func(childComplexity int, upc string) int - } - - Product struct { - InStock func(childComplexity int) int - Name func(childComplexity int) int - Price func(childComplexity int) int - Upc func(childComplexity int) int - } - - Query struct { - TopProducts func(childComplexity int, first *int) int - __resolve__service func(childComplexity int) int - __resolve_entities func(childComplexity int, representations []map[string]interface{}) int - } - - Subscription struct { - UpdateProductPrice func(childComplexity int, upc string) int - UpdatedPrice func(childComplexity int) int - } - - _Service struct { - SDL func(childComplexity int) int - } -} - -type EntityResolver interface { - FindProductByUpc(ctx context.Context, upc string) (*model.Product, error) -} -type QueryResolver interface { - TopProducts(ctx context.Context, first *int) ([]*model.Product, error) -} -type SubscriptionResolver interface { - UpdatedPrice(ctx context.Context) (<-chan *model.Product, error) - UpdateProductPrice(ctx context.Context, upc string) (<-chan *model.Product, error) -} - -type executableSchema struct { - resolvers ResolverRoot - directives DirectiveRoot - complexity ComplexityRoot -} - -func (e *executableSchema) Schema() *ast.Schema { - return parsedSchema -} - -func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { - ec := executionContext{nil, e} - _ = ec - switch typeName + "." + field { - - case "Entity.findProductByUpc": - if e.complexity.Entity.FindProductByUpc == nil { - break - } - - args, err := ec.field_Entity_findProductByUpc_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Entity.FindProductByUpc(childComplexity, args["upc"].(string)), true - - case "Product.inStock": - if e.complexity.Product.InStock == nil { - break - } - - return e.complexity.Product.InStock(childComplexity), true - - case "Product.name": - if e.complexity.Product.Name == nil { - break - } - - return e.complexity.Product.Name(childComplexity), true - - case "Product.price": - if e.complexity.Product.Price == nil { - break - } - - return e.complexity.Product.Price(childComplexity), true - - case "Product.upc": - if e.complexity.Product.Upc == nil { - break - } - - return e.complexity.Product.Upc(childComplexity), true - - case "Query.topProducts": - if e.complexity.Query.TopProducts == nil { - break - } - - args, err := ec.field_Query_topProducts_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Query.TopProducts(childComplexity, args["first"].(*int)), true - - case "Query._service": - if e.complexity.Query.__resolve__service == nil { - break - } - - return e.complexity.Query.__resolve__service(childComplexity), true - - case "Query._entities": - if e.complexity.Query.__resolve_entities == nil { - break - } - - args, err := ec.field_Query__entities_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Query.__resolve_entities(childComplexity, args["representations"].([]map[string]interface{})), true - - case "Subscription.updateProductPrice": - if e.complexity.Subscription.UpdateProductPrice == nil { - break - } - - args, err := ec.field_Subscription_updateProductPrice_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Subscription.UpdateProductPrice(childComplexity, args["upc"].(string)), true - - case "Subscription.updatedPrice": - if e.complexity.Subscription.UpdatedPrice == nil { - break - } - - return e.complexity.Subscription.UpdatedPrice(childComplexity), true - - case "_Service.sdl": - if e.complexity._Service.SDL == nil { - break - } - - return e.complexity._Service.SDL(childComplexity), true - - } - return 0, false -} - -func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { - rc := graphql.GetOperationContext(ctx) - ec := executionContext{rc, e} - inputUnmarshalMap := graphql.BuildUnmarshalerMap() - first := true - - switch rc.Operation.Operation { - case ast.Query: - return func(ctx context.Context) *graphql.Response { - if !first { - return nil - } - first = false - ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Query(ctx, rc.Operation.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - case ast.Subscription: - next := ec._Subscription(ctx, rc.Operation.SelectionSet) - - var buf bytes.Buffer - return func(ctx context.Context) *graphql.Response { - buf.Reset() - data := next(ctx) - - if data == nil { - return nil - } - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - - default: - return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) - } -} - -type executionContext struct { - *graphql.OperationContext - *executableSchema -} - -func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapSchema(parsedSchema), nil -} - -func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil -} - -var sources = []*ast.Source{ - {Name: "../schema.graphqls", Input: `extend type Query { - topProducts(first: Int = 5): [Product] -} - -extend type Subscription { - updatedPrice: Product! - updateProductPrice(upc: String!): Product! -} - -type Product @key(fields: "upc") { - upc: String! - name: String! - price: Int! - inStock: Int! -}`, BuiltIn: false}, - {Name: "../../federation/directives.graphql", Input: ` - scalar _Any - scalar _FieldSet - - directive @external on FIELD_DEFINITION - directive @requires(fields: _FieldSet!) on FIELD_DEFINITION - directive @provides(fields: _FieldSet!) on FIELD_DEFINITION - directive @extends on OBJECT | INTERFACE - - directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE -`, BuiltIn: true}, - {Name: "../../federation/entity.graphql", Input: ` -# a union of all types that use the @key directive -union _Entity = Product - -# fake type to build resolver interfaces for users to implement -type Entity { - findProductByUpc(upc: String!,): Product! - -} - -type _Service { - sdl: String -} - -extend type Query { - _entities(representations: [_Any!]!): [_Entity]! - _service: _Service! -} -`, BuiltIn: true}, -} -var parsedSchema = gqlparser.MustLoadSchema(sources...) - -// endregion ************************** generated!.gotpl ************************** - -// region ***************************** args.gotpl ***************************** - -func (ec *executionContext) field_Entity_findProductByUpc_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["upc"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("upc")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["upc"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["name"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query__entities_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 []map[string]interface{} - if tmp, ok := rawArgs["representations"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("representations")) - arg0, err = ec.unmarshalN_Any2ᚕmapᚄ(ctx, tmp) - if err != nil { - return nil, err - } - } - args["representations"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query_topProducts_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 *int - if tmp, ok := rawArgs["first"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("first")) - arg0, err = ec.unmarshalOInt2ᚖint(ctx, tmp) - if err != nil { - return nil, err - } - } - args["first"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Subscription_updateProductPrice_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["upc"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("upc")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["upc"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -// endregion ***************************** args.gotpl ***************************** - -// region ************************** directives.gotpl ************************** - -// endregion ************************** directives.gotpl ************************** - -// region **************************** field.gotpl ***************************** - -func (ec *executionContext) _Entity_findProductByUpc(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Entity_findProductByUpc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Entity().FindProductByUpc(rctx, fc.Args["upc"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Product) - fc.Result = res - return ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Entity_findProductByUpc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Entity", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - case "name": - return ec.fieldContext_Product_name(ctx, field) - case "price": - return ec.fieldContext_Product_price(ctx, field) - case "inStock": - return ec.fieldContext_Product_inStock(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Entity_findProductByUpc_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Product_upc(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_upc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Upc, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_upc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Product_name(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Product_price(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_price(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Price, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(int) - fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_price(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Product_inStock(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_inStock(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.InStock, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(int) - fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_inStock(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_topProducts(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_topProducts(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().TopProducts(rctx, fc.Args["first"].(*int)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]*model.Product) - fc.Result = res - return ec.marshalOProduct2ᚕᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_topProducts(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - case "name": - return ec.fieldContext_Product_name(ctx, field) - case "price": - return ec.fieldContext_Product_price(ctx, field) - case "inStock": - return ec.fieldContext_Product_inStock(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_topProducts_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query__entities(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__entities(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.__resolve_entities(ctx, fc.Args["representations"].([]map[string]interface{})), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]fedruntime.Entity) - fc.Result = res - return ec.marshalN_Entity2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__entities(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type _Entity does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__entities_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query__service(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__service(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.__resolve__service(ctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(fedruntime.Service) - fc.Result = res - return ec.marshalN_Service2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐService(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__service(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "sdl": - return ec.fieldContext__Service_sdl(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type _Service", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectType(fc.Args["name"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___schema(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectSchema() - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Schema) - fc.Result = res - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "description": - return ec.fieldContext___Schema_description(ctx, field) - case "types": - return ec.fieldContext___Schema_types(ctx, field) - case "queryType": - return ec.fieldContext___Schema_queryType(ctx, field) - case "mutationType": - return ec.fieldContext___Schema_mutationType(ctx, field) - case "subscriptionType": - return ec.fieldContext___Schema_subscriptionType(ctx, field) - case "directives": - return ec.fieldContext___Schema_directives(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Subscription_updatedPrice(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { - fc, err := ec.fieldContext_Subscription_updatedPrice(ctx, field) - if err != nil { - return nil - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Subscription().UpdatedPrice(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return nil - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return nil - } - return func(ctx context.Context) graphql.Marshaler { - select { - case res, ok := <-resTmp.(<-chan *model.Product): - if !ok { - return nil - } - return graphql.WriterFunc(func(w io.Writer) { - w.Write([]byte{'{'}) - graphql.MarshalString(field.Alias).MarshalGQL(w) - w.Write([]byte{':'}) - ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res).MarshalGQL(w) - w.Write([]byte{'}'}) - }) - case <-ctx.Done(): - return nil - } - } -} - -func (ec *executionContext) fieldContext_Subscription_updatedPrice(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Subscription", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - case "name": - return ec.fieldContext_Product_name(ctx, field) - case "price": - return ec.fieldContext_Product_price(ctx, field) - case "inStock": - return ec.fieldContext_Product_inStock(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Subscription_updateProductPrice(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { - fc, err := ec.fieldContext_Subscription_updateProductPrice(ctx, field) - if err != nil { - return nil - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Subscription().UpdateProductPrice(rctx, fc.Args["upc"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return nil - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return nil - } - return func(ctx context.Context) graphql.Marshaler { - select { - case res, ok := <-resTmp.(<-chan *model.Product): - if !ok { - return nil - } - return graphql.WriterFunc(func(w io.Writer) { - w.Write([]byte{'{'}) - graphql.MarshalString(field.Alias).MarshalGQL(w) - w.Write([]byte{':'}) - ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res).MarshalGQL(w) - w.Write([]byte{'}'}) - }) - case <-ctx.Done(): - return nil - } - } -} - -func (ec *executionContext) fieldContext_Subscription_updateProductPrice(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Subscription", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - case "name": - return ec.fieldContext_Product_name(ctx, field) - case "price": - return ec.fieldContext_Product_price(ctx, field) - case "inStock": - return ec.fieldContext_Product_inStock(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Subscription_updateProductPrice_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) __Service_sdl(ctx context.Context, field graphql.CollectedField, obj *fedruntime.Service) (ret graphql.Marshaler) { - fc, err := ec.fieldContext__Service_sdl(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SDL, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalOString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext__Service_sdl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "_Service", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_locations(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Locations, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]string) - fc.Result = res - return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __DirectiveLocation does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsRepeatable, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_types(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Types(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_queryType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.QueryType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_mutationType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.MutationType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SubscriptionType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_directives(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Directives(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Directive) - fc.Result = res - return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Directive_name(ctx, field) - case "description": - return ec.fieldContext___Directive_description(ctx, field) - case "locations": - return ec.fieldContext___Directive_locations(ctx, field) - case "args": - return ec.fieldContext___Directive_args(ctx, field) - case "isRepeatable": - return ec.fieldContext___Directive_isRepeatable(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_kind(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Kind(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalN__TypeKind2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __TypeKind does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_fields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Field) - fc.Result = res - return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Field_name(ctx, field) - case "description": - return ec.fieldContext___Field_description(ctx, field) - case "args": - return ec.fieldContext___Field_args(ctx, field) - case "type": - return ec.fieldContext___Field_type(ctx, field) - case "isDeprecated": - return ec.fieldContext___Field_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___Field_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_interfaces(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Interfaces(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_possibleTypes(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.PossibleTypes(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_enumValues(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.EnumValue) - fc.Result = res - return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___EnumValue_name(ctx, field) - case "description": - return ec.fieldContext___EnumValue_description(ctx, field) - case "isDeprecated": - return ec.fieldContext___EnumValue_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___EnumValue_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_inputFields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.InputFields(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_ofType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.OfType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SpecifiedByURL(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -// endregion **************************** field.gotpl ***************************** - -// region **************************** input.gotpl ***************************** - -// endregion **************************** input.gotpl ***************************** - -// region ************************** interface.gotpl *************************** - -func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, obj fedruntime.Entity) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Product: - return ec._Product(ctx, sel, &obj) - case *model.Product: - if obj == nil { - return graphql.Null - } - return ec._Product(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -// endregion ************************** interface.gotpl *************************** - -// region **************************** object.gotpl **************************** - -var entityImplementors = []string{"Entity"} - -func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, entityImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Entity", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Entity") - case "findProductByUpc": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Entity_findProductByUpc(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var productImplementors = []string{"Product", "_Entity"} - -func (ec *executionContext) _Product(ctx context.Context, sel ast.SelectionSet, obj *model.Product) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, productImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Product") - case "upc": - - out.Values[i] = ec._Product_upc(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "name": - - out.Values[i] = ec._Product_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "price": - - out.Values[i] = ec._Product_price(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "inStock": - - out.Values[i] = ec._Product_inStock(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var queryImplementors = []string{"Query"} - -func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Query", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Query") - case "topProducts": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_topProducts(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "_entities": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query__entities(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "_service": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query__service(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "__type": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___type(ctx, field) - }) - - case "__schema": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___schema(ctx, field) - }) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var subscriptionImplementors = []string{"Subscription"} - -func (ec *executionContext) _Subscription(ctx context.Context, sel ast.SelectionSet) func(ctx context.Context) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, subscriptionImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Subscription", - }) - if len(fields) != 1 { - ec.Errorf(ctx, "must subscribe to exactly one stream") - return nil - } - - switch fields[0].Name { - case "updatedPrice": - return ec._Subscription_updatedPrice(ctx, fields[0]) - case "updateProductPrice": - return ec._Subscription_updateProductPrice(ctx, fields[0]) - default: - panic("unknown field " + strconv.Quote(fields[0].Name)) - } -} - -var _ServiceImplementors = []string{"_Service"} - -func (ec *executionContext) __Service(ctx context.Context, sel ast.SelectionSet, obj *fedruntime.Service) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, _ServiceImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("_Service") - case "sdl": - - out.Values[i] = ec.__Service_sdl(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __DirectiveImplementors = []string{"__Directive"} - -func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Directive") - case "name": - - out.Values[i] = ec.___Directive_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Directive_description(ctx, field, obj) - - case "locations": - - out.Values[i] = ec.___Directive_locations(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "args": - - out.Values[i] = ec.___Directive_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isRepeatable": - - out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __EnumValueImplementors = []string{"__EnumValue"} - -func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__EnumValue") - case "name": - - out.Values[i] = ec.___EnumValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___EnumValue_description(ctx, field, obj) - - case "isDeprecated": - - out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __FieldImplementors = []string{"__Field"} - -func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Field") - case "name": - - out.Values[i] = ec.___Field_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Field_description(ctx, field, obj) - - case "args": - - out.Values[i] = ec.___Field_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "type": - - out.Values[i] = ec.___Field_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isDeprecated": - - out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __InputValueImplementors = []string{"__InputValue"} - -func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__InputValue") - case "name": - - out.Values[i] = ec.___InputValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___InputValue_description(ctx, field, obj) - - case "type": - - out.Values[i] = ec.___InputValue_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "defaultValue": - - out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __SchemaImplementors = []string{"__Schema"} - -func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Schema") - case "description": - - out.Values[i] = ec.___Schema_description(ctx, field, obj) - - case "types": - - out.Values[i] = ec.___Schema_types(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "queryType": - - out.Values[i] = ec.___Schema_queryType(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "mutationType": - - out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) - - case "subscriptionType": - - out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) - - case "directives": - - out.Values[i] = ec.___Schema_directives(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __TypeImplementors = []string{"__Type"} - -func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Type") - case "kind": - - out.Values[i] = ec.___Type_kind(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "name": - - out.Values[i] = ec.___Type_name(ctx, field, obj) - - case "description": - - out.Values[i] = ec.___Type_description(ctx, field, obj) - - case "fields": - - out.Values[i] = ec.___Type_fields(ctx, field, obj) - - case "interfaces": - - out.Values[i] = ec.___Type_interfaces(ctx, field, obj) - - case "possibleTypes": - - out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) - - case "enumValues": - - out.Values[i] = ec.___Type_enumValues(ctx, field, obj) - - case "inputFields": - - out.Values[i] = ec.___Type_inputFields(ctx, field, obj) - - case "ofType": - - out.Values[i] = ec.___Type_ofType(ctx, field, obj) - - case "specifiedByURL": - - out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -// endregion **************************** object.gotpl **************************** - -// region ***************************** type.gotpl ***************************** - -func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { - res, err := graphql.UnmarshalInt(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { - res := graphql.MarshalInt(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalNProduct2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v model.Product) graphql.Marshaler { - return ec._Product(ctx, sel, &v) -} - -func (ec *executionContext) marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v *model.Product) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._Product(ctx, sel, v) -} - -func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN_Any2map(ctx context.Context, v interface{}) (map[string]interface{}, error) { - res, err := graphql.UnmarshalMap(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN_Any2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - res := graphql.MarshalMap(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN_Any2ᚕmapᚄ(ctx context.Context, v interface{}) ([]map[string]interface{}, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]map[string]interface{}, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN_Any2map(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN_Any2ᚕmapᚄ(ctx context.Context, sel ast.SelectionSet, v []map[string]interface{}) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - for i := range v { - ret[i] = ec.marshalN_Any2map(ctx, sel, v[i]) - } - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN_Entity2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx context.Context, sel ast.SelectionSet, v []fedruntime.Entity) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalO_Entity2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) unmarshalN_FieldSet2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN_FieldSet2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalN_Service2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐService(ctx context.Context, sel ast.SelectionSet, v fedruntime.Service) graphql.Marshaler { - return ec.__Service(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { - return ec.___Directive(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]string, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { - return ec.___EnumValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { - return ec.___Field(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { - return ec.___InputValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { - return ec.___Type(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - return res -} - -func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalBoolean(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalBoolean(*v) - return res -} - -func (ec *executionContext) unmarshalOInt2ᚖint(ctx context.Context, v interface{}) (*int, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalInt(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOInt2ᚖint(ctx context.Context, sel ast.SelectionSet, v *int) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalInt(*v) - return res -} - -func (ec *executionContext) marshalOProduct2ᚕᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v []*model.Product) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalOProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) marshalOProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋproductsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v *model.Product) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Product(ctx, sel, v) -} - -func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - return res -} - -func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalString(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalString(*v) - return res -} - -func (ec *executionContext) marshalO_Entity2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx context.Context, sel ast.SelectionSet, v fedruntime.Entity) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.__Entity(ctx, sel, v) -} - -func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Schema(ctx, sel, v) -} - -func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -// endregion ***************************** type.gotpl ***************************** diff --git a/pkg/testing/federationtesting/products/graph/handler.go b/pkg/testing/federationtesting/products/graph/handler.go deleted file mode 100644 index 3e241b36a..000000000 --- a/pkg/testing/federationtesting/products/graph/handler.go +++ /dev/null @@ -1,82 +0,0 @@ -package graph - -import ( - "context" - "encoding/json" - "net/http" - "time" - - "github.com/99designs/gqlgen/graphql/handler" - "github.com/99designs/gqlgen/graphql/handler/debug" - "github.com/99designs/gqlgen/graphql/handler/extension" - "github.com/99designs/gqlgen/graphql/handler/transport" - "github.com/gorilla/websocket" - "go.uber.org/atomic" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/generated" -) - -var websocketConnections atomic.Uint32 - -type EndpointOptions struct { - EnableDebug bool - EnableRandomness bool - OverrideUpdateInterval time.Duration -} - -var TestOptions = EndpointOptions{ - EnableDebug: false, - EnableRandomness: false, - OverrideUpdateInterval: 50 * time.Millisecond, -} - -func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { - websocketConnections.Store(0) - srv := handler.New(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) - - srv.AddTransport(transport.POST{}) - srv.AddTransport(transport.Websocket{ - KeepAlivePingInterval: 10 * time.Second, - Upgrader: websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - }, - InitFunc: func(ctx context.Context, _ transport.InitPayload) (context.Context, error) { - websocketConnections.Inc() - go func(ctx context.Context) { - <-ctx.Done() - websocketConnections.Dec() - }(ctx) - return ctx, nil - }, - }) - srv.Use(extension.Introspection{}) - - if opts.EnableDebug { - srv.Use(&debug.Tracer{}) - } - - randomnessEnabled = opts.EnableRandomness - - if opts.OverrideUpdateInterval > 0 { - updateInterval = opts.OverrideUpdateInterval - } - - return srv -} - -func WebsocketConnectionsHandler(w http.ResponseWriter, r *http.Request) { - response := map[string]uint32{ - "websocket_connections": websocketConnections.Load(), - } - - responseBytes, err := json.Marshal(response) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - _, _ = w.Write([]byte("error")) - return - } - - _, _ = w.Write(responseBytes) -} diff --git a/pkg/testing/federationtesting/products/graph/model/models_gen.go b/pkg/testing/federationtesting/products/graph/model/models_gen.go deleted file mode 100644 index 8d909fa66..000000000 --- a/pkg/testing/federationtesting/products/graph/model/models_gen.go +++ /dev/null @@ -1,12 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package model - -type Product struct { - Upc string `json:"upc"` - Name string `json:"name"` - Price int `json:"price"` - InStock int `json:"inStock"` -} - -func (Product) IsEntity() {} diff --git a/pkg/testing/federationtesting/products/graph/products.go b/pkg/testing/federationtesting/products/graph/products.go deleted file mode 100644 index 157be37e1..000000000 --- a/pkg/testing/federationtesting/products/graph/products.go +++ /dev/null @@ -1,34 +0,0 @@ -package graph - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/model" -) - -var hats []*model.Product - -func Reset() { - hats = []*model.Product{ - { - Upc: "top-1", - Name: "Trilby", - Price: 11, - InStock: 500, - }, - { - Upc: "top-2", - Name: "Fedora", - Price: 22, - InStock: 1200, - }, - { - Upc: "top-3", - Name: "Boater", - Price: 33, - InStock: 850, - }, - } -} - -func init() { - Reset() -} diff --git a/pkg/testing/federationtesting/products/graph/resolver.go b/pkg/testing/federationtesting/products/graph/resolver.go deleted file mode 100644 index 278fb7db6..000000000 --- a/pkg/testing/federationtesting/products/graph/resolver.go +++ /dev/null @@ -1,6 +0,0 @@ -// This file will not be regenerated automatically. -// -// It serves as dependency injection for your app, add any dependencies you require here. -package graph - -type Resolver struct{} diff --git a/pkg/testing/federationtesting/products/graph/schema.graphqls b/pkg/testing/federationtesting/products/graph/schema.graphqls deleted file mode 100644 index de4df97f2..000000000 --- a/pkg/testing/federationtesting/products/graph/schema.graphqls +++ /dev/null @@ -1,15 +0,0 @@ -extend type Query { - topProducts(first: Int = 5): [Product] -} - -extend type Subscription { - updatedPrice: Product! - updateProductPrice(upc: String!): Product! -} - -type Product @key(fields: "upc") { - upc: String! - name: String! - price: Int! - inStock: Int! -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/products/graph/schema.resolvers.go b/pkg/testing/federationtesting/products/graph/schema.resolvers.go deleted file mode 100644 index f912f4bc2..000000000 --- a/pkg/testing/federationtesting/products/graph/schema.resolvers.go +++ /dev/null @@ -1,90 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.22 - -import ( - "context" - "fmt" - "math/rand" - "time" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/generated" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph/model" -) - -// TopProducts is the resolver for the topProducts field. -func (r *queryResolver) TopProducts(ctx context.Context, first *int) ([]*model.Product, error) { - return hats, nil -} - -// UpdatedPrice is the resolver for the updatedPrice field. -func (r *subscriptionResolver) UpdatedPrice(ctx context.Context) (<-chan *model.Product, error) { - updatedPrice := make(chan *model.Product) - go func() { - for { - select { - case <-ctx.Done(): - return - case <-time.After(updateInterval): - product := hats[0] - if randomnessEnabled { - product = hats[rand.Intn(len(hats)-1)] - product.Price = rand.Intn(maxPrice-minPrice+1) + minPrice - updatedPrice <- product - continue - } - - product.Price = currentPrice - currentPrice += 1 - updatedPrice <- product - } - } - }() - return updatedPrice, nil -} - -// UpdateProductPrice is the resolver for the updateProductPrice field. -func (r *subscriptionResolver) UpdateProductPrice(ctx context.Context, upc string) (<-chan *model.Product, error) { - updatedPrice := make(chan *model.Product) - var product *model.Product - - for _, hat := range hats { - if hat.Upc == upc { - product = hat - break - } - } - - if product == nil { - return nil, fmt.Errorf("unknown product upc: %s", upc) - } - - go func() { - var num int - - for { - num++ - - select { - case <-ctx.Done(): - return - case <-time.After(100 * time.Millisecond): - product.Price = num - updatedPrice <- product - } - } - }() - - return updatedPrice, nil -} - -// Query returns generated.QueryResolver implementation. -func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } - -// Subscription returns generated.SubscriptionResolver implementation. -func (r *Resolver) Subscription() generated.SubscriptionResolver { return &subscriptionResolver{r} } - -type queryResolver struct{ *Resolver } -type subscriptionResolver struct{ *Resolver } diff --git a/pkg/testing/federationtesting/products/graph/variables.go b/pkg/testing/federationtesting/products/graph/variables.go deleted file mode 100644 index 2feb83c7f..000000000 --- a/pkg/testing/federationtesting/products/graph/variables.go +++ /dev/null @@ -1,13 +0,0 @@ -package graph - -import ( - "time" -) - -var ( - randomnessEnabled = true - minPrice = 10 - maxPrice = 1499 - currentPrice = minPrice - updateInterval = time.Second -) diff --git a/pkg/testing/federationtesting/products/handler.go b/pkg/testing/federationtesting/products/handler.go deleted file mode 100644 index 8d4eb36aa..000000000 --- a/pkg/testing/federationtesting/products/handler.go +++ /dev/null @@ -1,17 +0,0 @@ -//go:generate go run -mod=mod github.com/99designs/gqlgen -package products - -import ( - "net/http" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/products/graph" -) - -func Handler() http.Handler { - mux := http.NewServeMux() - - mux.Handle("/", graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true})) - mux.HandleFunc("/websocket_connections", graph.WebsocketConnectionsHandler) - - return mux -} diff --git a/pkg/testing/federationtesting/reviews/gqlgen.yml b/pkg/testing/federationtesting/reviews/gqlgen.yml deleted file mode 100644 index a6b8fcbe3..000000000 --- a/pkg/testing/federationtesting/reviews/gqlgen.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Where are all the schema files located? globs are supported eg src/**/*.graphqls -schema: - - graph/*.graphqls - -# Where should the generated server code go? -exec: - filename: graph/generated/generated.go - package: generated - -federation: - filename: graph/generated/federation.go - package: generated - -# Where should any generated models go? -model: - filename: graph/model/models_gen.go - package: model - -# Where should the resolver implementations go? -resolver: - layout: follow-schema - dir: graph - package: graph - -# Optional: turn on use `gqlgen:"fieldName"` tags in your models -# struct_tag: json - -# Optional: turn on to use []Thing instead of []*Thing -# omit_slice_element_pointers: false - -# Optional: set to speed up generation time by not performing a final validation pass. -# skip_validation: true - -# gqlgen will search for any type names in the schema in these go packages -# if they match it will use them, otherwise it will generate them. -autobind: - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" - -# This section declares type mapping between the GraphQL and go type systems -# -# The first line in each type will be used as defaults for resolver arguments and -# modelgen, the others will be allowed when binding to fields. Configure them to -# your liking -models: - ID: - model: - - github.com/99designs/gqlgen/graphql.ID - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 - Int: - model: - - github.com/99designs/gqlgen/graphql.Int - - github.com/99designs/gqlgen/graphql.Int64 - - github.com/99designs/gqlgen/graphql.Int32 diff --git a/pkg/testing/federationtesting/reviews/graph/attachments.go b/pkg/testing/federationtesting/reviews/graph/attachments.go deleted file mode 100644 index 516863642..000000000 --- a/pkg/testing/federationtesting/reviews/graph/attachments.go +++ /dev/null @@ -1,32 +0,0 @@ -package graph - -import "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" - -var attachments = []model.Attachment{ - model.Question{ - Upc: "top-1", - Body: "How do I turn it on?", - }, - model.Question{ - Upc: "top-3", - Body: "Any recommendations for other teacosies?", - }, - model.Rating{ - Upc: "top-2", - Body: "The best hat I have ever bought in my life.", - Score: 5, - }, - model.Rating{ - Upc: "top-3", - Body: "Terrible teacosy!!!", - Score: 0, - }, - model.Video{ - Upc: "top-2", - Size: 13.37, - }, - model.Video{ - Upc: "top-3", - Size: 4.20, - }, -} diff --git a/pkg/testing/federationtesting/reviews/graph/entity.resolvers.go b/pkg/testing/federationtesting/reviews/graph/entity.resolvers.go deleted file mode 100644 index 3f06f1377..000000000 --- a/pkg/testing/federationtesting/reviews/graph/entity.resolvers.go +++ /dev/null @@ -1,31 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.22 - -import ( - "context" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/generated" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" -) - -// FindProductByUpc is the resolver for the findProductByUpc field. -func (r *entityResolver) FindProductByUpc(ctx context.Context, upc string) (*model.Product, error) { - return &model.Product{ - Upc: upc, - }, nil -} - -// FindUserByID is the resolver for the findUserByID field. -func (r *entityResolver) FindUserByID(ctx context.Context, id string) (*model.User, error) { - return &model.User{ - ID: id, - }, nil -} - -// Entity returns generated.EntityResolver implementation. -func (r *Resolver) Entity() generated.EntityResolver { return &entityResolver{r} } - -type entityResolver struct{ *Resolver } diff --git a/pkg/testing/federationtesting/reviews/graph/generated/federation.go b/pkg/testing/federationtesting/reviews/graph/generated/federation.go deleted file mode 100644 index 5abf78449..000000000 --- a/pkg/testing/federationtesting/reviews/graph/generated/federation.go +++ /dev/null @@ -1,224 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package generated - -import ( - "context" - "errors" - "fmt" - "strings" - "sync" - - "github.com/99designs/gqlgen/plugin/federation/fedruntime" -) - -var ( - ErrUnknownType = errors.New("unknown type") - ErrTypeNotFound = errors.New("type not found") -) - -func (ec *executionContext) __resolve__service(ctx context.Context) (fedruntime.Service, error) { - if ec.DisableIntrospection { - return fedruntime.Service{}, errors.New("federated introspection disabled") - } - - var sdl []string - - for _, src := range sources { - if src.BuiltIn { - continue - } - sdl = append(sdl, src.Input) - } - - return fedruntime.Service{ - SDL: strings.Join(sdl, "\n"), - }, nil -} - -func (ec *executionContext) __resolve_entities(ctx context.Context, representations []map[string]interface{}) []fedruntime.Entity { - list := make([]fedruntime.Entity, len(representations)) - - repsMap := map[string]struct { - i []int - r []map[string]interface{} - }{} - - // We group entities by typename so that we can parallelize their resolution. - // This is particularly helpful when there are entity groups in multi mode. - buildRepresentationGroups := func(reps []map[string]interface{}) { - for i, rep := range reps { - typeName, ok := rep["__typename"].(string) - if !ok { - // If there is no __typename, we just skip the representation; - // we just won't be resolving these unknown types. - ec.Error(ctx, errors.New("__typename must be an existing string")) - continue - } - - _r := repsMap[typeName] - _r.i = append(_r.i, i) - _r.r = append(_r.r, rep) - repsMap[typeName] = _r - } - } - - isMulti := func(typeName string) bool { - switch typeName { - default: - return false - } - } - - resolveEntity := func(ctx context.Context, typeName string, rep map[string]interface{}, idx []int, i int) (err error) { - // we need to do our own panic handling, because we may be called in a - // goroutine, where the usual panic handling can't catch us - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - } - }() - - switch typeName { - case "Product": - resolverName, err := entityResolverNameForProduct(ctx, rep) - if err != nil { - return fmt.Errorf(`finding resolver for Entity "Product": %w`, err) - } - switch resolverName { - - case "findProductByUpc": - id0, err := ec.unmarshalNString2string(ctx, rep["upc"]) - if err != nil { - return fmt.Errorf(`unmarshalling param 0 for findProductByUpc(): %w`, err) - } - entity, err := ec.resolvers.Entity().FindProductByUpc(ctx, id0) - if err != nil { - return fmt.Errorf(`resolving Entity "Product": %w`, err) - } - - list[idx[i]] = entity - return nil - } - case "User": - resolverName, err := entityResolverNameForUser(ctx, rep) - if err != nil { - return fmt.Errorf(`finding resolver for Entity "User": %w`, err) - } - switch resolverName { - - case "findUserByID": - id0, err := ec.unmarshalNID2string(ctx, rep["id"]) - if err != nil { - return fmt.Errorf(`unmarshalling param 0 for findUserByID(): %w`, err) - } - entity, err := ec.resolvers.Entity().FindUserByID(ctx, id0) - if err != nil { - return fmt.Errorf(`resolving Entity "User": %w`, err) - } - - list[idx[i]] = entity - return nil - } - - } - return fmt.Errorf("%w: %s", ErrUnknownType, typeName) - } - - resolveManyEntities := func(ctx context.Context, typeName string, reps []map[string]interface{}, idx []int) (err error) { - // we need to do our own panic handling, because we may be called in a - // goroutine, where the usual panic handling can't catch us - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - } - }() - - switch typeName { - - default: - return errors.New("unknown type: " + typeName) - } - } - - resolveEntityGroup := func(typeName string, reps []map[string]interface{}, idx []int) { - if isMulti(typeName) { - err := resolveManyEntities(ctx, typeName, reps, idx) - if err != nil { - ec.Error(ctx, err) - } - } else { - // if there are multiple entities to resolve, parallelize (similar to - // graphql.FieldSet.Dispatch) - var e sync.WaitGroup - e.Add(len(reps)) - for i, rep := range reps { - i, rep := i, rep - go func(i int, rep map[string]interface{}) { - err := resolveEntity(ctx, typeName, rep, idx, i) - if err != nil { - ec.Error(ctx, err) - } - e.Done() - }(i, rep) - } - e.Wait() - } - } - buildRepresentationGroups(representations) - - switch len(repsMap) { - case 0: - return list - case 1: - for typeName, reps := range repsMap { - resolveEntityGroup(typeName, reps.r, reps.i) - } - return list - default: - var g sync.WaitGroup - g.Add(len(repsMap)) - for typeName, reps := range repsMap { - go func(typeName string, reps []map[string]interface{}, idx []int) { - resolveEntityGroup(typeName, reps, idx) - g.Done() - }(typeName, reps.r, reps.i) - } - g.Wait() - return list - } -} - -func entityResolverNameForProduct(ctx context.Context, rep map[string]interface{}) (string, error) { - for { - var ( - m map[string]interface{} - val interface{} - ok bool - ) - _ = val - m = rep - if _, ok = m["upc"]; !ok { - break - } - return "findProductByUpc", nil - } - return "", fmt.Errorf("%w for Product", ErrTypeNotFound) -} - -func entityResolverNameForUser(ctx context.Context, rep map[string]interface{}) (string, error) { - for { - var ( - m map[string]interface{} - val interface{} - ok bool - ) - _ = val - m = rep - if _, ok = m["id"]; !ok { - break - } - return "findUserByID", nil - } - return "", fmt.Errorf("%w for User", ErrTypeNotFound) -} diff --git a/pkg/testing/federationtesting/reviews/graph/generated/generated.go b/pkg/testing/federationtesting/reviews/graph/generated/generated.go deleted file mode 100644 index 628222a58..000000000 --- a/pkg/testing/federationtesting/reviews/graph/generated/generated.go +++ /dev/null @@ -1,5645 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package generated - -import ( - "bytes" - "context" - "errors" - "fmt" - "strconv" - "sync" - "sync/atomic" - - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/introspection" - "github.com/99designs/gqlgen/plugin/federation/fedruntime" - gqlparser "github.com/vektah/gqlparser/v2" - "github.com/vektah/gqlparser/v2/ast" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" -) - -// region ************************** generated!.gotpl ************************** - -// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. -func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { - return &executableSchema{ - resolvers: cfg.Resolvers, - directives: cfg.Directives, - complexity: cfg.Complexity, - } -} - -type Config struct { - Resolvers ResolverRoot - Directives DirectiveRoot - Complexity ComplexityRoot -} - -type ResolverRoot interface { - Entity() EntityResolver - Mutation() MutationResolver - Product() ProductResolver - Query() QueryResolver - Review() ReviewResolver - User() UserResolver -} - -type DirectiveRoot struct { -} - -type ComplexityRoot struct { - Cat struct { - Name func(childComplexity int) int - } - - Entity struct { - FindProductByUpc func(childComplexity int, upc string) int - FindUserByID func(childComplexity int, id string) int - } - - Mutation struct { - AddReview func(childComplexity int, authorID string, upc string, review string) int - } - - Product struct { - Reviews func(childComplexity int) int - Upc func(childComplexity int) int - } - - Query struct { - Cat func(childComplexity int) int - Me func(childComplexity int) int - __resolve__service func(childComplexity int) int - __resolve_entities func(childComplexity int, representations []map[string]interface{}) int - } - - Question struct { - Body func(childComplexity int) int - Upc func(childComplexity int) int - } - - Rating struct { - Body func(childComplexity int) int - Score func(childComplexity int) int - Upc func(childComplexity int) int - } - - Review struct { - Attachments func(childComplexity int) int - Author func(childComplexity int) int - Body func(childComplexity int) int - Product func(childComplexity int) int - } - - User struct { - ID func(childComplexity int) int - RealName func(childComplexity int) int - Reviews func(childComplexity int) int - Username func(childComplexity int) int - } - - Video struct { - Size func(childComplexity int) int - Upc func(childComplexity int) int - } - - _Service struct { - SDL func(childComplexity int) int - } -} - -type EntityResolver interface { - FindProductByUpc(ctx context.Context, upc string) (*model.Product, error) - FindUserByID(ctx context.Context, id string) (*model.User, error) -} -type MutationResolver interface { - AddReview(ctx context.Context, authorID string, upc string, review string) (*model.Review, error) -} -type ProductResolver interface { - Reviews(ctx context.Context, obj *model.Product) ([]*model.Review, error) -} -type QueryResolver interface { - Me(ctx context.Context) (*model.User, error) - Cat(ctx context.Context) (*model.Cat, error) -} -type ReviewResolver interface { - Attachments(ctx context.Context, obj *model.Review) ([]model.Attachment, error) -} -type UserResolver interface { - Username(ctx context.Context, obj *model.User) (string, error) - Reviews(ctx context.Context, obj *model.User) ([]*model.Review, error) - RealName(ctx context.Context, obj *model.User) (string, error) -} - -type executableSchema struct { - resolvers ResolverRoot - directives DirectiveRoot - complexity ComplexityRoot -} - -func (e *executableSchema) Schema() *ast.Schema { - return parsedSchema -} - -func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { - ec := executionContext{nil, e} - _ = ec - switch typeName + "." + field { - - case "Cat.name": - if e.complexity.Cat.Name == nil { - break - } - - return e.complexity.Cat.Name(childComplexity), true - - case "Entity.findProductByUpc": - if e.complexity.Entity.FindProductByUpc == nil { - break - } - - args, err := ec.field_Entity_findProductByUpc_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Entity.FindProductByUpc(childComplexity, args["upc"].(string)), true - - case "Entity.findUserByID": - if e.complexity.Entity.FindUserByID == nil { - break - } - - args, err := ec.field_Entity_findUserByID_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Entity.FindUserByID(childComplexity, args["id"].(string)), true - - case "Mutation.addReview": - if e.complexity.Mutation.AddReview == nil { - break - } - - args, err := ec.field_Mutation_addReview_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Mutation.AddReview(childComplexity, args["authorID"].(string), args["upc"].(string), args["review"].(string)), true - - case "Product.reviews": - if e.complexity.Product.Reviews == nil { - break - } - - return e.complexity.Product.Reviews(childComplexity), true - - case "Product.upc": - if e.complexity.Product.Upc == nil { - break - } - - return e.complexity.Product.Upc(childComplexity), true - - case "Query.cat": - if e.complexity.Query.Cat == nil { - break - } - - return e.complexity.Query.Cat(childComplexity), true - - case "Query.me": - if e.complexity.Query.Me == nil { - break - } - - return e.complexity.Query.Me(childComplexity), true - - case "Query._service": - if e.complexity.Query.__resolve__service == nil { - break - } - - return e.complexity.Query.__resolve__service(childComplexity), true - - case "Query._entities": - if e.complexity.Query.__resolve_entities == nil { - break - } - - args, err := ec.field_Query__entities_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Query.__resolve_entities(childComplexity, args["representations"].([]map[string]interface{})), true - - case "Question.body": - if e.complexity.Question.Body == nil { - break - } - - return e.complexity.Question.Body(childComplexity), true - - case "Question.upc": - if e.complexity.Question.Upc == nil { - break - } - - return e.complexity.Question.Upc(childComplexity), true - - case "Rating.body": - if e.complexity.Rating.Body == nil { - break - } - - return e.complexity.Rating.Body(childComplexity), true - - case "Rating.score": - if e.complexity.Rating.Score == nil { - break - } - - return e.complexity.Rating.Score(childComplexity), true - - case "Rating.upc": - if e.complexity.Rating.Upc == nil { - break - } - - return e.complexity.Rating.Upc(childComplexity), true - - case "Review.attachments": - if e.complexity.Review.Attachments == nil { - break - } - - return e.complexity.Review.Attachments(childComplexity), true - - case "Review.author": - if e.complexity.Review.Author == nil { - break - } - - return e.complexity.Review.Author(childComplexity), true - - case "Review.body": - if e.complexity.Review.Body == nil { - break - } - - return e.complexity.Review.Body(childComplexity), true - - case "Review.product": - if e.complexity.Review.Product == nil { - break - } - - return e.complexity.Review.Product(childComplexity), true - - case "User.id": - if e.complexity.User.ID == nil { - break - } - - return e.complexity.User.ID(childComplexity), true - - case "User.realName": - if e.complexity.User.RealName == nil { - break - } - - return e.complexity.User.RealName(childComplexity), true - - case "User.reviews": - if e.complexity.User.Reviews == nil { - break - } - - return e.complexity.User.Reviews(childComplexity), true - - case "User.username": - if e.complexity.User.Username == nil { - break - } - - return e.complexity.User.Username(childComplexity), true - - case "Video.size": - if e.complexity.Video.Size == nil { - break - } - - return e.complexity.Video.Size(childComplexity), true - - case "Video.upc": - if e.complexity.Video.Upc == nil { - break - } - - return e.complexity.Video.Upc(childComplexity), true - - case "_Service.sdl": - if e.complexity._Service.SDL == nil { - break - } - - return e.complexity._Service.SDL(childComplexity), true - - } - return 0, false -} - -func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { - rc := graphql.GetOperationContext(ctx) - ec := executionContext{rc, e} - inputUnmarshalMap := graphql.BuildUnmarshalerMap() - first := true - - switch rc.Operation.Operation { - case ast.Query: - return func(ctx context.Context) *graphql.Response { - if !first { - return nil - } - first = false - ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Query(ctx, rc.Operation.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - case ast.Mutation: - return func(ctx context.Context) *graphql.Response { - if !first { - return nil - } - first = false - ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Mutation(ctx, rc.Operation.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - - default: - return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) - } -} - -type executionContext struct { - *graphql.OperationContext - *executableSchema -} - -func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapSchema(parsedSchema), nil -} - -func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil -} - -var sources = []*ast.Source{ - {Name: "../schema.graphqls", Input: `type Query { - me: User - cat: Cat -} - -type Cat { - name: String! -} - -interface Comment { - upc: String! - body: String! -} - -type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! - attachments: [Attachment] -} - -type Question implements Comment { - upc: String! - body: String! -} - -type Rating implements Comment { - upc: String! - body: String! - score: Int! -} - -type Video { - upc: String! - size: Float! -} - -union Attachment = Question | Rating | Video - -extend type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] - realName: String! -} - -extend type Product @key(fields: "upc") { - upc: String! @external - reviews: [Review] -} - -extend type Mutation { - addReview(authorID: String! upc: String!, review: String!): Review! -} -`, BuiltIn: false}, - {Name: "../../federation/directives.graphql", Input: ` - scalar _Any - scalar _FieldSet - - directive @external on FIELD_DEFINITION - directive @requires(fields: _FieldSet!) on FIELD_DEFINITION - directive @provides(fields: _FieldSet!) on FIELD_DEFINITION - directive @extends on OBJECT | INTERFACE - - directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE -`, BuiltIn: true}, - {Name: "../../federation/entity.graphql", Input: ` -# a union of all types that use the @key directive -union _Entity = Product | User - -# fake type to build resolver interfaces for users to implement -type Entity { - findProductByUpc(upc: String!,): Product! - findUserByID(id: ID!,): User! - -} - -type _Service { - sdl: String -} - -extend type Query { - _entities(representations: [_Any!]!): [_Entity]! - _service: _Service! -} -`, BuiltIn: true}, -} -var parsedSchema = gqlparser.MustLoadSchema(sources...) - -// endregion ************************** generated!.gotpl ************************** - -// region ***************************** args.gotpl ***************************** - -func (ec *executionContext) field_Entity_findProductByUpc_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["upc"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("upc")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["upc"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Entity_findUserByID_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["id"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) - arg0, err = ec.unmarshalNID2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["id"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Mutation_addReview_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["authorID"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("authorID")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["authorID"] = arg0 - var arg1 string - if tmp, ok := rawArgs["upc"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("upc")) - arg1, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["upc"] = arg1 - var arg2 string - if tmp, ok := rawArgs["review"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("review")) - arg2, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["review"] = arg2 - return args, nil -} - -func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["name"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query__entities_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 []map[string]interface{} - if tmp, ok := rawArgs["representations"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("representations")) - arg0, err = ec.unmarshalN_Any2ᚕmapᚄ(ctx, tmp) - if err != nil { - return nil, err - } - } - args["representations"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -// endregion ***************************** args.gotpl ***************************** - -// region ************************** directives.gotpl ************************** - -// endregion ************************** directives.gotpl ************************** - -// region **************************** field.gotpl ***************************** - -func (ec *executionContext) _Cat_name(ctx context.Context, field graphql.CollectedField, obj *model.Cat) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Cat_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Cat_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Cat", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Entity_findProductByUpc(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Entity_findProductByUpc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Entity().FindProductByUpc(rctx, fc.Args["upc"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Product) - fc.Result = res - return ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Entity_findProductByUpc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Entity", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - case "reviews": - return ec.fieldContext_Product_reviews(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Entity_findProductByUpc_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Entity_findUserByID(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Entity_findUserByID(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Entity().FindUserByID(rctx, fc.Args["id"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Entity_findUserByID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Entity", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "reviews": - return ec.fieldContext_User_reviews(ctx, field) - case "realName": - return ec.fieldContext_User_realName(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Entity_findUserByID_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Mutation_addReview(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_addReview(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().AddReview(rctx, fc.Args["authorID"].(string), fc.Args["upc"].(string), fc.Args["review"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Review) - fc.Result = res - return ec.marshalNReview2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_addReview(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "body": - return ec.fieldContext_Review_body(ctx, field) - case "author": - return ec.fieldContext_Review_author(ctx, field) - case "product": - return ec.fieldContext_Review_product(ctx, field) - case "attachments": - return ec.fieldContext_Review_attachments(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Review", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_addReview_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Product_upc(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_upc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Upc, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_upc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Product_reviews(ctx context.Context, field graphql.CollectedField, obj *model.Product) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Product_reviews(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Product().Reviews(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]*model.Review) - fc.Result = res - return ec.marshalOReview2ᚕᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Product_reviews(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Product", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "body": - return ec.fieldContext_Review_body(ctx, field) - case "author": - return ec.fieldContext_Review_author(ctx, field) - case "product": - return ec.fieldContext_Review_product(ctx, field) - case "attachments": - return ec.fieldContext_Review_attachments(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Review", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_me(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_me(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Me(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalOUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_me(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "reviews": - return ec.fieldContext_User_reviews(ctx, field) - case "realName": - return ec.fieldContext_User_realName(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query_cat(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_cat(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Cat(rctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*model.Cat) - fc.Result = res - return ec.marshalOCat2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐCat(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_cat(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext_Cat_name(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Cat", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query__entities(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__entities(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.__resolve_entities(ctx, fc.Args["representations"].([]map[string]interface{})), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]fedruntime.Entity) - fc.Result = res - return ec.marshalN_Entity2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__entities(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type _Entity does not have child fields") - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query__entities_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query__service(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query__service(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.__resolve__service(ctx) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(fedruntime.Service) - fc.Result = res - return ec.marshalN_Service2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐService(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query__service(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "sdl": - return ec.fieldContext__Service_sdl(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type _Service", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectType(fc.Args["name"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___schema(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectSchema() - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Schema) - fc.Result = res - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "description": - return ec.fieldContext___Schema_description(ctx, field) - case "types": - return ec.fieldContext___Schema_types(ctx, field) - case "queryType": - return ec.fieldContext___Schema_queryType(ctx, field) - case "mutationType": - return ec.fieldContext___Schema_mutationType(ctx, field) - case "subscriptionType": - return ec.fieldContext___Schema_subscriptionType(ctx, field) - case "directives": - return ec.fieldContext___Schema_directives(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Question_upc(ctx context.Context, field graphql.CollectedField, obj *model.Question) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Question_upc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Upc, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Question_upc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Question", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Question_body(ctx context.Context, field graphql.CollectedField, obj *model.Question) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Question_body(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Body, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Question_body(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Question", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Rating_upc(ctx context.Context, field graphql.CollectedField, obj *model.Rating) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Rating_upc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Upc, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Rating_upc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Rating", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Rating_body(ctx context.Context, field graphql.CollectedField, obj *model.Rating) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Rating_body(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Body, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Rating_body(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Rating", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Rating_score(ctx context.Context, field graphql.CollectedField, obj *model.Rating) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Rating_score(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Score, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(int) - fc.Result = res - return ec.marshalNInt2int(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Rating_score(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Rating", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Int does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Review_body(ctx context.Context, field graphql.CollectedField, obj *model.Review) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Review_body(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Body, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Review_body(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Review", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Review_author(ctx context.Context, field graphql.CollectedField, obj *model.Review) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Review_author(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Author, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.User) - fc.Result = res - return ec.marshalNUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐUser(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Review_author(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Review", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_User_id(ctx, field) - case "username": - return ec.fieldContext_User_username(ctx, field) - case "reviews": - return ec.fieldContext_User_reviews(ctx, field) - case "realName": - return ec.fieldContext_User_realName(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type User", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Review_product(ctx context.Context, field graphql.CollectedField, obj *model.Review) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Review_product(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Product, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*model.Product) - fc.Result = res - return ec.marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐProduct(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Review_product(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Review", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "upc": - return ec.fieldContext_Product_upc(ctx, field) - case "reviews": - return ec.fieldContext_Product_reviews(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Product", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Review_attachments(ctx context.Context, field graphql.CollectedField, obj *model.Review) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Review_attachments(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Review().Attachments(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]model.Attachment) - fc.Result = res - return ec.marshalOAttachment2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐAttachment(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Review_attachments(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Review", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Attachment does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_id(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_id(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.ID, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_username(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_username(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.User().Username(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_username(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _User_reviews(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_reviews(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.User().Reviews(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]*model.Review) - fc.Result = res - return ec.marshalOReview2ᚕᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_reviews(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "body": - return ec.fieldContext_Review_body(ctx, field) - case "author": - return ec.fieldContext_Review_author(ctx, field) - case "product": - return ec.fieldContext_Review_product(ctx, field) - case "attachments": - return ec.fieldContext_Review_attachments(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Review", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _User_realName(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_User_realName(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.User().RealName(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_User_realName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "User", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Video_upc(ctx context.Context, field graphql.CollectedField, obj *model.Video) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Video_upc(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Upc, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Video_upc(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Video", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Video_size(ctx context.Context, field graphql.CollectedField, obj *model.Video) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Video_size(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Size, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(float64) - fc.Result = res - return ec.marshalNFloat2float64(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Video_size(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Video", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Float does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) __Service_sdl(ctx context.Context, field graphql.CollectedField, obj *fedruntime.Service) (ret graphql.Marshaler) { - fc, err := ec.fieldContext__Service_sdl(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SDL, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalOString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext__Service_sdl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "_Service", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_locations(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Locations, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]string) - fc.Result = res - return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __DirectiveLocation does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsRepeatable, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_types(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Types(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_queryType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.QueryType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_mutationType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.MutationType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SubscriptionType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_directives(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Directives(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Directive) - fc.Result = res - return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Directive_name(ctx, field) - case "description": - return ec.fieldContext___Directive_description(ctx, field) - case "locations": - return ec.fieldContext___Directive_locations(ctx, field) - case "args": - return ec.fieldContext___Directive_args(ctx, field) - case "isRepeatable": - return ec.fieldContext___Directive_isRepeatable(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_kind(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Kind(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalN__TypeKind2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __TypeKind does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_fields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Field) - fc.Result = res - return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Field_name(ctx, field) - case "description": - return ec.fieldContext___Field_description(ctx, field) - case "args": - return ec.fieldContext___Field_args(ctx, field) - case "type": - return ec.fieldContext___Field_type(ctx, field) - case "isDeprecated": - return ec.fieldContext___Field_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___Field_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_interfaces(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Interfaces(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_possibleTypes(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.PossibleTypes(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_enumValues(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.EnumValue) - fc.Result = res - return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___EnumValue_name(ctx, field) - case "description": - return ec.fieldContext___EnumValue_description(ctx, field) - case "isDeprecated": - return ec.fieldContext___EnumValue_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___EnumValue_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_inputFields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.InputFields(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_ofType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.OfType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SpecifiedByURL(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -// endregion **************************** field.gotpl ***************************** - -// region **************************** input.gotpl ***************************** - -// endregion **************************** input.gotpl ***************************** - -// region ************************** interface.gotpl *************************** - -func (ec *executionContext) _Attachment(ctx context.Context, sel ast.SelectionSet, obj model.Attachment) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Question: - return ec._Question(ctx, sel, &obj) - case *model.Question: - if obj == nil { - return graphql.Null - } - return ec._Question(ctx, sel, obj) - case model.Rating: - return ec._Rating(ctx, sel, &obj) - case *model.Rating: - if obj == nil { - return graphql.Null - } - return ec._Rating(ctx, sel, obj) - case model.Video: - return ec._Video(ctx, sel, &obj) - case *model.Video: - if obj == nil { - return graphql.Null - } - return ec._Video(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) _Comment(ctx context.Context, sel ast.SelectionSet, obj model.Comment) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Question: - return ec._Question(ctx, sel, &obj) - case *model.Question: - if obj == nil { - return graphql.Null - } - return ec._Question(ctx, sel, obj) - case model.Rating: - return ec._Rating(ctx, sel, &obj) - case *model.Rating: - if obj == nil { - return graphql.Null - } - return ec._Rating(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -func (ec *executionContext) __Entity(ctx context.Context, sel ast.SelectionSet, obj fedruntime.Entity) graphql.Marshaler { - switch obj := (obj).(type) { - case nil: - return graphql.Null - case model.Product: - return ec._Product(ctx, sel, &obj) - case *model.Product: - if obj == nil { - return graphql.Null - } - return ec._Product(ctx, sel, obj) - case model.User: - return ec._User(ctx, sel, &obj) - case *model.User: - if obj == nil { - return graphql.Null - } - return ec._User(ctx, sel, obj) - default: - panic(fmt.Errorf("unexpected type %T", obj)) - } -} - -// endregion ************************** interface.gotpl *************************** - -// region **************************** object.gotpl **************************** - -var catImplementors = []string{"Cat"} - -func (ec *executionContext) _Cat(ctx context.Context, sel ast.SelectionSet, obj *model.Cat) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, catImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Cat") - case "name": - - out.Values[i] = ec._Cat_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var entityImplementors = []string{"Entity"} - -func (ec *executionContext) _Entity(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, entityImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Entity", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Entity") - case "findProductByUpc": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Entity_findProductByUpc(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "findUserByID": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Entity_findUserByID(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var mutationImplementors = []string{"Mutation"} - -func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Mutation", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Mutation") - case "addReview": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_addReview(ctx, field) - }) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var productImplementors = []string{"Product", "_Entity"} - -func (ec *executionContext) _Product(ctx context.Context, sel ast.SelectionSet, obj *model.Product) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, productImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Product") - case "upc": - - out.Values[i] = ec._Product_upc(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "reviews": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Product_reviews(ctx, field, obj) - return res - } - - out.Concurrently(i, func() graphql.Marshaler { - return innerFunc(ctx) - - }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var queryImplementors = []string{"Query"} - -func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Query", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Query") - case "me": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_me(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "cat": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_cat(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "_entities": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query__entities(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "_service": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query__service(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "__type": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___type(ctx, field) - }) - - case "__schema": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___schema(ctx, field) - }) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var questionImplementors = []string{"Question", "Comment", "Attachment"} - -func (ec *executionContext) _Question(ctx context.Context, sel ast.SelectionSet, obj *model.Question) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, questionImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Question") - case "upc": - - out.Values[i] = ec._Question_upc(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "body": - - out.Values[i] = ec._Question_body(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var ratingImplementors = []string{"Rating", "Comment", "Attachment"} - -func (ec *executionContext) _Rating(ctx context.Context, sel ast.SelectionSet, obj *model.Rating) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, ratingImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Rating") - case "upc": - - out.Values[i] = ec._Rating_upc(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "body": - - out.Values[i] = ec._Rating_body(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "score": - - out.Values[i] = ec._Rating_score(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var reviewImplementors = []string{"Review"} - -func (ec *executionContext) _Review(ctx context.Context, sel ast.SelectionSet, obj *model.Review) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, reviewImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Review") - case "body": - - out.Values[i] = ec._Review_body(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "author": - - out.Values[i] = ec._Review_author(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "product": - - out.Values[i] = ec._Review_product(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "attachments": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Review_attachments(ctx, field, obj) - return res - } - - out.Concurrently(i, func() graphql.Marshaler { - return innerFunc(ctx) - - }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var userImplementors = []string{"User", "_Entity"} - -func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *model.User) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("User") - case "id": - - out.Values[i] = ec._User_id(ctx, field, obj) - - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "username": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._User_username(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - out.Concurrently(i, func() graphql.Marshaler { - return innerFunc(ctx) - - }) - case "reviews": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._User_reviews(ctx, field, obj) - return res - } - - out.Concurrently(i, func() graphql.Marshaler { - return innerFunc(ctx) - - }) - case "realName": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._User_realName(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - } - - out.Concurrently(i, func() graphql.Marshaler { - return innerFunc(ctx) - - }) - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var videoImplementors = []string{"Video", "Attachment"} - -func (ec *executionContext) _Video(ctx context.Context, sel ast.SelectionSet, obj *model.Video) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, videoImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Video") - case "upc": - - out.Values[i] = ec._Video_upc(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "size": - - out.Values[i] = ec._Video_size(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var _ServiceImplementors = []string{"_Service"} - -func (ec *executionContext) __Service(ctx context.Context, sel ast.SelectionSet, obj *fedruntime.Service) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, _ServiceImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("_Service") - case "sdl": - - out.Values[i] = ec.__Service_sdl(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __DirectiveImplementors = []string{"__Directive"} - -func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Directive") - case "name": - - out.Values[i] = ec.___Directive_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Directive_description(ctx, field, obj) - - case "locations": - - out.Values[i] = ec.___Directive_locations(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "args": - - out.Values[i] = ec.___Directive_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isRepeatable": - - out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __EnumValueImplementors = []string{"__EnumValue"} - -func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__EnumValue") - case "name": - - out.Values[i] = ec.___EnumValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___EnumValue_description(ctx, field, obj) - - case "isDeprecated": - - out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __FieldImplementors = []string{"__Field"} - -func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Field") - case "name": - - out.Values[i] = ec.___Field_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Field_description(ctx, field, obj) - - case "args": - - out.Values[i] = ec.___Field_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "type": - - out.Values[i] = ec.___Field_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isDeprecated": - - out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __InputValueImplementors = []string{"__InputValue"} - -func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__InputValue") - case "name": - - out.Values[i] = ec.___InputValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___InputValue_description(ctx, field, obj) - - case "type": - - out.Values[i] = ec.___InputValue_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "defaultValue": - - out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __SchemaImplementors = []string{"__Schema"} - -func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Schema") - case "description": - - out.Values[i] = ec.___Schema_description(ctx, field, obj) - - case "types": - - out.Values[i] = ec.___Schema_types(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "queryType": - - out.Values[i] = ec.___Schema_queryType(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "mutationType": - - out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) - - case "subscriptionType": - - out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) - - case "directives": - - out.Values[i] = ec.___Schema_directives(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __TypeImplementors = []string{"__Type"} - -func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Type") - case "kind": - - out.Values[i] = ec.___Type_kind(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "name": - - out.Values[i] = ec.___Type_name(ctx, field, obj) - - case "description": - - out.Values[i] = ec.___Type_description(ctx, field, obj) - - case "fields": - - out.Values[i] = ec.___Type_fields(ctx, field, obj) - - case "interfaces": - - out.Values[i] = ec.___Type_interfaces(ctx, field, obj) - - case "possibleTypes": - - out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) - - case "enumValues": - - out.Values[i] = ec.___Type_enumValues(ctx, field, obj) - - case "inputFields": - - out.Values[i] = ec.___Type_inputFields(ctx, field, obj) - - case "ofType": - - out.Values[i] = ec.___Type_ofType(ctx, field, obj) - - case "specifiedByURL": - - out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -// endregion **************************** object.gotpl **************************** - -// region ***************************** type.gotpl ***************************** - -func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { - res, err := graphql.UnmarshalFloatContext(ctx, v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.SelectionSet, v float64) graphql.Marshaler { - res := graphql.MarshalFloatContext(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return graphql.WrapContextMarshaler(ctx, res) -} - -func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalID(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalID(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNInt2int(ctx context.Context, v interface{}) (int, error) { - res, err := graphql.UnmarshalInt(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNInt2int(ctx context.Context, sel ast.SelectionSet, v int) graphql.Marshaler { - res := graphql.MarshalInt(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalNProduct2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v model.Product) graphql.Marshaler { - return ec._Product(ctx, sel, &v) -} - -func (ec *executionContext) marshalNProduct2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐProduct(ctx context.Context, sel ast.SelectionSet, v *model.Product) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._Product(ctx, sel, v) -} - -func (ec *executionContext) marshalNReview2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx context.Context, sel ast.SelectionSet, v model.Review) graphql.Marshaler { - return ec._Review(ctx, sel, &v) -} - -func (ec *executionContext) marshalNReview2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx context.Context, sel ast.SelectionSet, v *model.Review) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._Review(ctx, sel, v) -} - -func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalNUser2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler { - return ec._User(ctx, sel, &v) -} - -func (ec *executionContext) marshalNUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._User(ctx, sel, v) -} - -func (ec *executionContext) unmarshalN_Any2map(ctx context.Context, v interface{}) (map[string]interface{}, error) { - res, err := graphql.UnmarshalMap(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN_Any2map(ctx context.Context, sel ast.SelectionSet, v map[string]interface{}) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - res := graphql.MarshalMap(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN_Any2ᚕmapᚄ(ctx context.Context, v interface{}) ([]map[string]interface{}, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]map[string]interface{}, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN_Any2map(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN_Any2ᚕmapᚄ(ctx context.Context, sel ast.SelectionSet, v []map[string]interface{}) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - for i := range v { - ret[i] = ec.marshalN_Any2map(ctx, sel, v[i]) - } - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN_Entity2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx context.Context, sel ast.SelectionSet, v []fedruntime.Entity) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalO_Entity2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) unmarshalN_FieldSet2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN_FieldSet2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalN_Service2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐService(ctx context.Context, sel ast.SelectionSet, v fedruntime.Service) graphql.Marshaler { - return ec.__Service(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { - return ec.___Directive(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]string, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { - return ec.___EnumValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { - return ec.___Field(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { - return ec.___InputValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { - return ec.___Type(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalOAttachment2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐAttachment(ctx context.Context, sel ast.SelectionSet, v model.Attachment) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Attachment(ctx, sel, v) -} - -func (ec *executionContext) marshalOAttachment2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐAttachment(ctx context.Context, sel ast.SelectionSet, v []model.Attachment) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalOAttachment2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐAttachment(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - return res -} - -func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalBoolean(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalBoolean(*v) - return res -} - -func (ec *executionContext) marshalOCat2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐCat(ctx context.Context, sel ast.SelectionSet, v *model.Cat) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Cat(ctx, sel, v) -} - -func (ec *executionContext) marshalOReview2ᚕᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx context.Context, sel ast.SelectionSet, v []*model.Review) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalOReview2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - return ret -} - -func (ec *executionContext) marshalOReview2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐReview(ctx context.Context, sel ast.SelectionSet, v *model.Review) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Review(ctx, sel, v) -} - -func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - return res -} - -func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalString(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalString(*v) - return res -} - -func (ec *executionContext) marshalOUser2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋfederationtestingᚋreviewsᚋgraphᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._User(ctx, sel, v) -} - -func (ec *executionContext) marshalO_Entity2githubᚗcomᚋ99designsᚋgqlgenᚋpluginᚋfederationᚋfedruntimeᚐEntity(ctx context.Context, sel ast.SelectionSet, v fedruntime.Entity) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.__Entity(ctx, sel, v) -} - -func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Schema(ctx, sel, v) -} - -func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -// endregion ***************************** type.gotpl ***************************** diff --git a/pkg/testing/federationtesting/reviews/graph/handler.go b/pkg/testing/federationtesting/reviews/graph/handler.go deleted file mode 100644 index 5575be741..000000000 --- a/pkg/testing/federationtesting/reviews/graph/handler.go +++ /dev/null @@ -1,31 +0,0 @@ -package graph - -import ( - "net/http" - - "github.com/99designs/gqlgen/graphql/handler" - "github.com/99designs/gqlgen/graphql/handler/debug" - "github.com/99designs/gqlgen/graphql/handler/extension" - "github.com/99designs/gqlgen/graphql/handler/transport" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/generated" -) - -type EndpointOptions struct { - EnableDebug bool -} - -var TestOptions = EndpointOptions{ - EnableDebug: false, -} - -func GraphQLEndpointHandler(opts EndpointOptions) http.Handler { - srv := handler.New(generated.NewExecutableSchema(generated.Config{Resolvers: &Resolver{}})) - srv.AddTransport(transport.POST{}) - srv.Use(extension.Introspection{}) - if opts.EnableDebug { - srv.Use(&debug.Tracer{}) - } - - return srv -} diff --git a/pkg/testing/federationtesting/reviews/graph/model/models.go b/pkg/testing/federationtesting/reviews/graph/model/models.go deleted file mode 100644 index 513940352..000000000 --- a/pkg/testing/federationtesting/reviews/graph/model/models.go +++ /dev/null @@ -1,19 +0,0 @@ -package model - -type Product struct { - Upc string `json:"upc"` -} - -func (Product) IsEntity() {} - -type Review struct { - Body string - Author *User - Product *Product -} - -type User struct { - ID string `json:"id"` -} - -func (User) IsEntity() {} diff --git a/pkg/testing/federationtesting/reviews/graph/model/models_gen.go b/pkg/testing/federationtesting/reviews/graph/model/models_gen.go deleted file mode 100644 index cbcbfe215..000000000 --- a/pkg/testing/federationtesting/reviews/graph/model/models_gen.go +++ /dev/null @@ -1,47 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package model - -type Attachment interface { - IsAttachment() -} - -type Comment interface { - IsComment() - GetUpc() string - GetBody() string -} - -type Cat struct { - Name string `json:"name"` -} - -type Question struct { - Upc string `json:"upc"` - Body string `json:"body"` -} - -func (Question) IsComment() {} -func (this Question) GetUpc() string { return this.Upc } -func (this Question) GetBody() string { return this.Body } - -func (Question) IsAttachment() {} - -type Rating struct { - Upc string `json:"upc"` - Body string `json:"body"` - Score int `json:"score"` -} - -func (Rating) IsComment() {} -func (this Rating) GetUpc() string { return this.Upc } -func (this Rating) GetBody() string { return this.Body } - -func (Rating) IsAttachment() {} - -type Video struct { - Upc string `json:"upc"` - Size float64 `json:"size"` -} - -func (Video) IsAttachment() {} diff --git a/pkg/testing/federationtesting/reviews/graph/resolver.go b/pkg/testing/federationtesting/reviews/graph/resolver.go deleted file mode 100644 index 278fb7db6..000000000 --- a/pkg/testing/federationtesting/reviews/graph/resolver.go +++ /dev/null @@ -1,6 +0,0 @@ -// This file will not be regenerated automatically. -// -// It serves as dependency injection for your app, add any dependencies you require here. -package graph - -type Resolver struct{} diff --git a/pkg/testing/federationtesting/reviews/graph/reviews.go b/pkg/testing/federationtesting/reviews/graph/reviews.go deleted file mode 100644 index 7488fc966..000000000 --- a/pkg/testing/federationtesting/reviews/graph/reviews.go +++ /dev/null @@ -1,23 +0,0 @@ -package graph - -import ( - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" -) - -var reviews = []*model.Review{ - { - Body: "A highly effective form of birth control.", - Product: &model.Product{Upc: "top-1"}, - Author: &model.User{ID: "1234"}, - }, - { - Body: "Fedoras are one of the most fashionable hats around and can look great with a variety of outfits.", - Product: &model.Product{Upc: "top-2"}, - Author: &model.User{ID: "1234"}, - }, - { - Body: "This is the last straw. Hat you will wear. 11/10", - Product: &model.Product{Upc: "top-3"}, - Author: &model.User{ID: "7777"}, - }, -} diff --git a/pkg/testing/federationtesting/reviews/graph/schema.graphqls b/pkg/testing/federationtesting/reviews/graph/schema.graphqls deleted file mode 100644 index 545c5b31f..000000000 --- a/pkg/testing/federationtesting/reviews/graph/schema.graphqls +++ /dev/null @@ -1,54 +0,0 @@ -type Query { - me: User - cat: Cat -} - -type Cat { - name: String! -} - -interface Comment { - upc: String! - body: String! -} - -type Review { - body: String! - author: User! @provides(fields: "username") - product: Product! - attachments: [Attachment] -} - -type Question implements Comment { - upc: String! - body: String! -} - -type Rating implements Comment { - upc: String! - body: String! - score: Int! -} - -type Video { - upc: String! - size: Float! -} - -union Attachment = Question | Rating | Video - -extend type User @key(fields: "id") { - id: ID! @external - username: String! @external - reviews: [Review] - realName: String! -} - -extend type Product @key(fields: "upc") { - upc: String! @external - reviews: [Review] -} - -extend type Mutation { - addReview(authorID: String! upc: String!, review: String!): Review! -} diff --git a/pkg/testing/federationtesting/reviews/graph/schema.resolvers.go b/pkg/testing/federationtesting/reviews/graph/schema.resolvers.go deleted file mode 100644 index 5b4486893..000000000 --- a/pkg/testing/federationtesting/reviews/graph/schema.resolvers.go +++ /dev/null @@ -1,129 +0,0 @@ -package graph - -// This file will be automatically regenerated based on the schema, any resolver implementations -// will be copied through when generating and any unknown code will be moved to the end. -// Code generated by github.com/99designs/gqlgen version v0.17.22 - -import ( - "context" - "fmt" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/generated" - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph/model" -) - -// AddReview is the resolver for the addReview field. -func (r *mutationResolver) AddReview(ctx context.Context, authorID string, upc string, review string) (*model.Review, error) { - record := &model.Review{ - Body: review, - Author: &model.User{ID: authorID}, - Product: &model.Product{Upc: upc}, - } - - reviews = append(reviews, record) - - return record, nil -} - -// Reviews is the resolver for the reviews field. -func (r *productResolver) Reviews(ctx context.Context, obj *model.Product) ([]*model.Review, error) { - var res []*model.Review - - for _, review := range reviews { - if review.Product.Upc == obj.Upc { - res = append(res, review) - } - } - - return res, nil -} - -// Me is the resolver for the me field. -func (r *queryResolver) Me(ctx context.Context) (*model.User, error) { - return &model.User{ - ID: "1234", - }, nil -} - -// Cat is the resolver for the cat field. -func (r *queryResolver) Cat(ctx context.Context) (*model.Cat, error) { - return &model.Cat{ - Name: "Pepper", - }, nil -} - -// Attachments is the resolver for the attachments field. -func (r *reviewResolver) Attachments(ctx context.Context, obj *model.Review) ([]model.Attachment, error) { - var res []model.Attachment - - for _, attachment := range attachments { - switch v := attachment.(type) { - case model.Question: - if v.Upc == obj.Product.Upc { - res = append(res, attachment) - } - case model.Rating: - if v.Upc == obj.Product.Upc { - res = append(res, attachment) - } - case model.Video: - if v.Upc == obj.Product.Upc { - res = append(res, attachment) - } - } - } - - return res, nil -} - -// Username is the resolver for the username field. -func (r *userResolver) Username(ctx context.Context, obj *model.User) (string, error) { - username := fmt.Sprintf("User %s", obj.ID) - if obj.ID == "1234" { - username = "Me" - } - return username, nil -} - -// Reviews is the resolver for the reviews field. -func (r *userResolver) Reviews(ctx context.Context, obj *model.User) ([]*model.Review, error) { - var res []*model.Review - - for _, review := range reviews { - if review.Author.ID == obj.ID { - res = append(res, review) - } - } - - return res, nil -} - -// RealName is the resolver for the realName field. -func (r *userResolver) RealName(ctx context.Context, obj *model.User) (string, error) { - realName := fmt.Sprintf("User %s", obj.ID) - if obj.ID == "1234" { - realName = "User Usington" - } - return realName, nil -} - -// Mutation returns generated.MutationResolver implementation. -func (r *Resolver) Mutation() generated.MutationResolver { return &mutationResolver{r} } - -// Product returns generated.ProductResolver implementation. -func (r *Resolver) Product() generated.ProductResolver { return &productResolver{r} } - -// Query returns generated.QueryResolver implementation. -func (r *Resolver) Query() generated.QueryResolver { return &queryResolver{r} } - -// Review returns generated.ReviewResolver implementation. -func (r *Resolver) Review() generated.ReviewResolver { return &reviewResolver{r} } - -// User returns generated.UserResolver implementation. -func (r *Resolver) User() generated.UserResolver { return &userResolver{r} } - -type mutationResolver struct{ *Resolver } -type productResolver struct{ *Resolver } -type queryResolver struct{ *Resolver } -type reviewResolver struct{ *Resolver } -type userResolver struct{ *Resolver } diff --git a/pkg/testing/federationtesting/reviews/handler.go b/pkg/testing/federationtesting/reviews/handler.go deleted file mode 100644 index c520b5ed2..000000000 --- a/pkg/testing/federationtesting/reviews/handler.go +++ /dev/null @@ -1,12 +0,0 @@ -//go:generate go run -mod=mod github.com/99designs/gqlgen -package reviews - -import ( - "net/http" - - "github.com/wundergraph/graphql-go-tools/pkg/testing/federationtesting/reviews/graph" -) - -func Handler() http.Handler { - return graph.GraphQLEndpointHandler(graph.EndpointOptions{EnableDebug: true}) -} diff --git a/pkg/testing/federationtesting/testdata/mutations/mutation_with_variables.query b/pkg/testing/federationtesting/testdata/mutations/mutation_with_variables.query deleted file mode 100644 index 6f86f1b2c..000000000 --- a/pkg/testing/federationtesting/testdata/mutations/mutation_with_variables.query +++ /dev/null @@ -1,8 +0,0 @@ -mutation AddReview($authorID: String!, $upc: String!, $review: String!) { - addReview(authorID: $authorID upc: $upc, review: $review) { - body - author { - username - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/complex_nesting.graphql b/pkg/testing/federationtesting/testdata/queries/complex_nesting.graphql deleted file mode 100644 index 771f8ebba..000000000 --- a/pkg/testing/federationtesting/testdata/queries/complex_nesting.graphql +++ /dev/null @@ -1,41 +0,0 @@ -query ComplexNesting { - me { - id - username - history { - ... on Store { - location - } - ... on Purchase { - wallet { - currency - } - } - ... on Sale { - location - product { - upc - name - } - } - } - reviews { - __typename - attachments { - ... on Comment { - upc - ... on Rating { - body - } - } - ... on Question { - body - } - ... on Video { - upc - size - } - } - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/interface.query b/pkg/testing/federationtesting/testdata/queries/interface.query deleted file mode 100644 index 4c8f56e47..000000000 --- a/pkg/testing/federationtesting/testdata/queries/interface.query +++ /dev/null @@ -1,21 +0,0 @@ -query MyHistory { - me { - username - history { - ... on Purchase { - wallet { - amount - ... on WalletType1 { - specialField1 - } - ... on WalletType2 { - specialField2 - } - } - } - ... on Sale { - rating - } - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/interface_fragment_on_object.graphql b/pkg/testing/federationtesting/testdata/queries/interface_fragment_on_object.graphql deleted file mode 100644 index 80aa73899..000000000 --- a/pkg/testing/federationtesting/testdata/queries/interface_fragment_on_object.graphql +++ /dev/null @@ -1,10 +0,0 @@ -query InterfaceFragment { - me { - ... on Identifiable { - id - } - ... on User { - username - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/interface_fragments_on_union.graphql b/pkg/testing/federationtesting/testdata/queries/interface_fragments_on_union.graphql deleted file mode 100644 index 84eba5a47..000000000 --- a/pkg/testing/federationtesting/testdata/queries/interface_fragments_on_union.graphql +++ /dev/null @@ -1,12 +0,0 @@ -query InterfaceFragmentsOnUnion { - histories { - ... on Store { - __typename - location - } - ... on Info { - __typename - quantity - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/merged_field.graphql b/pkg/testing/federationtesting/testdata/queries/merged_field.graphql deleted file mode 100644 index f4b58a646..000000000 --- a/pkg/testing/federationtesting/testdata/queries/merged_field.graphql +++ /dev/null @@ -1,18 +0,0 @@ -query MergedField { - cat { - name - } - me { - id - username - realName - reviews { - body - } - history { - ... on Sale { - rating - } - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/multiple_queries.query b/pkg/testing/federationtesting/testdata/queries/multiple_queries.query deleted file mode 100644 index 08555d9e9..000000000 --- a/pkg/testing/federationtesting/testdata/queries/multiple_queries.query +++ /dev/null @@ -1,12 +0,0 @@ -query { - topProducts { - __typename - price - upc - } - me { - __typename - id - username - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_nested_fragments.query b/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_nested_fragments.query deleted file mode 100644 index b28b42959..000000000 --- a/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_nested_fragments.query +++ /dev/null @@ -1,30 +0,0 @@ -fragment ProductFragment on Product { - __typename - price - upc -} - -fragment ReviewFragment on Review { - __typename - product { - ...ProductFragment - } -} - -fragment UserFragment on User { - __typename - id - username - reviews { - ...ReviewFragment - } -} - -query { - topProducts { - ...ProductFragment - } - me { - ...UserFragment - } -} diff --git a/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_union_return.query b/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_union_return.query deleted file mode 100644 index e96f60e2a..000000000 --- a/pkg/testing/federationtesting/testdata/queries/multiple_queries_with_union_return.query +++ /dev/null @@ -1,27 +0,0 @@ -query Histories { - me { - __typename - id - username - } - histories { - __typename - ... on Sale { - product { - __typename - upc - } - rating - } - ... on Purchase { - product { - __typename - upc - } - wallet { - __typename - currency - } - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/multiple_upstream.query b/pkg/testing/federationtesting/testdata/queries/multiple_upstream.query deleted file mode 100644 index 842b2019f..000000000 --- a/pkg/testing/federationtesting/testdata/queries/multiple_upstream.query +++ /dev/null @@ -1,11 +0,0 @@ -query MultipleServers { - topProducts { - name - reviews { - body - author { - username - } - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/object_fragment_on_interface.graphql b/pkg/testing/federationtesting/testdata/queries/object_fragment_on_interface.graphql deleted file mode 100644 index dc08d01a9..000000000 --- a/pkg/testing/federationtesting/testdata/queries/object_fragment_on_interface.graphql +++ /dev/null @@ -1,9 +0,0 @@ -query InterfaceResponse { - identifiable { - __typename - id - ... on User { - username - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/single_upstream.query b/pkg/testing/federationtesting/testdata/queries/single_upstream.query deleted file mode 100644 index 4acf51e7e..000000000 --- a/pkg/testing/federationtesting/testdata/queries/single_upstream.query +++ /dev/null @@ -1,6 +0,0 @@ -query Me { - me { - id - username - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/queries/union.query b/pkg/testing/federationtesting/testdata/queries/union.query deleted file mode 100644 index afbc8429b..000000000 --- a/pkg/testing/federationtesting/testdata/queries/union.query +++ /dev/null @@ -1,16 +0,0 @@ -query MyHistory { - me { - username - history { - __typename - ... on Purchase { - wallet { - amount - } - } - ... on Sale { - rating - } - } - } -} \ No newline at end of file diff --git a/pkg/testing/federationtesting/testdata/subscriptions/subscription.query b/pkg/testing/federationtesting/testdata/subscriptions/subscription.query deleted file mode 100644 index b7c647c47..000000000 --- a/pkg/testing/federationtesting/testdata/subscriptions/subscription.query +++ /dev/null @@ -1,7 +0,0 @@ -subscription UpdatePrice($upc: String!) { - updateProductPrice(upc: $upc) { - upc - name - price - } -} diff --git a/pkg/testing/federationtesting/util.go b/pkg/testing/federationtesting/util.go deleted file mode 100644 index 55bda7f74..000000000 --- a/pkg/testing/federationtesting/util.go +++ /dev/null @@ -1,48 +0,0 @@ -package federationtesting - -import ( - "os" - "path/filepath" - "strings" -) - -const ( - federationExampleDirectoryRelativePath = "pkg/testing/federationtesting" - - QueryReviewsOfMe = `query ReviewsOfMe { - me { - reviews { - body - product { - upc - name - price - } - } - } -}` - SubscriptionUpdatedPrice = `subscription UpdatedPrice { - updatedPrice { - name - price - } -}` -) - -type Upstream string - -const ( - UpstreamAccounts Upstream = "accounts" - UpstreamProducts Upstream = "products" - UpstreamReviews Upstream = "reviews" -) - -func LoadSDLFromExamplesDirectoryWithinPkg(upstream Upstream) ([]byte, error) { - wd, err := os.Getwd() - if err != nil { - return nil, err - } - - absolutePath := filepath.Join(strings.Split(wd, "pkg")[0], federationExampleDirectoryRelativePath, string(upstream), "graph", "schema.graphqls") - return os.ReadFile(absolutePath) -} diff --git a/pkg/testing/flags/flags.go b/pkg/testing/flags/flags.go deleted file mode 100644 index e33c37c0a..000000000 --- a/pkg/testing/flags/flags.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build !windows - -package flags - -const IsWindows = false diff --git a/pkg/testing/flags/flags_win.go b/pkg/testing/flags/flags_win.go deleted file mode 100644 index 7ed8d38c9..000000000 --- a/pkg/testing/flags/flags_win.go +++ /dev/null @@ -1,5 +0,0 @@ -//go:build windows - -package flags - -const IsWindows = true diff --git a/pkg/testing/goldie/goldie.go b/pkg/testing/goldie/goldie.go deleted file mode 100644 index 11f5e5825..000000000 --- a/pkg/testing/goldie/goldie.go +++ /dev/null @@ -1,12 +0,0 @@ -package goldie - -import ( - "testing" - - "github.com/sebdah/goldie/v2" -) - -// New creates a new instance of Goldie. -func New(t *testing.T) *goldie.Goldie { - return goldie.New(t, goldie.WithFixtureDir("fixtures")) -} diff --git a/pkg/testing/goldie/goldie_posix.go b/pkg/testing/goldie/goldie_posix.go deleted file mode 100644 index 682f1539d..000000000 --- a/pkg/testing/goldie/goldie_posix.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build !windows - -package goldie - -import ( - "testing" -) - -func Assert(t *testing.T, name string, actual []byte, _ ...bool) { - t.Helper() - - New(t).Assert(t, name, actual) -} - -func Update(t *testing.T, name string, actual []byte) { - t.Helper() - - _ = New(t).Update(t, name, actual) -} diff --git a/pkg/testing/goldie/goldie_win.go b/pkg/testing/goldie/goldie_win.go deleted file mode 100644 index f51595e61..000000000 --- a/pkg/testing/goldie/goldie_win.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build windows - -package goldie - -import ( - "testing" -) - -func Assert(t *testing.T, name string, actual []byte, useOSSuffix ...bool) { - t.Helper() - - if len(useOSSuffix) == 1 && useOSSuffix[0] { - name = name + "_windows" - } - - New(t).Assert(t, name, actual) -} - -func Update(t *testing.T, name string, actual []byte) { - t.Helper() - t.Fatalf("golden files should not be updated on windows") -} diff --git a/pkg/testing/subscriptiontesting/.gqlgen.yml b/pkg/testing/subscriptiontesting/.gqlgen.yml deleted file mode 100644 index 6ae573ebd..000000000 --- a/pkg/testing/subscriptiontesting/.gqlgen.yml +++ /dev/null @@ -1,3 +0,0 @@ -models: - Chatroom: - model: github.com/wundergraph/graphql-go-tools/pkg/testing/subscriptiontesting.Chatroom diff --git a/pkg/testing/subscriptiontesting/chat_test.go b/pkg/testing/subscriptiontesting/chat_test.go deleted file mode 100644 index b01ced3f9..000000000 --- a/pkg/testing/subscriptiontesting/chat_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package subscriptiontesting - -import ( - "testing" - "time" - - "github.com/99designs/gqlgen/client" - "github.com/99designs/gqlgen/graphql/handler" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestChatSubscriptions(t *testing.T) { - c := client.New(handler.NewDefaultServer(NewExecutableSchema(New()))) - - sub := c.Websocket(`subscription @user(username:"vektah") { messageAdded(roomName:"#gophers") { text createdBy } }`) - defer func() { - _ = sub.Close() - }() - - go func() { - var resp interface{} - time.Sleep(10 * time.Millisecond) - err := c.Post(`mutation { - a:post(text:"Hello!", roomName:"#gophers", username:"vektah") { id } - b:post(text:"Hello Vektah!", roomName:"#gophers", username:"andrey") { id } - c:post(text:"Whats up?", roomName:"#gophers", username:"vektah") { id } - }`, &resp) - assert.NoError(t, err) - }() - - var msg struct { - resp struct { - MessageAdded struct { - Text string - CreatedBy string - } - } - err error - } - - msg.err = sub.Next(&msg.resp) - require.NoError(t, msg.err, "sub.Next") - require.Equal(t, "Hello!", msg.resp.MessageAdded.Text) - require.Equal(t, "vektah", msg.resp.MessageAdded.CreatedBy) - - msg.err = sub.Next(&msg.resp) - require.NoError(t, msg.err, "sub.Next") - require.Equal(t, "Whats up?", msg.resp.MessageAdded.Text) - require.Equal(t, "vektah", msg.resp.MessageAdded.CreatedBy) -} diff --git a/pkg/testing/subscriptiontesting/generated.go b/pkg/testing/subscriptiontesting/generated.go deleted file mode 100644 index 4f6260726..000000000 --- a/pkg/testing/subscriptiontesting/generated.go +++ /dev/null @@ -1,3982 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package subscriptiontesting - -import ( - "bytes" - "context" - "embed" - "errors" - "fmt" - "io" - "strconv" - "sync" - "time" - - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/introspection" - gqlparser "github.com/vektah/gqlparser/v2" - "github.com/vektah/gqlparser/v2/ast" -) - -// region ************************** generated!.gotpl ************************** - -// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. -func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { - return &executableSchema{ - resolvers: cfg.Resolvers, - directives: cfg.Directives, - complexity: cfg.Complexity, - } -} - -type Config struct { - Resolvers ResolverRoot - Directives DirectiveRoot - Complexity ComplexityRoot -} - -type ResolverRoot interface { - Mutation() MutationResolver - Query() QueryResolver - Subscription() SubscriptionResolver -} - -type DirectiveRoot struct { - User func(ctx context.Context, obj interface{}, next graphql.Resolver, username string) (res interface{}, err error) -} - -type ComplexityRoot struct { - Chatroom struct { - Messages func(childComplexity int) int - Name func(childComplexity int) int - } - - Message struct { - CreatedAt func(childComplexity int) int - CreatedBy func(childComplexity int) int - ID func(childComplexity int) int - Text func(childComplexity int) int - } - - Mutation struct { - Post func(childComplexity int, text string, username string, roomName string) int - } - - Query struct { - Room func(childComplexity int, name string) int - } - - Subscription struct { - MessageAdded func(childComplexity int, roomName string) int - } -} - -type MutationResolver interface { - Post(ctx context.Context, text string, username string, roomName string) (*Message, error) -} -type QueryResolver interface { - Room(ctx context.Context, name string) (*Chatroom, error) -} -type SubscriptionResolver interface { - MessageAdded(ctx context.Context, roomName string) (<-chan *Message, error) -} - -type executableSchema struct { - resolvers ResolverRoot - directives DirectiveRoot - complexity ComplexityRoot -} - -func (e *executableSchema) Schema() *ast.Schema { - return parsedSchema -} - -func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { - ec := executionContext{nil, e} - _ = ec - switch typeName + "." + field { - - case "Chatroom.messages": - if e.complexity.Chatroom.Messages == nil { - break - } - - return e.complexity.Chatroom.Messages(childComplexity), true - - case "Chatroom.name": - if e.complexity.Chatroom.Name == nil { - break - } - - return e.complexity.Chatroom.Name(childComplexity), true - - case "Message.createdAt": - if e.complexity.Message.CreatedAt == nil { - break - } - - return e.complexity.Message.CreatedAt(childComplexity), true - - case "Message.createdBy": - if e.complexity.Message.CreatedBy == nil { - break - } - - return e.complexity.Message.CreatedBy(childComplexity), true - - case "Message.id": - if e.complexity.Message.ID == nil { - break - } - - return e.complexity.Message.ID(childComplexity), true - - case "Message.text": - if e.complexity.Message.Text == nil { - break - } - - return e.complexity.Message.Text(childComplexity), true - - case "Mutation.post": - if e.complexity.Mutation.Post == nil { - break - } - - args, err := ec.field_Mutation_post_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Mutation.Post(childComplexity, args["text"].(string), args["username"].(string), args["roomName"].(string)), true - - case "Query.room": - if e.complexity.Query.Room == nil { - break - } - - args, err := ec.field_Query_room_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Query.Room(childComplexity, args["name"].(string)), true - - case "Subscription.messageAdded": - if e.complexity.Subscription.MessageAdded == nil { - break - } - - args, err := ec.field_Subscription_messageAdded_args(context.TODO(), rawArgs) - if err != nil { - return 0, false - } - - return e.complexity.Subscription.MessageAdded(childComplexity, args["roomName"].(string)), true - - } - return 0, false -} - -func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { - rc := graphql.GetOperationContext(ctx) - ec := executionContext{rc, e} - inputUnmarshalMap := graphql.BuildUnmarshalerMap() - first := true - - switch rc.Operation.Operation { - case ast.Query: - return func(ctx context.Context) *graphql.Response { - if !first { - return nil - } - first = false - ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Query(ctx, rc.Operation.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - case ast.Mutation: - return func(ctx context.Context) *graphql.Response { - if !first { - return nil - } - first = false - ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) - data := ec._Mutation(ctx, rc.Operation.SelectionSet) - var buf bytes.Buffer - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - case ast.Subscription: - next := ec._subscriptionMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error) { - return ec._Subscription(ctx, rc.Operation.SelectionSet), nil - }) - - var buf bytes.Buffer - return func(ctx context.Context) *graphql.Response { - buf.Reset() - data := next(ctx) - - if data == nil { - return nil - } - data.MarshalGQL(&buf) - - return &graphql.Response{ - Data: buf.Bytes(), - } - } - - default: - return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) - } -} - -type executionContext struct { - *graphql.OperationContext - *executableSchema -} - -func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapSchema(parsedSchema), nil -} - -func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { - if ec.DisableIntrospection { - return nil, errors.New("introspection disabled") - } - return introspection.WrapTypeFromDef(parsedSchema, parsedSchema.Types[name]), nil -} - -//go:embed "schema.graphql" -var sourcesFS embed.FS - -func sourceData(filename string) string { - data, err := sourcesFS.ReadFile(filename) - if err != nil { - panic(fmt.Sprintf("codegen problem: %s not available", filename)) - } - return string(data) -} - -var sources = []*ast.Source{ - {Name: "schema.graphql", Input: sourceData("schema.graphql"), BuiltIn: false}, -} -var parsedSchema = gqlparser.MustLoadSchema(sources...) - -// endregion ************************** generated!.gotpl ************************** - -// region ***************************** args.gotpl ***************************** - -func (ec *executionContext) dir_user_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["username"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("username")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["username"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Mutation_post_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["text"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("text")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["text"] = arg0 - var arg1 string - if tmp, ok := rawArgs["username"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("username")) - arg1, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["username"] = arg1 - var arg2 string - if tmp, ok := rawArgs["roomName"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roomName")) - arg2, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["roomName"] = arg2 - return args, nil -} - -func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["name"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Query_room_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["name"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["name"] = arg0 - return args, nil -} - -func (ec *executionContext) field_Subscription_messageAdded_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 string - if tmp, ok := rawArgs["roomName"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("roomName")) - arg0, err = ec.unmarshalNString2string(ctx, tmp) - if err != nil { - return nil, err - } - } - args["roomName"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { - var err error - args := map[string]interface{}{} - var arg0 bool - if tmp, ok := rawArgs["includeDeprecated"]; ok { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) - arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) - if err != nil { - return nil, err - } - } - args["includeDeprecated"] = arg0 - return args, nil -} - -// endregion ***************************** args.gotpl ***************************** - -// region ************************** directives.gotpl ************************** - -func (ec *executionContext) _subscriptionMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) func(ctx context.Context) graphql.Marshaler { - for _, d := range obj.Directives { - switch d.Name { - case "user": - rawArgs := d.ArgumentMap(ec.Variables) - args, err := ec.dir_user_args(ctx, rawArgs) - if err != nil { - ec.Error(ctx, err) - return func(ctx context.Context) graphql.Marshaler { - return graphql.Null - } - } - n := next - next = func(ctx context.Context) (interface{}, error) { - if ec.directives.User == nil { - return nil, errors.New("directive user is not implemented") - } - return ec.directives.User(ctx, obj, n, args["username"].(string)) - } - } - } - tmp, err := next(ctx) - if err != nil { - ec.Error(ctx, err) - return func(ctx context.Context) graphql.Marshaler { - return graphql.Null - } - } - if data, ok := tmp.(func(ctx context.Context) graphql.Marshaler); ok { - return data - } - ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) - return func(ctx context.Context) graphql.Marshaler { - return graphql.Null - } -} - -// endregion ************************** directives.gotpl ************************** - -// region **************************** field.gotpl ***************************** - -func (ec *executionContext) _Chatroom_name(ctx context.Context, field graphql.CollectedField, obj *Chatroom) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Chatroom_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Chatroom_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Chatroom", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Chatroom_messages(ctx context.Context, field graphql.CollectedField, obj *Chatroom) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Chatroom_messages(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Messages, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]Message) - fc.Result = res - return ec.marshalNMessage2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessageᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Chatroom_messages(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Chatroom", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Message_id(ctx, field) - case "text": - return ec.fieldContext_Message_text(ctx, field) - case "createdBy": - return ec.fieldContext_Message_createdBy(ctx, field) - case "createdAt": - return ec.fieldContext_Message_createdAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Message", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Message_id(ctx context.Context, field graphql.CollectedField, obj *Message) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Message_id(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.ID, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNID2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Message_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Message", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type ID does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Message_text(ctx context.Context, field graphql.CollectedField, obj *Message) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Message_text(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Text, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Message_text(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Message", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Message_createdBy(ctx context.Context, field graphql.CollectedField, obj *Message) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Message_createdBy(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.CreatedBy, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Message_createdBy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Message", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Message_createdAt(ctx context.Context, field graphql.CollectedField, obj *Message) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Message_createdAt(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.CreatedAt, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(time.Time) - fc.Result = res - return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Message_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Message", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Time does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) _Mutation_post(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Mutation_post(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().Post(rctx, fc.Args["text"].(string), fc.Args["username"].(string), fc.Args["roomName"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*Message) - fc.Result = res - return ec.marshalNMessage2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessage(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Mutation_post(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Mutation", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Message_id(ctx, field) - case "text": - return ec.fieldContext_Message_text(ctx, field) - case "createdBy": - return ec.fieldContext_Message_createdBy(ctx, field) - case "createdAt": - return ec.fieldContext_Message_createdAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Message", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Mutation_post_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query_room(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query_room(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Room(rctx, fc.Args["name"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*Chatroom) - fc.Result = res - return ec.marshalOChatroom2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐChatroom(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query_room(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext_Chatroom_name(ctx, field) - case "messages": - return ec.fieldContext_Chatroom_messages(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Chatroom", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query_room_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectType(fc.Args["name"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - fc, err := ec.fieldContext_Query___schema(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.introspectSchema() - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Schema) - fc.Result = res - return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Query", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "description": - return ec.fieldContext___Schema_description(ctx, field) - case "types": - return ec.fieldContext___Schema_types(ctx, field) - case "queryType": - return ec.fieldContext___Schema_queryType(ctx, field) - case "mutationType": - return ec.fieldContext___Schema_mutationType(ctx, field) - case "subscriptionType": - return ec.fieldContext___Schema_subscriptionType(ctx, field) - case "directives": - return ec.fieldContext___Schema_directives(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) _Subscription_messageAdded(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { - fc, err := ec.fieldContext_Subscription_messageAdded(ctx, field) - if err != nil { - return nil - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Subscription().MessageAdded(rctx, fc.Args["roomName"].(string)) - }) - if err != nil { - ec.Error(ctx, err) - return nil - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return nil - } - return func(ctx context.Context) graphql.Marshaler { - select { - case res, ok := <-resTmp.(<-chan *Message): - if !ok { - return nil - } - return graphql.WriterFunc(func(w io.Writer) { - w.Write([]byte{'{'}) - graphql.MarshalString(field.Alias).MarshalGQL(w) - w.Write([]byte{':'}) - ec.marshalNMessage2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessage(ctx, field.Selections, res).MarshalGQL(w) - w.Write([]byte{'}'}) - }) - case <-ctx.Done(): - return nil - } - } -} - -func (ec *executionContext) fieldContext_Subscription_messageAdded(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "Subscription", - Field: field, - IsMethod: true, - IsResolver: true, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "id": - return ec.fieldContext_Message_id(ctx, field) - case "text": - return ec.fieldContext_Message_text(ctx, field) - case "createdBy": - return ec.fieldContext_Message_createdBy(ctx, field) - case "createdAt": - return ec.fieldContext_Message_createdAt(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type Message", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field_Subscription_messageAdded_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_locations(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Locations, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]string) - fc.Result = res - return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __DirectiveLocation does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsRepeatable, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Directive", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__EnumValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_args(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Args, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_isDeprecated(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.IsDeprecated(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(bool) - fc.Result = res - return ec.marshalNBoolean2bool(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type Boolean does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Field_deprecationReason(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DeprecationReason(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Field", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_type(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Type, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.DefaultValue, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__InputValue", - Field: field, - IsMethod: false, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_types(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Types(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_queryType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.QueryType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_mutationType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.MutationType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SubscriptionType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Schema_directives(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Directives(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]introspection.Directive) - fc.Result = res - return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Schema", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Directive_name(ctx, field) - case "description": - return ec.fieldContext___Directive_description(ctx, field) - case "locations": - return ec.fieldContext___Directive_locations(ctx, field) - case "args": - return ec.fieldContext___Directive_args(ctx, field) - case "isRepeatable": - return ec.fieldContext___Directive_isRepeatable(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_kind(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Kind(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalN__TypeKind2string(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type __TypeKind does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_name(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_description(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Description(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_fields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Field) - fc.Result = res - return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___Field_name(ctx, field) - case "description": - return ec.fieldContext___Field_description(ctx, field) - case "args": - return ec.fieldContext___Field_args(ctx, field) - case "type": - return ec.fieldContext___Field_type(ctx, field) - case "isDeprecated": - return ec.fieldContext___Field_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___Field_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_interfaces(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Interfaces(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_possibleTypes(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.PossibleTypes(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_enumValues(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.EnumValue) - fc.Result = res - return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___EnumValue_name(ctx, field) - case "description": - return ec.fieldContext___EnumValue_description(ctx, field) - case "isDeprecated": - return ec.fieldContext___EnumValue_isDeprecated(ctx, field) - case "deprecationReason": - return ec.fieldContext___EnumValue_deprecationReason(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) - }, - } - defer func() { - if r := recover(); r != nil { - err = ec.Recover(ctx, r) - ec.Error(ctx, err) - } - }() - ctx = graphql.WithFieldContext(ctx, fc) - if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { - ec.Error(ctx, err) - return - } - return fc, nil -} - -func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_inputFields(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.InputFields(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.([]introspection.InputValue) - fc.Result = res - return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "name": - return ec.fieldContext___InputValue_name(ctx, field) - case "description": - return ec.fieldContext___InputValue_description(ctx, field) - case "type": - return ec.fieldContext___InputValue_type(ctx, field) - case "defaultValue": - return ec.fieldContext___InputValue_defaultValue(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_ofType(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.OfType(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*introspection.Type) - fc.Result = res - return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - switch field.Name { - case "kind": - return ec.fieldContext___Type_kind(ctx, field) - case "name": - return ec.fieldContext___Type_name(ctx, field) - case "description": - return ec.fieldContext___Type_description(ctx, field) - case "fields": - return ec.fieldContext___Type_fields(ctx, field) - case "interfaces": - return ec.fieldContext___Type_interfaces(ctx, field) - case "possibleTypes": - return ec.fieldContext___Type_possibleTypes(ctx, field) - case "enumValues": - return ec.fieldContext___Type_enumValues(ctx, field) - case "inputFields": - return ec.fieldContext___Type_inputFields(ctx, field) - case "ofType": - return ec.fieldContext___Type_ofType(ctx, field) - case "specifiedByURL": - return ec.fieldContext___Type_specifiedByURL(ctx, field) - } - return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) - }, - } - return fc, nil -} - -func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { - fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) - if err != nil { - return graphql.Null - } - ctx = graphql.WithFieldContext(ctx, fc) - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.SpecifiedByURL(), nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - return graphql.Null - } - res := resTmp.(*string) - fc.Result = res - return ec.marshalOString2ᚖstring(ctx, field.Selections, res) -} - -func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { - fc = &graphql.FieldContext{ - Object: "__Type", - Field: field, - IsMethod: true, - IsResolver: false, - Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { - return nil, errors.New("field of type String does not have child fields") - }, - } - return fc, nil -} - -// endregion **************************** field.gotpl ***************************** - -// region **************************** input.gotpl ***************************** - -// endregion **************************** input.gotpl ***************************** - -// region ************************** interface.gotpl *************************** - -// endregion ************************** interface.gotpl *************************** - -// region **************************** object.gotpl **************************** - -var chatroomImplementors = []string{"Chatroom"} - -func (ec *executionContext) _Chatroom(ctx context.Context, sel ast.SelectionSet, obj *Chatroom) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, chatroomImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Chatroom") - case "name": - - out.Values[i] = ec._Chatroom_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "messages": - - out.Values[i] = ec._Chatroom_messages(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var messageImplementors = []string{"Message"} - -func (ec *executionContext) _Message(ctx context.Context, sel ast.SelectionSet, obj *Message) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, messageImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Message") - case "id": - - out.Values[i] = ec._Message_id(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "text": - - out.Values[i] = ec._Message_text(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "createdBy": - - out.Values[i] = ec._Message_createdBy(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "createdAt": - - out.Values[i] = ec._Message_createdAt(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var mutationImplementors = []string{"Mutation"} - -func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Mutation", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Mutation") - case "post": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Mutation_post(ctx, field) - }) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var queryImplementors = []string{"Query"} - -func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Query", - }) - - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ - Object: field.Name, - Field: field, - }) - - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("Query") - case "room": - field := field - - innerFunc := func(ctx context.Context) (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_room(ctx, field) - return res - } - - rrm := func(ctx context.Context) graphql.Marshaler { - return ec.OperationContext.RootResolverMiddleware(ctx, innerFunc) - } - - out.Concurrently(i, func() graphql.Marshaler { - return rrm(innerCtx) - }) - case "__type": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___type(ctx, field) - }) - - case "__schema": - - out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { - return ec._Query___schema(ctx, field) - }) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var subscriptionImplementors = []string{"Subscription"} - -func (ec *executionContext) _Subscription(ctx context.Context, sel ast.SelectionSet) func(ctx context.Context) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, subscriptionImplementors) - ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ - Object: "Subscription", - }) - if len(fields) != 1 { - ec.Errorf(ctx, "must subscribe to exactly one stream") - return nil - } - - switch fields[0].Name { - case "messageAdded": - return ec._Subscription_messageAdded(ctx, fields[0]) - default: - panic("unknown field " + strconv.Quote(fields[0].Name)) - } -} - -var __DirectiveImplementors = []string{"__Directive"} - -func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Directive") - case "name": - - out.Values[i] = ec.___Directive_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Directive_description(ctx, field, obj) - - case "locations": - - out.Values[i] = ec.___Directive_locations(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "args": - - out.Values[i] = ec.___Directive_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isRepeatable": - - out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __EnumValueImplementors = []string{"__EnumValue"} - -func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__EnumValue") - case "name": - - out.Values[i] = ec.___EnumValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___EnumValue_description(ctx, field, obj) - - case "isDeprecated": - - out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __FieldImplementors = []string{"__Field"} - -func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Field") - case "name": - - out.Values[i] = ec.___Field_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___Field_description(ctx, field, obj) - - case "args": - - out.Values[i] = ec.___Field_args(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "type": - - out.Values[i] = ec.___Field_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "isDeprecated": - - out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "deprecationReason": - - out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __InputValueImplementors = []string{"__InputValue"} - -func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__InputValue") - case "name": - - out.Values[i] = ec.___InputValue_name(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "description": - - out.Values[i] = ec.___InputValue_description(ctx, field, obj) - - case "type": - - out.Values[i] = ec.___InputValue_type(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "defaultValue": - - out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __SchemaImplementors = []string{"__Schema"} - -func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Schema") - case "description": - - out.Values[i] = ec.___Schema_description(ctx, field, obj) - - case "types": - - out.Values[i] = ec.___Schema_types(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "queryType": - - out.Values[i] = ec.___Schema_queryType(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "mutationType": - - out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) - - case "subscriptionType": - - out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) - - case "directives": - - out.Values[i] = ec.___Schema_directives(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -var __TypeImplementors = []string{"__Type"} - -func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) - out := graphql.NewFieldSet(fields) - var invalids uint32 - for i, field := range fields { - switch field.Name { - case "__typename": - out.Values[i] = graphql.MarshalString("__Type") - case "kind": - - out.Values[i] = ec.___Type_kind(ctx, field, obj) - - if out.Values[i] == graphql.Null { - invalids++ - } - case "name": - - out.Values[i] = ec.___Type_name(ctx, field, obj) - - case "description": - - out.Values[i] = ec.___Type_description(ctx, field, obj) - - case "fields": - - out.Values[i] = ec.___Type_fields(ctx, field, obj) - - case "interfaces": - - out.Values[i] = ec.___Type_interfaces(ctx, field, obj) - - case "possibleTypes": - - out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) - - case "enumValues": - - out.Values[i] = ec.___Type_enumValues(ctx, field, obj) - - case "inputFields": - - out.Values[i] = ec.___Type_inputFields(ctx, field, obj) - - case "ofType": - - out.Values[i] = ec.___Type_ofType(ctx, field, obj) - - case "specifiedByURL": - - out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) - - default: - panic("unknown field " + strconv.Quote(field.Name)) - } - } - out.Dispatch() - if invalids > 0 { - return graphql.Null - } - return out -} - -// endregion **************************** object.gotpl **************************** - -// region ***************************** type.gotpl ***************************** - -func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalID(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalID(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalNMessage2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessage(ctx context.Context, sel ast.SelectionSet, v Message) graphql.Marshaler { - return ec._Message(ctx, sel, &v) -} - -func (ec *executionContext) marshalNMessage2ᚕgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessageᚄ(ctx context.Context, sel ast.SelectionSet, v []Message) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNMessage2githubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessage(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalNMessage2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐMessage(ctx context.Context, sel ast.SelectionSet, v *Message) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec._Message(ctx, sel, v) -} - -func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) { - res, err := graphql.UnmarshalTime(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler { - res := graphql.MarshalTime(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { - return ec.___Directive(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]string, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { - return ec.___EnumValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { - return ec.___Field(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { - return ec.___InputValue(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { - return ec.___Type(ctx, sel, &v) -} - -func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { - res, err := graphql.UnmarshalString(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { - res := graphql.MarshalString(v) - if res == graphql.Null { - if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { - ec.Errorf(ctx, "the requested element is null which the schema does not allow") - } - } - return res -} - -func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { - res, err := graphql.UnmarshalBoolean(v) - return res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { - res := graphql.MarshalBoolean(v) - return res -} - -func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalBoolean(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalBoolean(*v) - return res -} - -func (ec *executionContext) marshalOChatroom2ᚖgithubᚗcomᚋwundergraphᚋgraphqlᚑgoᚑtoolsᚋpkgᚋtestingᚋsubscriptiontestingᚐChatroom(ctx context.Context, sel ast.SelectionSet, v *Chatroom) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec._Chatroom(ctx, sel, v) -} - -func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { - if v == nil { - return nil, nil - } - res, err := graphql.UnmarshalString(v) - return &res, graphql.ErrorOnPath(ctx, err) -} - -func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { - if v == nil { - return graphql.Null - } - res := graphql.MarshalString(*v) - return res -} - -func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Schema(ctx, sel, v) -} - -func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - - for _, e := range ret { - if e == graphql.Null { - return graphql.Null - } - } - - return ret -} - -func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { - if v == nil { - return graphql.Null - } - return ec.___Type(ctx, sel, v) -} - -// endregion ***************************** type.gotpl ***************************** diff --git a/pkg/testing/subscriptiontesting/handler.go b/pkg/testing/subscriptiontesting/handler.go deleted file mode 100644 index 71212bdbe..000000000 --- a/pkg/testing/subscriptiontesting/handler.go +++ /dev/null @@ -1,29 +0,0 @@ -//go:generate go run -mod=mod github.com/99designs/gqlgen -package subscriptiontesting - -import ( - "net/http" - "time" - - "github.com/99designs/gqlgen/graphql/handler" - "github.com/99designs/gqlgen/graphql/handler/extension" - "github.com/99designs/gqlgen/graphql/handler/transport" - "github.com/gorilla/websocket" -) - -func ChatGraphQLEndpointHandler() http.Handler { - srv := handler.New(NewExecutableSchema(New())) - - srv.AddTransport(transport.POST{}) - srv.AddTransport(transport.Websocket{ - KeepAlivePingInterval: 10 * time.Second, - Upgrader: websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - }, - }) - srv.Use(extension.Introspection{}) - - return srv -} diff --git a/pkg/testing/subscriptiontesting/models_gen.go b/pkg/testing/subscriptiontesting/models_gen.go deleted file mode 100644 index 21dc5276c..000000000 --- a/pkg/testing/subscriptiontesting/models_gen.go +++ /dev/null @@ -1,14 +0,0 @@ -// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. - -package subscriptiontesting - -import ( - "time" -) - -type Message struct { - ID string `json:"id"` - Text string `json:"text"` - CreatedBy string `json:"createdBy"` - CreatedAt time.Time `json:"createdAt"` -} diff --git a/pkg/testing/subscriptiontesting/resolvers.go b/pkg/testing/subscriptiontesting/resolvers.go deleted file mode 100644 index 84614eef8..000000000 --- a/pkg/testing/subscriptiontesting/resolvers.go +++ /dev/null @@ -1,169 +0,0 @@ -//go:generate go run -mod=mod github.com/99designs/gqlgen - -package subscriptiontesting - -import ( - "context" - "math/rand" - "sync" - "time" - - "github.com/99designs/gqlgen/graphql" - "github.com/99designs/gqlgen/graphql/introspection" -) - -type ckey string - -type resolver struct { - Rooms map[string]*Chatroom - mu sync.Mutex // nolint: structcheck -} - -func (r *resolver) Mutation() MutationResolver { - return &mutationResolver{r} -} - -func (r *resolver) Query() QueryResolver { - return &queryResolver{r} -} - -func (r *resolver) Subscription() SubscriptionResolver { - return &subscriptionResolver{r} -} - -func New() Config { - return Config{ - Resolvers: &resolver{ - Rooms: map[string]*Chatroom{}, - }, - Directives: DirectiveRoot{ - User: func(ctx context.Context, obj interface{}, next graphql.Resolver, username string) (res interface{}, err error) { - return next(context.WithValue(ctx, ckey("username"), username)) - }, - }, - } -} - -func getUsername(ctx context.Context) string { - if username, ok := ctx.Value(ckey("username")).(string); ok { - return username - } - return "" -} - -type Chatroom struct { - Name string - Messages []Message - Observers map[string]struct { - Username string - Message chan *Message - } -} - -type mutationResolver struct{ *resolver } - -func (r *mutationResolver) Post(ctx context.Context, text string, username string, roomName string) (*Message, error) { - r.mu.Lock() - room := r.Rooms[roomName] - if room == nil { - room = &Chatroom{ - Name: roomName, - Observers: map[string]struct { - Username string - Message chan *Message - }{}, - } - r.Rooms[roomName] = room - } - r.mu.Unlock() - - message := Message{ - ID: randString(8), - CreatedAt: time.Now(), - Text: text, - CreatedBy: username, - } - - room.Messages = append(room.Messages, message) - r.mu.Lock() - for _, observer := range room.Observers { - if observer.Username == "" || observer.Username == message.CreatedBy { - observer.Message <- &message - } - } - r.mu.Unlock() - return &message, nil -} - -type queryResolver struct{ *resolver } - -func (r *queryResolver) Room(ctx context.Context, name string) (*Chatroom, error) { - r.mu.Lock() - room := r.Rooms[name] - if room == nil { - room = &Chatroom{ - Name: name, - Observers: map[string]struct { - Username string - Message chan *Message - }{}, - } - r.Rooms[name] = room - } - r.mu.Unlock() - - return room, nil -} - -type subscriptionResolver struct{ *resolver } - -func (r *subscriptionResolver) MessageAdded(ctx context.Context, roomName string) (<-chan *Message, error) { - r.mu.Lock() - room := r.Rooms[roomName] - if room == nil { - room = &Chatroom{ - Name: roomName, - Observers: map[string]struct { - Username string - Message chan *Message - }{}, - } - r.Rooms[roomName] = room - } - r.mu.Unlock() - - id := randString(8) - events := make(chan *Message, 1) - - go func() { - <-ctx.Done() - r.mu.Lock() - delete(room.Observers, id) - r.mu.Unlock() - }() - - r.mu.Lock() - room.Observers[id] = struct { - Username string - Message chan *Message - }{Username: getUsername(ctx), Message: events} - r.mu.Unlock() - - return events, nil -} - -type DirectiveIsRepeatableResolver struct{ *resolver } - -func (d DirectiveIsRepeatableResolver) IsRepeatable(ctx context.Context, obj *introspection.Directive) (bool, error) { - return true, nil -} - -var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") - -func randString(n int) string { - b := make([]rune, n) - for i := range b { - b[i] = letterRunes[rand.Intn(len(letterRunes))] - } - return string(b) -} diff --git a/pkg/testing/subscriptiontesting/schema.graphql b/pkg/testing/subscriptiontesting/schema.graphql deleted file mode 100644 index 18bfcae12..000000000 --- a/pkg/testing/subscriptiontesting/schema.graphql +++ /dev/null @@ -1,27 +0,0 @@ -type Chatroom { - name: String! - messages: [Message!]! -} - -type Message { - id: ID! - text: String! - createdBy: String! - createdAt: Time! -} - -type Query { - room(name:String!): Chatroom -} - -type Mutation { - post(text: String!, username: String!, roomName: String!): Message! -} - -type Subscription { - messageAdded(roomName: String!): Message! -} - -scalar Time - -directive @user(username: String!) on SUBSCRIPTION diff --git a/pkg/testing/subscriptiontesting/util.go b/pkg/testing/subscriptiontesting/util.go deleted file mode 100644 index a648ee0d0..000000000 --- a/pkg/testing/subscriptiontesting/util.go +++ /dev/null @@ -1,76 +0,0 @@ -package subscriptiontesting - -import ( - "encoding/json" - "os" - "path/filepath" - "strings" -) - -const ( - chatExampleDirectoryRelativePath = "pkg/testing/subscriptiontesting" - - MutationSendMessage = `mutation SendMessage{ - post(roomName: "#test", username: "myuser", text: "Hello World!") { - text - createdBy - } -}` - - QueryGetMessages = `query GetMessages { - room(name:"#test") { - name - messages { - text - createdBy - } - } -}` - - SubscriptionLiveMessages = `subscription LiveMessages { - messageAdded(roomName: "#test") { - text - createdBy - } -}` - - InvalidSubscriptionLiveMessages = `subscription LiveMessages { - messageAdded(roomName: "#test") { - a: text - } - messageAdded(roomName: "#test") { - a: createdBy - } -}` - - InvalidOperation = `query InvalidOperation { - serverName -} -` -) - -type graphqlRequest struct { - OperationName string `json:"operationName"` - Query string `json:"query"` - Variables json.RawMessage `json:"variables"` -} - -func LoadSchemaFromExamplesDirectoryWithinPkg() ([]byte, error) { - wd, err := os.Getwd() - if err != nil { - return nil, err - } - - absolutePath := filepath.Join(strings.Split(wd, "pkg")[0], chatExampleDirectoryRelativePath, "schema.graphql") - return os.ReadFile(absolutePath) -} - -func GraphQLRequestForOperation(operation string) ([]byte, error) { - gqlRequest := graphqlRequest{ - OperationName: "", - Query: operation, - Variables: nil, - } - - return json.Marshal(gqlRequest) -} From a5e36ee72fbf12afee137ae26764914d41a41590 Mon Sep 17 00:00:00 2001 From: Yury Smolski <140245+ysmolski@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:30:18 +0300 Subject: [PATCH 4/5] add dummy ci and clarify other workflows --- .github/workflows/dummy-ci.yaml | 15 +++++++++++++++ .github/workflows/execution.yml | 2 ++ .github/workflows/v2.yml | 2 ++ 3 files changed, 19 insertions(+) create mode 100644 .github/workflows/dummy-ci.yaml diff --git a/.github/workflows/dummy-ci.yaml b/.github/workflows/dummy-ci.yaml new file mode 100644 index 000000000..ecea30403 --- /dev/null +++ b/.github/workflows/dummy-ci.yaml @@ -0,0 +1,15 @@ +# This job is used to satisfy PR checks for parts of the codebase +# that are not tested during CI +name: Dummy CI +on: + pull_request: + paths: + - '.gitignore' + - 'LICENSE' + - 'README.md' +jobs: + build_test: + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - run: echo Nothing to do diff --git a/.github/workflows/execution.yml b/.github/workflows/execution.yml index 7ed92f8a8..101833086 100644 --- a/.github/workflows/execution.yml +++ b/.github/workflows/execution.yml @@ -5,6 +5,7 @@ on: - 'v2/**' - 'execution/**' - '.github/workflows/execution.yml' + - '.golangci.yml' push: branches: - master @@ -12,6 +13,7 @@ on: - 'v2/**' - 'execution/**' - '.github/workflows/execution.yml' + - '.golangci.yml' jobs: test: name: Build and test (go ${{ matrix.go }} / ${{ matrix.os }}) diff --git a/.github/workflows/v2.yml b/.github/workflows/v2.yml index 913f0fc00..25546e7e8 100644 --- a/.github/workflows/v2.yml +++ b/.github/workflows/v2.yml @@ -7,6 +7,7 @@ on: - '.github/workflows/pr-title.yml' - '.github/workflows/release.yml' - 'commitlint.config.js' + - '.golangci.yml' push: branches: - master @@ -16,6 +17,7 @@ on: - '.github/workflows/pr-title.yml' - '.github/workflows/release.yml' - 'commitlint.config.js' + - '.golangci.yml' jobs: test: name: Build and test (go ${{ matrix.go }} / ${{ matrix.os }}) From 9541989ff15cad65f2e2d472884f8cd420175747 Mon Sep 17 00:00:00 2001 From: Yury Smolski <140245+ysmolski@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:46:22 +0300 Subject: [PATCH 5/5] add future version with retraction and tidy the mod file --- go.mod | 75 +------------------- go.sum | 218 --------------------------------------------------------- 2 files changed, 1 insertion(+), 292 deletions(-) diff --git a/go.mod b/go.mod index 47aa44c3b..59c1a6733 100644 --- a/go.mod +++ b/go.mod @@ -4,80 +4,7 @@ go 1.25 // Use github.com/wundergraph/graphql-go-tools/v2 instead. retract ( - [v1.0.0, v1.67.4] + [v1.0.0, v1.67.5] v0.13.2 v0.0.1 ) - -require ( - github.com/99designs/gqlgen v0.17.45 - github.com/buger/jsonparser v1.1.1 - github.com/cespare/xxhash/v2 v2.3.0 - github.com/dave/jennifer v1.4.0 - github.com/davecgh/go-spew v1.1.1 - github.com/eclipse/paho.mqtt.golang v1.2.0 - github.com/evanphx/json-patch/v5 v5.1.0 - github.com/go-test/deep v1.0.8 - github.com/gobwas/ws v1.4.0 - github.com/golang/mock v1.6.0 - github.com/google/go-cmp v0.6.0 - github.com/gorilla/websocket v1.5.1 - github.com/hashicorp/golang-lru v0.5.4 - github.com/iancoleman/strcase v0.3.0 - github.com/jensneuse/abstractlogger v0.0.4 - github.com/jensneuse/byte-template v0.0.0-20200214152254-4f3cf06e5c68 - github.com/jensneuse/diffview v1.0.0 - github.com/jensneuse/pipeline v0.0.0-20200117120358-9fb4de085cd6 - github.com/nats-io/nats.go v1.35.0 - github.com/r3labs/sse/v2 v2.8.1 - github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 - github.com/sebdah/goldie/v2 v2.7.1 - github.com/stretchr/testify v1.10.0 - github.com/tidwall/gjson v1.17.0 - github.com/tidwall/sjson v1.2.5 - github.com/vektah/gqlparser/v2 v2.5.14 - go.uber.org/atomic v1.11.0 - go.uber.org/zap v1.26.0 - golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 - gopkg.in/yaml.v2 v2.4.0 - nhooyr.io/websocket v1.8.11 -) - -require ( - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver v1.5.0 // indirect - github.com/Masterminds/sprig v2.22.0+incompatible // indirect - github.com/agnivade/levenshtein v1.1.1 // indirect - github.com/gobwas/httphead v0.1.0 // indirect - github.com/gobwas/pool v0.2.1 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/huandu/xstrings v1.2.1 // indirect - github.com/imdario/mergo v0.3.8 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/logrusorgru/aurora/v3 v3.0.0 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/copystructure v1.0.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.0 // indirect - github.com/nats-io/nkeys v0.4.7 // indirect - github.com/nats-io/nuid v1.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rogpeppe/go-internal v1.13.1 // indirect - github.com/sergi/go-diff v1.3.1 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/sosodev/duration v1.2.0 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.1 // indirect - go.uber.org/goleak v1.3.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.36.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sys v0.31.0 // indirect - gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/go.sum b/go.sum index 0103b204e..e69de29bb 100644 --- a/go.sum +++ b/go.sum @@ -1,218 +0,0 @@ -github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= -github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= -github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= -github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= -github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/dave/jennifer v1.4.0 h1:tNJFJmLDVTLu+v05mVZ88RINa3vQqnyyWkTKWYz0CwE= -github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= -github.com/eclipse/paho.mqtt.golang v1.2.0 h1:1F8mhG9+aO5/xpdtFkW4SxOJB67ukuDC3t2y2qayIX0= -github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= -github.com/evanphx/json-patch/v5 v5.1.0 h1:B0aXl1o/1cP8NbviYiBMkcHBtUjIJ1/Ccg6b+SwCLQg= -github.com/evanphx/json-patch/v5 v5.1.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= -github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= -github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= -github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= -github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= -github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= -github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huandu/xstrings v1.2.1 h1:v6IdmkCnDhJG/S0ivr58PeIfg+tyhqQYy4YsCsQ0Pdc= -github.com/huandu/xstrings v1.2.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= -github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= -github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/jensneuse/abstractlogger v0.0.4 h1:sa4EH8fhWk3zlTDbSncaWKfwxYM8tYSlQ054ETLyyQY= -github.com/jensneuse/abstractlogger v0.0.4/go.mod h1:6WuamOHuykJk8zED/R0LNiLhWR6C7FIAo43ocUEB3mo= -github.com/jensneuse/byte-template v0.0.0-20200214152254-4f3cf06e5c68 h1:E80wOd3IFQcoBxLkAUpUQ3BoGrZ4DxhQdP21+HH1s6A= -github.com/jensneuse/byte-template v0.0.0-20200214152254-4f3cf06e5c68/go.mod h1:0D5r/VSW6D/o65rKLL9xk7sZxL2+oku2HvFPYeIMFr4= -github.com/jensneuse/diffview v1.0.0 h1:4b6FQJ7y3295JUHU3tRko6euyEboL825ZsXeZZM47Z4= -github.com/jensneuse/diffview v1.0.0/go.mod h1:i6IacuD8LnEaPuiyzMHA+Wfz5mAuycMOf3R/orUY9y4= -github.com/jensneuse/pipeline v0.0.0-20200117120358-9fb4de085cd6 h1:y8hvuqbuVGFNpEos+vB5I5X+QxWm0uyTk+5oeOinMjY= -github.com/jensneuse/pipeline v0.0.0-20200117120358-9fb4de085cd6/go.mod h1:UsfzaMt+keVOxa007GcCJMFeTHr6voRfBGMQEW7DkdM= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/logrusorgru/aurora/v3 v3.0.0 h1:R6zcoZZbvVcGMvDCKo45A9U/lzYyzl5NfYIvznmDfE4= -github.com/logrusorgru/aurora/v3 v3.0.0/go.mod h1:vsR12bk5grlLvLXAYrBsb5Oc/N+LxAlxggSjiwMnCUc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/nats-io/nats.go v1.35.0 h1:XFNqNM7v5B+MQMKqVGAyHwYhyKb48jrenXNxIU20ULk= -github.com/nats-io/nats.go v1.35.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= -github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= -github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= -github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/r3labs/sse/v2 v2.8.1 h1:lZH+W4XOLIq88U5MIHOsLec7+R62uhz3bIi2yn0Sg8o= -github.com/r3labs/sse/v2 v2.8.1/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= -github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= -github.com/sebdah/goldie/v2 v2.7.1 h1:PkBHymaYdtvEkZV7TmyqKxdmn5/Vcj+8TpATWZjnG5E= -github.com/sebdah/goldie/v2 v2.7.1/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= -github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= -github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= -github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= -github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= -github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/vektah/gqlparser/v2 v2.5.14 h1:dzLq75BJe03jjQm6n56PdH1oweB8ana42wj7E4jRy70= -github.com/vektah/gqlparser/v2 v2.5.14/go.mod h1:WQQjFc+I1YIzoPvZBhUQX7waZgg3pMLi0r8KymvAE2w= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= -golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= -gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= -nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c=