graphql 1.13.24 → 2.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +50 -1
- data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/relay.rb +21 -18
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +8 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +65 -28
- data/lib/graphql/analysis/max_query_complexity.rb +11 -17
- data/lib/graphql/analysis/max_query_depth.rb +13 -19
- data/lib/graphql/analysis/query_complexity.rb +236 -61
- data/lib/graphql/analysis/query_depth.rb +38 -23
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +93 -6
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -73
- data/lib/graphql/backtrace.rb +2 -25
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +101 -0
- data/lib/graphql/dataloader/null_dataloader.rb +11 -2
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +103 -47
- data/lib/graphql/dataloader.rb +174 -148
- data/lib/graphql/dig.rb +3 -2
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -82
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +30 -35
- data/lib/graphql/execution/interpreter/resolve.rb +32 -2
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +215 -0
- data/lib/graphql/execution/interpreter/runtime.rb +525 -502
- data/lib/graphql/execution/interpreter.rb +127 -81
- data/lib/graphql/execution/lazy.rb +7 -21
- data/lib/graphql/execution/lookahead.rb +133 -55
- data/lib/graphql/execution/multiplex.rb +6 -176
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +10 -17
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +13 -6
- data/lib/graphql/introspection.rb +4 -3
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +114 -80
- data/lib/graphql/language/lexer.rb +375 -1489
- data/lib/graphql/language/nodes.rb +189 -104
- data/lib/graphql/language/parser.rb +807 -1941
- data/lib/graphql/language/printer.rb +366 -163
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +189 -138
- data/lib/graphql/language.rb +62 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +3 -28
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +2 -0
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +131 -225
- data/lib/graphql/query/input_validation_result.rb +1 -1
- data/lib/graphql/query/null_context.rb +11 -33
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +14 -37
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +6 -19
- data/lib/graphql/query.rb +162 -98
- data/lib/graphql/railtie.rb +15 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -20
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +70 -33
- data/lib/graphql/schema/always_visible.rb +15 -0
- data/lib/graphql/schema/argument.rb +104 -59
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +154 -74
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +47 -24
- data/lib/graphql/schema/enum.rb +137 -65
- data/lib/graphql/schema/enum_value.rb +11 -26
- data/lib/graphql/schema/field/connection_extension.rb +6 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +399 -404
- data/lib/graphql/schema/field_extension.rb +2 -5
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +144 -99
- data/lib/graphql/schema/interface.rb +34 -51
- data/lib/graphql/schema/introspection_system.rb +12 -26
- data/lib/graphql/schema/late_bound_type.rb +12 -2
- data/lib/graphql/schema/list.rb +3 -9
- data/lib/graphql/schema/loader.rb +4 -6
- data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
- data/lib/graphql/schema/member/build_type.rb +15 -9
- data/lib/graphql/schema/member/has_arguments.rb +192 -96
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +18 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +119 -39
- data/lib/graphql/schema/member/has_interfaces.rb +66 -23
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +32 -2
- data/lib/graphql/schema/member/validates_input.rb +4 -4
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +7 -9
- data/lib/graphql/schema/non_null.rb +1 -7
- data/lib/graphql/schema/object.rb +42 -49
- data/lib/graphql/schema/printer.rb +12 -8
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +12 -124
- data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
- data/lib/graphql/schema/resolver.rb +96 -81
- data/lib/graphql/schema/scalar.rb +10 -30
- data/lib/graphql/schema/subscription.rb +60 -14
- data/lib/graphql/schema/timeout.rb +44 -31
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +12 -19
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +60 -10
- data/lib/graphql/schema/validator.rb +5 -3
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +318 -94
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +1148 -1085
- data/lib/graphql/static_validation/all_rules.rb +4 -3
- data/lib/graphql/static_validation/base_visitor.rb +11 -27
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/error.rb +2 -2
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -12
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +48 -6
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -27
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +19 -9
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +12 -26
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +14 -6
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
- data/lib/graphql/subscriptions/event.rb +24 -12
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +48 -32
- data/lib/graphql/testing/helpers.rb +158 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +27 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +259 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +54 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +71 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +3 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +93 -0
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
- data/lib/graphql/tracing/legacy_trace.rb +12 -0
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +68 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +195 -0
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +734 -0
- data/lib/graphql/tracing/platform_trace.rb +123 -0
- data/lib/graphql/tracing/platform_tracing.rb +28 -41
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
- data/lib/graphql/tracing/prometheus_trace.rb +93 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
- data/lib/graphql/tracing/scout_trace.rb +49 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +80 -0
- data/lib/graphql/tracing/statsd_trace.rb +48 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +186 -0
- data/lib/graphql/tracing.rb +32 -52
- data/lib/graphql/type_kinds.rb +8 -4
- data/lib/graphql/types/iso_8601_date.rb +4 -1
- data/lib/graphql/types/iso_8601_date_time.rb +4 -0
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +65 -23
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +76 -123
- data/readme.md +13 -3
- metadata +225 -142
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -55
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -56
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -91
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backtrace/tracer.rb +0 -81
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -255
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -260
- data/lib/graphql/language/parser.y +0 -550
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -31
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require "graphql/execution/interpreter/runtime/graphql_result"
|
2
3
|
|
3
4
|
module GraphQL
|
4
5
|
module Execution
|
@@ -8,135 +9,21 @@ module GraphQL
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class Runtime
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@graphql_result_name = result_name
|
19
|
-
# Jump through some hoops to avoid creating this duplicate storage if at all possible.
|
20
|
-
@graphql_metadata = nil
|
12
|
+
class CurrentState
|
13
|
+
def initialize
|
14
|
+
@current_field = nil
|
15
|
+
@current_arguments = nil
|
16
|
+
@current_result_name = nil
|
17
|
+
@current_result = nil
|
18
|
+
@was_authorized_by_scope_items = nil
|
21
19
|
end
|
22
20
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
# Although these are used by only one of the Result classes,
|
27
|
-
# it's handy to have the methods implemented on both (even though they just return `nil`)
|
28
|
-
# because it makes it easy to check if anything is assigned.
|
29
|
-
# @return [nil, Array<String>]
|
30
|
-
attr_accessor :graphql_non_null_field_names
|
31
|
-
# @return [nil, true]
|
32
|
-
attr_accessor :graphql_non_null_list_items
|
33
|
-
|
34
|
-
# @return [Hash] Plain-Ruby result data (`@graphql_metadata` contains Result wrapper objects)
|
35
|
-
attr_accessor :graphql_result_data
|
36
|
-
end
|
37
|
-
|
38
|
-
class GraphQLResultHash
|
39
|
-
def initialize(_result_name, _parent_result)
|
40
|
-
super
|
41
|
-
@graphql_result_data = {}
|
21
|
+
def current_object
|
22
|
+
@current_result.graphql_application_value
|
42
23
|
end
|
43
24
|
|
44
|
-
|
45
|
-
|
46
|
-
attr_accessor :graphql_merged_into
|
47
|
-
|
48
|
-
def []=(key, value)
|
49
|
-
# This is a hack.
|
50
|
-
# Basically, this object is merged into the root-level result at some point.
|
51
|
-
# But the problem is, some lazies are created whose closures retain reference to _this_
|
52
|
-
# object. When those lazies are resolved, they cause an update to this object.
|
53
|
-
#
|
54
|
-
# In order to return a proper top-level result, we have to update that top-level result object.
|
55
|
-
# In order to return a proper partial result (eg, for a directive), we have to update this object, too.
|
56
|
-
# Yowza.
|
57
|
-
if (t = @graphql_merged_into)
|
58
|
-
t[key] = value
|
59
|
-
end
|
60
|
-
|
61
|
-
if value.respond_to?(:graphql_result_data)
|
62
|
-
@graphql_result_data[key] = value.graphql_result_data
|
63
|
-
# If we encounter some part of this response that requires metadata tracking,
|
64
|
-
# then create the metadata hash if necessary. It will be kept up-to-date after this.
|
65
|
-
(@graphql_metadata ||= @graphql_result_data.dup)[key] = value
|
66
|
-
else
|
67
|
-
@graphql_result_data[key] = value
|
68
|
-
# keep this up-to-date if it's been initialized
|
69
|
-
@graphql_metadata && @graphql_metadata[key] = value
|
70
|
-
end
|
71
|
-
|
72
|
-
value
|
73
|
-
end
|
74
|
-
|
75
|
-
def delete(key)
|
76
|
-
@graphql_metadata && @graphql_metadata.delete(key)
|
77
|
-
@graphql_result_data.delete(key)
|
78
|
-
end
|
79
|
-
|
80
|
-
def each
|
81
|
-
(@graphql_metadata || @graphql_result_data).each { |k, v| yield(k, v) }
|
82
|
-
end
|
83
|
-
|
84
|
-
def values
|
85
|
-
(@graphql_metadata || @graphql_result_data).values
|
86
|
-
end
|
87
|
-
|
88
|
-
def key?(k)
|
89
|
-
@graphql_result_data.key?(k)
|
90
|
-
end
|
91
|
-
|
92
|
-
def [](k)
|
93
|
-
(@graphql_metadata || @graphql_result_data)[k]
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
class GraphQLResultArray
|
98
|
-
include GraphQLResult
|
99
|
-
|
100
|
-
def initialize(_result_name, _parent_result)
|
101
|
-
super
|
102
|
-
@graphql_result_data = []
|
103
|
-
end
|
104
|
-
|
105
|
-
def graphql_skip_at(index)
|
106
|
-
# Mark this index as dead. It's tricky because some indices may already be storing
|
107
|
-
# `Lazy`s. So the runtime is still holding indexes _before_ skipping,
|
108
|
-
# this object has to coordinate incoming writes to account for any already-skipped indices.
|
109
|
-
@skip_indices ||= []
|
110
|
-
@skip_indices << index
|
111
|
-
offset_by = @skip_indices.count { |skipped_idx| skipped_idx < index}
|
112
|
-
delete_at_index = index - offset_by
|
113
|
-
@graphql_metadata && @graphql_metadata.delete_at(delete_at_index)
|
114
|
-
@graphql_result_data.delete_at(delete_at_index)
|
115
|
-
end
|
116
|
-
|
117
|
-
def []=(idx, value)
|
118
|
-
if @skip_indices
|
119
|
-
offset_by = @skip_indices.count { |skipped_idx| skipped_idx < idx }
|
120
|
-
idx -= offset_by
|
121
|
-
end
|
122
|
-
if value.respond_to?(:graphql_result_data)
|
123
|
-
@graphql_result_data[idx] = value.graphql_result_data
|
124
|
-
(@graphql_metadata ||= @graphql_result_data.dup)[idx] = value
|
125
|
-
else
|
126
|
-
@graphql_result_data[idx] = value
|
127
|
-
@graphql_metadata && @graphql_metadata[idx] = value
|
128
|
-
end
|
129
|
-
|
130
|
-
value
|
131
|
-
end
|
132
|
-
|
133
|
-
def values
|
134
|
-
(@graphql_metadata || @graphql_result_data)
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
class GraphQLSelectionSet < Hash
|
139
|
-
attr_accessor :graphql_directives
|
25
|
+
attr_accessor :current_result, :current_result_name,
|
26
|
+
:current_arguments, :current_field, :was_authorized_by_scope_items
|
140
27
|
end
|
141
28
|
|
142
29
|
# @return [GraphQL::Query]
|
@@ -148,14 +35,14 @@ module GraphQL
|
|
148
35
|
# @return [GraphQL::Query::Context]
|
149
36
|
attr_reader :context
|
150
37
|
|
151
|
-
def initialize(query:)
|
38
|
+
def initialize(query:, lazies_at_depth:)
|
152
39
|
@query = query
|
40
|
+
@current_trace = query.current_trace
|
153
41
|
@dataloader = query.multiplex.dataloader
|
42
|
+
@lazies_at_depth = lazies_at_depth
|
154
43
|
@schema = query.schema
|
155
44
|
@context = query.context
|
156
|
-
@
|
157
|
-
@interpreter_context = @context.namespace(:interpreter)
|
158
|
-
@response = GraphQLResultHash.new(nil, nil)
|
45
|
+
@response = nil
|
159
46
|
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
|
160
47
|
@runtime_directive_names = []
|
161
48
|
noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
|
@@ -165,115 +52,165 @@ module GraphQL
|
|
165
52
|
@runtime_directive_names << name
|
166
53
|
end
|
167
54
|
end
|
168
|
-
# A cache of { Class => { String => Schema::Field } }
|
169
|
-
# Which assumes that MyObject.get_field("myField") will return the same field
|
170
|
-
# during the lifetime of a query
|
171
|
-
@fields_cache = Hash.new { |h, k| h[k] = {} }
|
172
55
|
# { Class => Boolean }
|
173
|
-
@lazy_cache = {}
|
56
|
+
@lazy_cache = {}.compare_by_identity
|
174
57
|
end
|
175
58
|
|
176
59
|
def final_result
|
177
|
-
@response
|
60
|
+
@response.respond_to?(:graphql_result_data) ? @response.graphql_result_data : @response
|
178
61
|
end
|
179
62
|
|
180
63
|
def inspect
|
181
64
|
"#<#{self.class.name} response=#{@response.inspect}>"
|
182
65
|
end
|
183
66
|
|
184
|
-
def tap_or_each(obj_or_array)
|
185
|
-
if obj_or_array.is_a?(Array)
|
186
|
-
obj_or_array.each do |item|
|
187
|
-
yield(item, true)
|
188
|
-
end
|
189
|
-
else
|
190
|
-
yield(obj_or_array, false)
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
# This _begins_ the execution. Some deferred work
|
195
|
-
# might be stored up in lazies.
|
196
67
|
# @return [void]
|
197
68
|
def run_eager
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
69
|
+
root_type = query.root_type
|
70
|
+
case query
|
71
|
+
when GraphQL::Query
|
72
|
+
ast_node = query.selected_operation
|
73
|
+
selections = ast_node.selections
|
74
|
+
object = query.root_value
|
75
|
+
is_eager = ast_node.operation_type == "mutation"
|
76
|
+
base_path = nil
|
77
|
+
when GraphQL::Query::Partial
|
78
|
+
ast_node = query.ast_nodes.first
|
79
|
+
selections = query.ast_nodes.map(&:selections).inject(&:+)
|
80
|
+
object = query.object
|
81
|
+
is_eager = false
|
82
|
+
base_path = query.path
|
209
83
|
else
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
84
|
+
raise ArgumentError, "Unexpected Runnable, can't execute: #{query.class} (#{query.inspect})"
|
85
|
+
end
|
86
|
+
object = schema.sync_lazy(object) # TODO test query partial with lazy root object
|
87
|
+
runtime_state = get_current_runtime_state
|
88
|
+
case root_type.kind.name
|
89
|
+
when "OBJECT"
|
90
|
+
object_proxy = root_type.wrap(object, context)
|
91
|
+
object_proxy = schema.sync_lazy(object_proxy)
|
92
|
+
if object_proxy.nil?
|
93
|
+
@response = nil
|
94
|
+
else
|
95
|
+
@response = GraphQLResultHash.new(nil, root_type, object_proxy, nil, false, selections, is_eager, ast_node, nil, nil)
|
96
|
+
@response.base_path = base_path
|
97
|
+
runtime_state.current_result = @response
|
98
|
+
call_method_on_directives(:resolve, object, ast_node.directives) do
|
99
|
+
each_gathered_selections(@response) do |selections, is_selection_array, ordered_result_keys|
|
100
|
+
@response.ordered_result_keys ||= ordered_result_keys
|
101
|
+
if is_selection_array
|
102
|
+
selection_response = GraphQLResultHash.new(nil, root_type, object_proxy, nil, false, selections, is_eager, ast_node, nil, nil)
|
103
|
+
selection_response.ordered_result_keys = ordered_result_keys
|
104
|
+
final_response = @response
|
105
|
+
else
|
106
|
+
selection_response = @response
|
107
|
+
final_response = nil
|
108
|
+
end
|
227
109
|
|
228
|
-
|
229
|
-
set_all_interpreter_context(query.root_value, nil, nil, path)
|
230
|
-
call_method_on_directives(:resolve, object_proxy, selections.graphql_directives) do
|
110
|
+
@dataloader.append_job {
|
231
111
|
evaluate_selections(
|
232
|
-
path,
|
233
|
-
context.scoped_context,
|
234
|
-
object_proxy,
|
235
|
-
root_type,
|
236
|
-
root_op_type == "mutation",
|
237
112
|
selections,
|
238
113
|
selection_response,
|
239
114
|
final_response,
|
240
115
|
nil,
|
241
116
|
)
|
242
|
-
|
243
|
-
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
when "LIST"
|
122
|
+
inner_type = root_type.unwrap
|
123
|
+
case inner_type.kind.name
|
124
|
+
when "SCALAR", "ENUM"
|
125
|
+
result_name = ast_node.alias || ast_node.name
|
126
|
+
field_defn = query.field_definition
|
127
|
+
owner_type = field_defn.owner
|
128
|
+
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
|
129
|
+
selection_result.base_path = base_path
|
130
|
+
selection_result.ordered_result_keys = [result_name]
|
131
|
+
runtime_state = get_current_runtime_state
|
132
|
+
runtime_state.current_result = selection_result
|
133
|
+
runtime_state.current_result_name = result_name
|
134
|
+
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
|
135
|
+
if HALT != continue_value
|
136
|
+
continue_field(continue_value, owner_type, field_defn, root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
|
137
|
+
end
|
138
|
+
@response = selection_result[result_name]
|
139
|
+
else
|
140
|
+
@response = GraphQLResultArray.new(nil, root_type, nil, nil, false, selections, false, ast_node, nil, nil)
|
141
|
+
@response.base_path = base_path
|
142
|
+
idx = nil
|
143
|
+
object.each do |inner_value|
|
144
|
+
idx ||= 0
|
145
|
+
this_idx = idx
|
146
|
+
idx += 1
|
147
|
+
@dataloader.append_job do
|
148
|
+
runtime_state.current_result_name = this_idx
|
149
|
+
runtime_state.current_result = @response
|
150
|
+
continue_field(
|
151
|
+
inner_value, root_type, nil, inner_type, nil, @response.graphql_selections, false, object_proxy,
|
152
|
+
nil, this_idx, @response, false, runtime_state
|
153
|
+
)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
when "SCALAR", "ENUM"
|
158
|
+
result_name = ast_node.alias || ast_node.name
|
159
|
+
field_defn = query.field_definition
|
160
|
+
owner_type = field_defn.owner
|
161
|
+
selection_result = GraphQLResultHash.new(nil, owner_type, nil, nil, false, EmptyObjects::EMPTY_ARRAY, false, ast_node, nil, nil)
|
162
|
+
selection_result.ordered_result_keys = [result_name]
|
163
|
+
selection_result.base_path = base_path
|
164
|
+
runtime_state = get_current_runtime_state
|
165
|
+
runtime_state.current_result = selection_result
|
166
|
+
runtime_state.current_result_name = result_name
|
167
|
+
continue_value = continue_value(object, field_defn, false, ast_node, result_name, selection_result)
|
168
|
+
if HALT != continue_value
|
169
|
+
continue_field(continue_value, owner_type, field_defn, query.root_type, ast_node, nil, false, nil, nil, result_name, selection_result, false, runtime_state) # rubocop:disable Metrics/ParameterLists
|
170
|
+
end
|
171
|
+
@response = selection_result[result_name]
|
172
|
+
when "UNION", "INTERFACE"
|
173
|
+
resolved_type, _resolved_obj = resolve_type(root_type, object)
|
174
|
+
resolved_type = schema.sync_lazy(resolved_type)
|
175
|
+
object_proxy = resolved_type.wrap(object, context)
|
176
|
+
object_proxy = schema.sync_lazy(object_proxy)
|
177
|
+
@response = GraphQLResultHash.new(nil, resolved_type, object_proxy, nil, false, selections, false, query.ast_nodes.first, nil, nil)
|
178
|
+
@response.base_path = base_path
|
179
|
+
each_gathered_selections(@response) do |selections, is_selection_array, ordered_result_keys|
|
180
|
+
@response.ordered_result_keys ||= ordered_result_keys
|
181
|
+
if is_selection_array == true
|
182
|
+
raise "This isn't supported yet"
|
244
183
|
end
|
184
|
+
|
185
|
+
@dataloader.append_job {
|
186
|
+
evaluate_selections(
|
187
|
+
selections,
|
188
|
+
@response,
|
189
|
+
nil,
|
190
|
+
runtime_state,
|
191
|
+
)
|
192
|
+
}
|
245
193
|
end
|
194
|
+
else
|
195
|
+
raise "Invariant: unsupported type kind for partial execution: #{root_type.kind.inspect} (#{root_type})"
|
246
196
|
end
|
247
|
-
delete_interpreter_context(:current_path)
|
248
|
-
delete_interpreter_context(:current_field)
|
249
|
-
delete_interpreter_context(:current_object)
|
250
|
-
delete_interpreter_context(:current_arguments)
|
251
197
|
nil
|
252
198
|
end
|
253
199
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
when GraphQLResultHash
|
262
|
-
deep_merge_selection_result(value, into_result[key])
|
263
|
-
else
|
264
|
-
# We have to assume that, since this passed the `fields_will_merge` selection,
|
265
|
-
# that the old and new values are the same.
|
266
|
-
# There's no special handling of arrays because currently, there's no way to split the execution
|
267
|
-
# of a list over several concurrent flows.
|
268
|
-
into_result[key] = value
|
269
|
-
end
|
200
|
+
def each_gathered_selections(response_hash)
|
201
|
+
ordered_result_keys = []
|
202
|
+
gathered_selections = gather_selections(response_hash.graphql_application_value, response_hash.graphql_result_type, response_hash.graphql_selections, nil, {}, ordered_result_keys)
|
203
|
+
ordered_result_keys.uniq!
|
204
|
+
if gathered_selections.is_a?(Array)
|
205
|
+
gathered_selections.each do |item|
|
206
|
+
yield(item, true, ordered_result_keys)
|
270
207
|
end
|
208
|
+
else
|
209
|
+
yield(gathered_selections, false, ordered_result_keys)
|
271
210
|
end
|
272
|
-
from_result.graphql_merged_into = into_result
|
273
|
-
nil
|
274
211
|
end
|
275
212
|
|
276
|
-
def gather_selections(owner_object, owner_type, selections, selections_to_run
|
213
|
+
def gather_selections(owner_object, owner_type, selections, selections_to_run, selections_by_name, ordered_result_keys)
|
277
214
|
selections.each do |node|
|
278
215
|
# Skip gathering this if the directive says so
|
279
216
|
if !directives_include?(node, owner_object, owner_type)
|
@@ -282,10 +219,11 @@ module GraphQL
|
|
282
219
|
|
283
220
|
if node.is_a?(GraphQL::Language::Nodes::Field)
|
284
221
|
response_key = node.alias || node.name
|
222
|
+
ordered_result_keys << response_key
|
285
223
|
selections = selections_by_name[response_key]
|
286
224
|
# if there was already a selection of this field,
|
287
225
|
# use an array to hold all selections,
|
288
|
-
#
|
226
|
+
# otherwise, use the single node to represent the selection
|
289
227
|
if selections
|
290
228
|
# This field was already selected at least once,
|
291
229
|
# add this node to the list of selections
|
@@ -298,9 +236,9 @@ module GraphQL
|
|
298
236
|
end
|
299
237
|
else
|
300
238
|
# This is an InlineFragment or a FragmentSpread
|
301
|
-
if
|
302
|
-
next_selections =
|
303
|
-
next_selections
|
239
|
+
if !@runtime_directive_names.empty? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
|
240
|
+
next_selections = {}
|
241
|
+
next_selections[:graphql_directives] = node.directives
|
304
242
|
if selections_to_run
|
305
243
|
selections_to_run << next_selections
|
306
244
|
else
|
@@ -315,27 +253,28 @@ module GraphQL
|
|
315
253
|
case node
|
316
254
|
when GraphQL::Language::Nodes::InlineFragment
|
317
255
|
if node.type
|
318
|
-
type_defn =
|
256
|
+
type_defn = query.types.type(node.type.name)
|
319
257
|
|
320
|
-
|
321
|
-
|
322
|
-
if
|
323
|
-
|
324
|
-
break
|
258
|
+
if query.types.possible_types(type_defn).include?(owner_type)
|
259
|
+
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
|
260
|
+
if !result.equal?(next_selections)
|
261
|
+
selections_to_run = result
|
325
262
|
end
|
326
263
|
end
|
327
264
|
else
|
328
265
|
# it's an untyped fragment, definitely continue
|
329
|
-
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
266
|
+
result = gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections, ordered_result_keys)
|
267
|
+
if !result.equal?(next_selections)
|
268
|
+
selections_to_run = result
|
269
|
+
end
|
330
270
|
end
|
331
271
|
when GraphQL::Language::Nodes::FragmentSpread
|
332
272
|
fragment_def = query.fragments[node.name]
|
333
|
-
type_defn = query.
|
334
|
-
|
335
|
-
|
336
|
-
if
|
337
|
-
|
338
|
-
break
|
273
|
+
type_defn = query.types.type(fragment_def.type.name)
|
274
|
+
if query.types.possible_types(type_defn).include?(owner_type)
|
275
|
+
result = gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections, ordered_result_keys)
|
276
|
+
if !result.equal?(next_selections)
|
277
|
+
selections_to_run = result
|
339
278
|
end
|
340
279
|
end
|
341
280
|
else
|
@@ -346,34 +285,49 @@ module GraphQL
|
|
346
285
|
selections_to_run || selections_by_name
|
347
286
|
end
|
348
287
|
|
349
|
-
NO_ARGS =
|
288
|
+
NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
|
350
289
|
|
351
290
|
# @return [void]
|
352
|
-
def evaluate_selections(
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
291
|
+
def evaluate_selections(gathered_selections, selections_result, target_result, runtime_state) # rubocop:disable Metrics/ParameterLists
|
292
|
+
runtime_state ||= get_current_runtime_state
|
293
|
+
runtime_state.current_result_name = nil
|
294
|
+
runtime_state.current_result = selections_result
|
295
|
+
# This is a less-frequent case; use a fast check since it's often not there.
|
296
|
+
if (directives = gathered_selections[:graphql_directives])
|
297
|
+
gathered_selections.delete(:graphql_directives)
|
298
|
+
end
|
299
|
+
|
300
|
+
call_method_on_directives(:resolve, selections_result.graphql_application_value, directives) do
|
301
|
+
gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
|
302
|
+
# Field resolution may pause the fiber,
|
303
|
+
# so it wouldn't get to the `Resolve` call that happens below.
|
304
|
+
# So instead trigger a run from this outer context.
|
305
|
+
if selections_result.graphql_is_eager
|
306
|
+
@dataloader.clear_cache
|
307
|
+
@dataloader.run_isolated {
|
308
|
+
evaluate_selection(
|
309
|
+
result_name, field_ast_nodes_or_ast_node, selections_result
|
310
|
+
)
|
311
|
+
@dataloader.clear_cache
|
312
|
+
}
|
313
|
+
else
|
314
|
+
@dataloader.append_job {
|
315
|
+
evaluate_selection(
|
316
|
+
result_name, field_ast_nodes_or_ast_node, selections_result
|
317
|
+
)
|
318
|
+
}
|
365
319
|
end
|
366
|
-
|
320
|
+
end
|
321
|
+
if target_result
|
322
|
+
selections_result.merge_into(target_result)
|
323
|
+
end
|
324
|
+
selections_result
|
367
325
|
end
|
368
|
-
|
369
|
-
selections_result
|
370
326
|
end
|
371
327
|
|
372
|
-
attr_reader :progress_path
|
373
|
-
|
374
328
|
# @return [void]
|
375
|
-
def evaluate_selection(
|
376
|
-
return if
|
329
|
+
def evaluate_selection(result_name, field_ast_nodes_or_ast_node, selections_result) # rubocop:disable Metrics/ParameterLists
|
330
|
+
return if selections_result.graphql_dead
|
377
331
|
# As a performance optimization, the hash key will be a `Node` if
|
378
332
|
# there's only one selection of the field. But if there are multiple
|
379
333
|
# selections of the field, it will be an Array of nodes
|
@@ -385,67 +339,52 @@ module GraphQL
|
|
385
339
|
ast_node = field_ast_nodes_or_ast_node
|
386
340
|
end
|
387
341
|
field_name = ast_node.name
|
388
|
-
|
389
|
-
|
390
|
-
field_defn = @fields_cache[owner_type][field_name] ||= owner_type.get_field(field_name, @context)
|
391
|
-
is_introspection = false
|
392
|
-
if field_defn.nil?
|
393
|
-
field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
|
394
|
-
is_introspection = true
|
395
|
-
entry_point_field
|
396
|
-
elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
|
397
|
-
is_introspection = true
|
398
|
-
dynamic_field
|
399
|
-
else
|
400
|
-
raise "Invariant: no field for #{owner_type}.#{field_name}"
|
401
|
-
end
|
402
|
-
end
|
342
|
+
owner_type = selections_result.graphql_result_type
|
343
|
+
field_defn = query.types.field(owner_type, field_name)
|
403
344
|
|
404
|
-
return_type = field_defn.type
|
405
|
-
|
406
|
-
next_path = path.dup
|
407
|
-
next_path << result_name
|
408
|
-
next_path.freeze
|
409
|
-
|
410
|
-
# This seems janky, but we need to know
|
411
|
-
# the field's return type at this path in order
|
412
|
-
# to propagate `null`
|
413
|
-
if return_type.non_null?
|
414
|
-
(selections_result.graphql_non_null_field_names ||= []).push(result_name)
|
415
|
-
end
|
416
345
|
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
417
|
-
|
346
|
+
runtime_state = get_current_runtime_state
|
347
|
+
runtime_state.current_field = field_defn
|
348
|
+
runtime_state.current_result = selections_result
|
349
|
+
runtime_state.current_result_name = result_name
|
418
350
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
if is_introspection
|
423
|
-
object = authorized_new(field_defn.owner, object, context)
|
351
|
+
owner_object = selections_result.graphql_application_value
|
352
|
+
if field_defn.dynamic_introspection
|
353
|
+
owner_object = field_defn.owner.wrap(owner_object, context)
|
424
354
|
end
|
425
355
|
|
426
|
-
|
427
|
-
if total_args_count == 0
|
356
|
+
if !field_defn.any_arguments?
|
428
357
|
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
429
|
-
|
358
|
+
if field_defn.extras.size == 0
|
359
|
+
evaluate_selection_with_resolved_keyword_args(
|
360
|
+
NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state
|
361
|
+
)
|
362
|
+
else
|
363
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
|
364
|
+
end
|
430
365
|
else
|
431
|
-
|
432
|
-
|
433
|
-
evaluate_selection_with_args(resolved_arguments, field_defn,
|
366
|
+
@query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
|
367
|
+
runtime_state = get_current_runtime_state # This might be in a different fiber
|
368
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_object, result_name, selections_result, runtime_state)
|
434
369
|
end
|
435
370
|
end
|
436
371
|
end
|
437
372
|
|
438
|
-
def evaluate_selection_with_args(arguments, field_defn,
|
439
|
-
|
440
|
-
after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
|
373
|
+
def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state) # rubocop:disable Metrics/ParameterLists
|
374
|
+
after_lazy(arguments, field: field_defn, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |resolved_arguments, runtime_state|
|
441
375
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
442
|
-
|
376
|
+
return_type_non_null = field_defn.type.non_null?
|
377
|
+
continue_value(resolved_arguments, field_defn, return_type_non_null, ast_node, result_name, selection_result)
|
443
378
|
next
|
444
379
|
end
|
445
380
|
|
446
|
-
kwarg_arguments = if
|
447
|
-
|
448
|
-
|
381
|
+
kwarg_arguments = if field_defn.extras.empty?
|
382
|
+
if resolved_arguments.empty?
|
383
|
+
# We can avoid allocating the `{ Symbol => Object }` hash in this case
|
384
|
+
NO_ARGS
|
385
|
+
else
|
386
|
+
resolved_arguments.keyword_arguments
|
387
|
+
end
|
449
388
|
else
|
450
389
|
# Bundle up the extras, then make a new arguments instance
|
451
390
|
# that includes the extras, too.
|
@@ -455,9 +394,9 @@ module GraphQL
|
|
455
394
|
when :ast_node
|
456
395
|
extra_args[:ast_node] = ast_node
|
457
396
|
when :execution_errors
|
458
|
-
extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node,
|
397
|
+
extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node, current_path)
|
459
398
|
when :path
|
460
|
-
extra_args[:path] =
|
399
|
+
extra_args[:path] = current_path
|
461
400
|
when :lookahead
|
462
401
|
if !field_ast_nodes
|
463
402
|
field_ast_nodes = [ast_node]
|
@@ -472,79 +411,90 @@ module GraphQL
|
|
472
411
|
# Use this flag to tell Interpreter::Arguments to add itself
|
473
412
|
# to the keyword args hash _before_ freezing everything.
|
474
413
|
extra_args[:argument_details] = :__arguments_add_self
|
475
|
-
when :irep_node
|
476
|
-
# This is used by `__typename` in order to support the legacy runtime,
|
477
|
-
# but it has no use here (and it's always `nil`).
|
478
|
-
# Stop adding it here to avoid the overhead of `.merge_extras` below.
|
479
414
|
when :parent
|
480
|
-
|
415
|
+
parent_result = selection_result.graphql_parent
|
416
|
+
extra_args[:parent] = parent_result&.graphql_application_value&.object
|
481
417
|
else
|
482
418
|
extra_args[extra] = field_defn.fetch_extra(extra, context)
|
483
419
|
end
|
484
420
|
end
|
485
|
-
if extra_args.
|
421
|
+
if !extra_args.empty?
|
486
422
|
resolved_arguments = resolved_arguments.merge_extras(extra_args)
|
487
423
|
end
|
488
424
|
resolved_arguments.keyword_arguments
|
489
425
|
end
|
490
426
|
|
491
|
-
|
427
|
+
evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state)
|
428
|
+
end
|
429
|
+
end
|
492
430
|
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
431
|
+
def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, object, result_name, selection_result, runtime_state) # rubocop:disable Metrics/ParameterLists
|
432
|
+
runtime_state.current_field = field_defn
|
433
|
+
runtime_state.current_arguments = resolved_arguments
|
434
|
+
runtime_state.current_result_name = result_name
|
435
|
+
runtime_state.current_result = selection_result
|
436
|
+
# Optimize for the case that field is selected only once
|
437
|
+
if field_ast_nodes.nil? || field_ast_nodes.size == 1
|
438
|
+
next_selections = ast_node.selections
|
439
|
+
directives = ast_node.directives
|
440
|
+
else
|
441
|
+
next_selections = []
|
442
|
+
directives = []
|
443
|
+
field_ast_nodes.each { |f|
|
444
|
+
next_selections.concat(f.selections)
|
445
|
+
directives.concat(f.directives)
|
446
|
+
}
|
447
|
+
end
|
505
448
|
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
449
|
+
field_result = call_method_on_directives(:resolve, object, directives) do
|
450
|
+
if !directives.empty?
|
451
|
+
# This might be executed in a different context; reset this info
|
452
|
+
runtime_state = get_current_runtime_state
|
453
|
+
runtime_state.current_field = field_defn
|
454
|
+
runtime_state.current_arguments = resolved_arguments
|
455
|
+
runtime_state.current_result_name = result_name
|
456
|
+
runtime_state.current_result = selection_result
|
457
|
+
end
|
458
|
+
# Actually call the field resolver and capture the result
|
459
|
+
app_result = begin
|
460
|
+
@current_trace.begin_execute_field(field_defn, object, kwarg_arguments, query)
|
461
|
+
@current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
|
462
|
+
field_defn.resolve(object, kwarg_arguments, context)
|
516
463
|
end
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
464
|
+
rescue GraphQL::ExecutionError => err
|
465
|
+
err
|
466
|
+
rescue StandardError => err
|
467
|
+
begin
|
468
|
+
query.handle_or_reraise(err)
|
469
|
+
rescue GraphQL::ExecutionError => ex_err
|
470
|
+
ex_err
|
522
471
|
end
|
523
472
|
end
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
473
|
+
@current_trace.end_execute_field(field_defn, object, kwarg_arguments, query, app_result)
|
474
|
+
after_lazy(app_result, field: field_defn, ast_node: ast_node, owner_object: object, arguments: resolved_arguments, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_result, runtime_state|
|
475
|
+
owner_type = selection_result.graphql_result_type
|
476
|
+
return_type = field_defn.type
|
477
|
+
continue_value = continue_value(inner_result, field_defn, return_type.non_null?, ast_node, result_name, selection_result)
|
478
|
+
if HALT != continue_value
|
479
|
+
was_scoped = runtime_state.was_authorized_by_scope_items
|
480
|
+
runtime_state.was_authorized_by_scope_items = nil
|
481
|
+
continue_field(continue_value, owner_type, field_defn, return_type, ast_node, next_selections, false, object, resolved_arguments, result_name, selection_result, was_scoped, runtime_state)
|
482
|
+
else
|
483
|
+
nil
|
484
|
+
end
|
533
485
|
end
|
534
486
|
end
|
487
|
+
# If this field is a root mutation field, immediately resolve
|
488
|
+
# all of its child fields before moving on to the next root mutation field.
|
489
|
+
# (Subselections of this mutation will still be resolved level-by-level.)
|
490
|
+
if selection_result.graphql_is_eager
|
491
|
+
Interpreter::Resolve.resolve_all([field_result], @dataloader)
|
492
|
+
end
|
535
493
|
end
|
536
494
|
|
537
|
-
def
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
def set_result(selection_result, result_name, value)
|
542
|
-
if !dead_result?(selection_result)
|
543
|
-
if value.nil? &&
|
544
|
-
( # there are two conditions under which `nil` is not allowed in the response:
|
545
|
-
(selection_result.graphql_non_null_list_items) || # this value would be written into a list that doesn't allow nils
|
546
|
-
((nn = selection_result.graphql_non_null_field_names) && nn.include?(result_name)) # this value would be written into a field that doesn't allow nils
|
547
|
-
)
|
495
|
+
def set_result(selection_result, result_name, value, is_child_result, is_non_null)
|
496
|
+
if !selection_result.graphql_dead
|
497
|
+
if value.nil? && is_non_null
|
548
498
|
# This is an invalid nil that should be propagated
|
549
499
|
# One caller of this method passes a block,
|
550
500
|
# namely when application code returns a `nil` to GraphQL and it doesn't belong there.
|
@@ -554,15 +504,18 @@ module GraphQL
|
|
554
504
|
# TODO the code is trying to tell me something.
|
555
505
|
yield if block_given?
|
556
506
|
parent = selection_result.graphql_parent
|
557
|
-
name_in_parent = selection_result.graphql_result_name
|
558
507
|
if parent.nil? # This is a top-level result hash
|
559
508
|
@response = nil
|
560
509
|
else
|
561
|
-
|
510
|
+
name_in_parent = selection_result.graphql_result_name
|
511
|
+
is_non_null_in_parent = selection_result.graphql_is_non_null_in_parent
|
512
|
+
set_result(parent, name_in_parent, nil, false, is_non_null_in_parent)
|
562
513
|
set_graphql_dead(selection_result)
|
563
514
|
end
|
515
|
+
elsif is_child_result
|
516
|
+
selection_result.set_child_result(result_name, value)
|
564
517
|
else
|
565
|
-
selection_result
|
518
|
+
selection_result.set_leaf(result_name, value)
|
566
519
|
end
|
567
520
|
end
|
568
521
|
end
|
@@ -582,18 +535,32 @@ module GraphQL
|
|
582
535
|
end
|
583
536
|
end
|
584
537
|
|
585
|
-
|
586
|
-
|
538
|
+
def current_path
|
539
|
+
st = get_current_runtime_state
|
540
|
+
result = st.current_result
|
541
|
+
path = result && result.path
|
542
|
+
if path && (rn = st.current_result_name)
|
543
|
+
path = path.dup
|
544
|
+
path.push(rn)
|
545
|
+
end
|
546
|
+
path
|
547
|
+
end
|
548
|
+
|
549
|
+
HALT = Object.new.freeze
|
550
|
+
def continue_value(value, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
587
551
|
case value
|
588
552
|
when nil
|
589
553
|
if is_non_null
|
590
|
-
set_result(selection_result, result_name, nil) do
|
554
|
+
set_result(selection_result, result_name, nil, false, is_non_null) do
|
555
|
+
# When this comes from a list item, use the parent object:
|
556
|
+
is_from_array = selection_result.is_a?(GraphQLResultArray)
|
557
|
+
parent_type = is_from_array ? selection_result.graphql_parent.graphql_result_type : selection_result.graphql_result_type
|
591
558
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
592
|
-
err = parent_type::InvalidNullError.new(parent_type, field,
|
559
|
+
err = parent_type::InvalidNullError.new(parent_type, field, ast_node, is_from_array: is_from_array)
|
593
560
|
schema.type_error(err, context)
|
594
561
|
end
|
595
562
|
else
|
596
|
-
set_result(selection_result, result_name, nil)
|
563
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
597
564
|
end
|
598
565
|
HALT
|
599
566
|
when GraphQL::Error
|
@@ -601,15 +568,25 @@ module GraphQL
|
|
601
568
|
# to avoid the overhead of checking three different classes
|
602
569
|
# every time.
|
603
570
|
if value.is_a?(GraphQL::ExecutionError)
|
604
|
-
if selection_result.nil? || !
|
605
|
-
value.path ||=
|
571
|
+
if selection_result.nil? || !selection_result.graphql_dead
|
572
|
+
value.path ||= current_path
|
606
573
|
value.ast_node ||= ast_node
|
607
574
|
context.errors << value
|
608
575
|
if selection_result
|
609
|
-
set_result(selection_result, result_name, nil)
|
576
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
610
577
|
end
|
611
578
|
end
|
612
579
|
HALT
|
580
|
+
elsif value.is_a?(GraphQL::UnauthorizedFieldError)
|
581
|
+
value.field ||= field
|
582
|
+
# this hook might raise & crash, or it might return
|
583
|
+
# a replacement value
|
584
|
+
next_value = begin
|
585
|
+
schema.unauthorized_field(value)
|
586
|
+
rescue GraphQL::ExecutionError => err
|
587
|
+
err
|
588
|
+
end
|
589
|
+
continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
|
613
590
|
elsif value.is_a?(GraphQL::UnauthorizedError)
|
614
591
|
# this hook might raise & crash, or it might return
|
615
592
|
# a replacement value
|
@@ -618,8 +595,8 @@ module GraphQL
|
|
618
595
|
rescue GraphQL::ExecutionError => err
|
619
596
|
err
|
620
597
|
end
|
621
|
-
continue_value(
|
622
|
-
elsif GraphQL::Execution::
|
598
|
+
continue_value(next_value, field, is_non_null, ast_node, result_name, selection_result)
|
599
|
+
elsif GraphQL::Execution::SKIP == value
|
623
600
|
# It's possible a lazy was already written here
|
624
601
|
case selection_result
|
625
602
|
when GraphQLResultHash
|
@@ -639,20 +616,20 @@ module GraphQL
|
|
639
616
|
end
|
640
617
|
when Array
|
641
618
|
# It's an array full of execution errors; add them all.
|
642
|
-
if value.
|
619
|
+
if !value.empty? && value.all?(GraphQL::ExecutionError)
|
643
620
|
list_type_at_all = (field && (field.type.list?))
|
644
|
-
if selection_result.nil? || !
|
621
|
+
if selection_result.nil? || !selection_result.graphql_dead
|
645
622
|
value.each_with_index do |error, index|
|
646
623
|
error.ast_node ||= ast_node
|
647
|
-
error.path ||=
|
624
|
+
error.path ||= current_path + (list_type_at_all ? [index] : [])
|
648
625
|
context.errors << error
|
649
626
|
end
|
650
627
|
if selection_result
|
651
628
|
if list_type_at_all
|
652
629
|
result_without_errors = value.map { |v| v.is_a?(GraphQL::ExecutionError) ? nil : v }
|
653
|
-
set_result(selection_result, result_name, result_without_errors)
|
630
|
+
set_result(selection_result, result_name, result_without_errors, false, is_non_null)
|
654
631
|
else
|
655
|
-
set_result(selection_result, result_name, nil)
|
632
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
656
633
|
end
|
657
634
|
end
|
658
635
|
end
|
@@ -662,7 +639,7 @@ module GraphQL
|
|
662
639
|
end
|
663
640
|
when GraphQL::Execution::Interpreter::RawValue
|
664
641
|
# Write raw value directly to the response without resolving nested objects
|
665
|
-
set_result(selection_result, result_name, value.resolve)
|
642
|
+
set_result(selection_result, result_name, value.resolve, false, is_non_null)
|
666
643
|
HALT
|
667
644
|
else
|
668
645
|
value
|
@@ -677,7 +654,7 @@ module GraphQL
|
|
677
654
|
# Location information from `path` and `ast_node`.
|
678
655
|
#
|
679
656
|
# @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
|
680
|
-
def continue_field(
|
657
|
+
def continue_field(value, owner_type, field, current_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
|
681
658
|
if current_type.non_null?
|
682
659
|
current_type = current_type.of_type
|
683
660
|
is_non_null = true
|
@@ -685,70 +662,75 @@ module GraphQL
|
|
685
662
|
|
686
663
|
case current_type.kind.name
|
687
664
|
when "SCALAR", "ENUM"
|
688
|
-
r =
|
689
|
-
|
665
|
+
r = begin
|
666
|
+
current_type.coerce_result(value, context)
|
667
|
+
rescue GraphQL::ExecutionError => ex_err
|
668
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
669
|
+
rescue StandardError => err
|
670
|
+
query.handle_or_reraise(err)
|
671
|
+
end
|
672
|
+
set_result(selection_result, result_name, r, false, is_non_null)
|
690
673
|
r
|
691
674
|
when "UNION", "INTERFACE"
|
692
|
-
resolved_type_or_lazy
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
|
675
|
+
resolved_type_or_lazy = begin
|
676
|
+
resolve_type(current_type, value)
|
677
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
678
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
679
|
+
rescue StandardError => err
|
680
|
+
begin
|
681
|
+
query.handle_or_reraise(err)
|
682
|
+
rescue GraphQL::ExecutionError => ex_err
|
683
|
+
return continue_value(ex_err, field, is_non_null, ast_node, result_name, selection_result)
|
684
|
+
end
|
685
|
+
end
|
686
|
+
after_lazy(resolved_type_or_lazy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |resolved_type_result, runtime_state|
|
687
|
+
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
688
|
+
resolved_type, resolved_value = resolved_type_result
|
689
|
+
else
|
690
|
+
resolved_type = resolved_type_result
|
691
|
+
resolved_value = value
|
692
|
+
end
|
697
693
|
|
694
|
+
possible_types = query.types.possible_types(current_type)
|
698
695
|
if !possible_types.include?(resolved_type)
|
699
696
|
parent_type = field.owner_type
|
700
697
|
err_class = current_type::UnresolvedTypeError
|
701
698
|
type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
|
702
699
|
schema.type_error(type_error, context)
|
703
|
-
set_result(selection_result, result_name, nil)
|
700
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
704
701
|
nil
|
705
702
|
else
|
706
|
-
continue_field(
|
703
|
+
continue_field(resolved_value, owner_type, field, resolved_type, ast_node, next_selections, is_non_null, owner_object, arguments, result_name, selection_result, was_scoped, runtime_state)
|
707
704
|
end
|
708
705
|
end
|
709
706
|
when "OBJECT"
|
710
707
|
object_proxy = begin
|
711
|
-
|
708
|
+
was_scoped ? current_type.wrap_scoped(value, context) : current_type.wrap(value, context)
|
712
709
|
rescue GraphQL::ExecutionError => err
|
713
710
|
err
|
714
711
|
end
|
715
|
-
after_lazy(object_proxy,
|
716
|
-
continue_value = continue_value(
|
712
|
+
after_lazy(object_proxy, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result, runtime_state: runtime_state) do |inner_object, runtime_state|
|
713
|
+
continue_value = continue_value(inner_object, field, is_non_null, ast_node, result_name, selection_result)
|
717
714
|
if HALT != continue_value
|
718
|
-
response_hash = GraphQLResultHash.new(result_name, selection_result)
|
719
|
-
set_result(selection_result, result_name, response_hash)
|
720
|
-
|
721
|
-
|
722
|
-
# 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
|
723
|
-
# This case is handled below, and the result can be written right into the main `response_hash` above.
|
724
|
-
# In this case, `gathered_selections` is a hash of selections.
|
725
|
-
# 2. Some selections of this object have runtime directives that may or may not modify execution.
|
726
|
-
# That part of the selection is evaluated in an isolated way, writing into a sub-response object which is
|
727
|
-
# eventually merged into the final response. In this case, `gathered_selections` is an array of things to run in isolation.
|
728
|
-
# (Technically, it's possible that one of those entries _doesn't_ require isolation.)
|
729
|
-
tap_or_each(gathered_selections) do |selections, is_selection_array|
|
715
|
+
response_hash = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
716
|
+
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
717
|
+
each_gathered_selections(response_hash) do |selections, is_selection_array, ordered_result_keys|
|
718
|
+
response_hash.ordered_result_keys ||= ordered_result_keys
|
730
719
|
if is_selection_array
|
731
|
-
this_result = GraphQLResultHash.new(result_name, selection_result)
|
720
|
+
this_result = GraphQLResultHash.new(result_name, current_type, continue_value, selection_result, is_non_null, selections, false, ast_node, arguments, field)
|
721
|
+
this_result.ordered_result_keys = ordered_result_keys
|
732
722
|
final_result = response_hash
|
733
723
|
else
|
734
724
|
this_result = response_hash
|
735
725
|
final_result = nil
|
736
726
|
end
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
false,
|
745
|
-
selections,
|
746
|
-
this_result,
|
747
|
-
final_result,
|
748
|
-
owner_object.object,
|
749
|
-
)
|
750
|
-
this_result
|
751
|
-
end
|
727
|
+
|
728
|
+
evaluate_selections(
|
729
|
+
selections,
|
730
|
+
this_result,
|
731
|
+
final_result,
|
732
|
+
runtime_state,
|
733
|
+
)
|
752
734
|
end
|
753
735
|
end
|
754
736
|
end
|
@@ -756,53 +738,68 @@ module GraphQL
|
|
756
738
|
inner_type = current_type.of_type
|
757
739
|
# This is true for objects, unions, and interfaces
|
758
740
|
use_dataloader_job = !inner_type.unwrap.kind.input?
|
759
|
-
|
760
|
-
response_list
|
761
|
-
set_result(selection_result, result_name, response_list)
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
resolve_list_item(inner_value, inner_type, next_path, ast_node, scoped_context, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type)
|
741
|
+
inner_type_non_null = inner_type.non_null?
|
742
|
+
response_list = GraphQLResultArray.new(result_name, current_type, owner_object, selection_result, is_non_null, next_selections, false, ast_node, arguments, field)
|
743
|
+
set_result(selection_result, result_name, response_list, true, is_non_null)
|
744
|
+
idx = nil
|
745
|
+
list_value = begin
|
746
|
+
begin
|
747
|
+
value.each do |inner_value|
|
748
|
+
idx ||= 0
|
749
|
+
this_idx = idx
|
750
|
+
idx += 1
|
751
|
+
if use_dataloader_job
|
752
|
+
@dataloader.append_job do
|
753
|
+
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
754
|
+
end
|
755
|
+
else
|
756
|
+
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state)
|
776
757
|
end
|
758
|
+
end
|
759
|
+
|
760
|
+
response_list
|
761
|
+
rescue NoMethodError => err
|
762
|
+
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
763
|
+
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
764
|
+
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
765
|
+
raise ListResultFailedError.new(value: value, field: field, path: current_path)
|
777
766
|
else
|
778
|
-
|
767
|
+
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
768
|
+
raise
|
769
|
+
end
|
770
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
771
|
+
ex_err
|
772
|
+
rescue StandardError => err
|
773
|
+
begin
|
774
|
+
query.handle_or_reraise(err)
|
775
|
+
rescue GraphQL::ExecutionError => ex_err
|
776
|
+
ex_err
|
779
777
|
end
|
780
778
|
end
|
781
|
-
rescue
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
else
|
787
|
-
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
788
|
-
raise
|
779
|
+
rescue StandardError => err
|
780
|
+
begin
|
781
|
+
query.handle_or_reraise(err)
|
782
|
+
rescue GraphQL::ExecutionError => ex_err
|
783
|
+
ex_err
|
789
784
|
end
|
790
785
|
end
|
791
|
-
|
792
|
-
|
786
|
+
# Detect whether this error came while calling `.each` (before `idx` is set) or while running list *items* (after `idx` is set)
|
787
|
+
error_is_non_null = idx.nil? ? is_non_null : inner_type.non_null?
|
788
|
+
continue_value(list_value, field, error_is_non_null, ast_node, result_name, selection_result)
|
793
789
|
else
|
794
790
|
raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
|
795
791
|
end
|
796
792
|
end
|
797
793
|
|
798
|
-
def resolve_list_item(inner_value, inner_type,
|
799
|
-
|
794
|
+
def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, owner_type, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
|
795
|
+
runtime_state.current_result_name = this_idx
|
796
|
+
runtime_state.current_result = response_list
|
800
797
|
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
801
798
|
# This will update `response_list` with the lazy
|
802
|
-
after_lazy(inner_value,
|
803
|
-
continue_value = continue_value(
|
799
|
+
after_lazy(inner_value, ast_node: ast_node, field: field, owner_object: owner_object, arguments: arguments, result_name: this_idx, result: response_list, runtime_state: runtime_state) do |inner_inner_value, runtime_state|
|
800
|
+
continue_value = continue_value(inner_inner_value, field, inner_type_non_null, ast_node, this_idx, response_list)
|
804
801
|
if HALT != continue_value
|
805
|
-
continue_field(
|
802
|
+
continue_field(continue_value, owner_type, field, inner_type, ast_node, response_list.graphql_selections, false, owner_object, arguments, this_idx, response_list, was_scoped, runtime_state)
|
806
803
|
end
|
807
804
|
end
|
808
805
|
end
|
@@ -819,14 +816,16 @@ module GraphQL
|
|
819
816
|
yield
|
820
817
|
else
|
821
818
|
dir_defn = @schema_directives.fetch(dir_node.name)
|
822
|
-
if !dir_defn.is_a?(Class)
|
823
|
-
dir_defn = dir_defn.type_class || raise("Only class-based directives are supported (not `@#{dir_node.name}`)")
|
824
|
-
end
|
825
819
|
raw_dir_args = arguments(nil, dir_defn, dir_node)
|
820
|
+
if !raw_dir_args.is_a?(GraphQL::ExecutionError)
|
821
|
+
begin
|
822
|
+
dir_defn.validate!(raw_dir_args, context)
|
823
|
+
rescue GraphQL::ExecutionError => err
|
824
|
+
raw_dir_args = err
|
825
|
+
end
|
826
|
+
end
|
826
827
|
dir_args = continue_value(
|
827
|
-
@context[:current_path], # path
|
828
828
|
raw_dir_args, # value
|
829
|
-
dir_defn, # parent_type
|
830
829
|
nil, # field
|
831
830
|
false, # is_non_null
|
832
831
|
dir_node, # ast_node
|
@@ -847,7 +846,7 @@ module GraphQL
|
|
847
846
|
# Check {Schema::Directive.include?} for each directive that's present
|
848
847
|
def directives_include?(node, graphql_object, parent_type)
|
849
848
|
node.directives.each do |dir_node|
|
850
|
-
dir_defn = @schema_directives.fetch(dir_node.name)
|
849
|
+
dir_defn = @schema_directives.fetch(dir_node.name)
|
851
850
|
args = arguments(graphql_object, dir_defn, dir_node)
|
852
851
|
if !dir_defn.include?(graphql_object, args, context)
|
853
852
|
return false
|
@@ -856,63 +855,85 @@ module GraphQL
|
|
856
855
|
true
|
857
856
|
end
|
858
857
|
|
859
|
-
def
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
858
|
+
def get_current_runtime_state
|
859
|
+
current_state = Fiber[:__graphql_runtime_info] ||= {}.compare_by_identity
|
860
|
+
current_state[@query] ||= CurrentState.new
|
861
|
+
end
|
862
|
+
|
863
|
+
def minimal_after_lazy(value, &block)
|
864
|
+
if lazy?(value)
|
865
|
+
GraphQL::Execution::Lazy.new do
|
866
|
+
result = @schema.sync_lazy(value)
|
867
|
+
# The returned result might also be lazy, so check it, too
|
868
|
+
minimal_after_lazy(result, &block)
|
869
|
+
end
|
870
|
+
else
|
871
|
+
yield(value)
|
871
872
|
end
|
872
873
|
end
|
873
874
|
|
874
875
|
# @param obj [Object] Some user-returned value that may want to be batched
|
875
|
-
# @param path [Array<String>]
|
876
876
|
# @param field [GraphQL::Schema::Field]
|
877
877
|
# @param eager [Boolean] Set to `true` for mutation root fields only
|
878
878
|
# @param trace [Boolean] If `false`, don't wrap this with field tracing
|
879
879
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
880
|
-
def after_lazy(lazy_obj,
|
880
|
+
def after_lazy(lazy_obj, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, runtime_state:, trace: true, &block)
|
881
881
|
if lazy?(lazy_obj)
|
882
|
-
|
883
|
-
|
884
|
-
|
882
|
+
orig_result = result
|
883
|
+
was_authorized_by_scope_items = runtime_state.was_authorized_by_scope_items
|
884
|
+
lazy = GraphQL::Execution::Lazy.new(field: field) do
|
885
|
+
# This block might be called in a new fiber;
|
886
|
+
# In that case, this will initialize a new state
|
887
|
+
# to avoid conflicting with the parent fiber.
|
888
|
+
runtime_state = get_current_runtime_state
|
889
|
+
runtime_state.current_field = field
|
890
|
+
runtime_state.current_arguments = arguments
|
891
|
+
runtime_state.current_result_name = result_name
|
892
|
+
runtime_state.current_result = orig_result
|
893
|
+
runtime_state.was_authorized_by_scope_items = was_authorized_by_scope_items
|
885
894
|
# Wrap the execution of _this_ method with tracing,
|
886
895
|
# but don't wrap the continuation below
|
896
|
+
result = nil
|
887
897
|
inner_obj = begin
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
schema.sync_lazy(lazy_obj)
|
893
|
-
end
|
894
|
-
else
|
895
|
-
schema.sync_lazy(lazy_obj)
|
896
|
-
end
|
897
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
|
898
|
-
err
|
898
|
+
result = if trace
|
899
|
+
@current_trace.begin_execute_field(field, owner_object, arguments, query)
|
900
|
+
@current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
901
|
+
schema.sync_lazy(lazy_obj)
|
899
902
|
end
|
903
|
+
else
|
904
|
+
schema.sync_lazy(lazy_obj)
|
900
905
|
end
|
901
|
-
rescue GraphQL::ExecutionError => ex_err
|
906
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
902
907
|
ex_err
|
908
|
+
rescue StandardError => err
|
909
|
+
begin
|
910
|
+
query.handle_or_reraise(err)
|
911
|
+
rescue GraphQL::ExecutionError => ex_err
|
912
|
+
ex_err
|
913
|
+
end
|
914
|
+
ensure
|
915
|
+
if trace
|
916
|
+
@current_trace.end_execute_field(field, owner_object, arguments, query, result)
|
917
|
+
end
|
903
918
|
end
|
904
|
-
yield(inner_obj)
|
919
|
+
yield(inner_obj, runtime_state)
|
905
920
|
end
|
906
921
|
|
907
922
|
if eager
|
908
923
|
lazy.value
|
909
924
|
else
|
910
|
-
set_result(result, result_name, lazy)
|
925
|
+
set_result(result, result_name, lazy, false, false) # is_non_null is irrelevant here
|
926
|
+
current_depth = 0
|
927
|
+
while result
|
928
|
+
current_depth += 1
|
929
|
+
result = result.graphql_parent
|
930
|
+
end
|
931
|
+
@lazies_at_depth[current_depth] << lazy
|
911
932
|
lazy
|
912
933
|
end
|
913
934
|
else
|
914
|
-
|
915
|
-
yield(lazy_obj)
|
935
|
+
# Don't need to reset state here because it _wasn't_ lazy.
|
936
|
+
yield(lazy_obj, runtime_state)
|
916
937
|
end
|
917
938
|
end
|
918
939
|
|
@@ -925,28 +946,31 @@ module GraphQL
|
|
925
946
|
end
|
926
947
|
end
|
927
948
|
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
@context.delete(key)
|
949
|
+
def delete_all_interpreter_context
|
950
|
+
per_query_state = Fiber[:__graphql_runtime_info]
|
951
|
+
if per_query_state
|
952
|
+
per_query_state.delete(@query)
|
953
|
+
if per_query_state.size == 0
|
954
|
+
Fiber[:__graphql_runtime_info] = nil
|
955
|
+
end
|
956
|
+
end
|
957
|
+
nil
|
938
958
|
end
|
939
959
|
|
940
|
-
def resolve_type(type, value
|
941
|
-
|
942
|
-
resolved_type, resolved_value =
|
960
|
+
def resolve_type(type, value)
|
961
|
+
@current_trace.begin_resolve_type(type, value, context)
|
962
|
+
resolved_type, resolved_value = @current_trace.resolve_type(query: query, type: type, object: value) do
|
943
963
|
query.resolve_type(type, value)
|
944
964
|
end
|
965
|
+
@current_trace.end_resolve_type(type, value, context, resolved_type)
|
945
966
|
|
946
967
|
if lazy?(resolved_type)
|
947
968
|
GraphQL::Execution::Lazy.new do
|
948
|
-
|
949
|
-
|
969
|
+
@current_trace.begin_resolve_type(type, value, context)
|
970
|
+
@current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
971
|
+
rt = schema.sync_lazy(resolved_type)
|
972
|
+
@current_trace.end_resolve_type(type, value, context, rt)
|
973
|
+
rt
|
950
974
|
end
|
951
975
|
end
|
952
976
|
else
|
@@ -954,14 +978,13 @@ module GraphQL
|
|
954
978
|
end
|
955
979
|
end
|
956
980
|
|
957
|
-
def authorized_new(type, value, context)
|
958
|
-
type.authorized_new(value, context)
|
959
|
-
end
|
960
|
-
|
961
981
|
def lazy?(object)
|
962
|
-
|
963
|
-
|
964
|
-
|
982
|
+
obj_class = object.class
|
983
|
+
is_lazy = @lazy_cache[obj_class]
|
984
|
+
if is_lazy.nil?
|
985
|
+
is_lazy = @lazy_cache[obj_class] = @schema.lazy?(object)
|
986
|
+
end
|
987
|
+
is_lazy
|
965
988
|
end
|
966
989
|
end
|
967
990
|
end
|