graphql 1.12.12 → 2.2.14
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.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +3 -8
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +14 -4
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +10 -38
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +23 -12
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- 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 +6 -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/enum.erb +5 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/schema.erb +19 -2
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/ast/analyzer.rb +7 -0
- data/lib/graphql/analysis/ast/field_usage.rb +55 -1
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -1
- data/lib/graphql/analysis/ast/query_complexity.rb +88 -140
- data/lib/graphql/analysis/ast/query_depth.rb +7 -3
- data/lib/graphql/analysis/ast/visitor.rb +50 -42
- data/lib/graphql/analysis/ast.rb +26 -23
- data/lib/graphql/analysis.rb +0 -7
- data/lib/graphql/backtrace/table.rb +4 -22
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +8 -6
- data/lib/graphql/backtrace.rb +3 -8
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/dataloader/async_dataloader.rb +85 -0
- data/lib/graphql/dataloader/null_dataloader.rb +3 -1
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +120 -31
- data/lib/graphql/dataloader.rb +168 -142
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -81
- data/lib/graphql/execution/interpreter/arguments.rb +2 -2
- data/lib/graphql/execution/interpreter/arguments_cache.rb +36 -34
- data/lib/graphql/execution/interpreter/resolve.rb +32 -2
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +170 -0
- data/lib/graphql/execution/interpreter/runtime.rb +414 -341
- data/lib/graphql/execution/interpreter.rb +122 -80
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +125 -54
- data/lib/graphql/execution/multiplex.rb +4 -172
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +5 -3
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +11 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +3 -3
- data/lib/graphql/introspection/input_value_type.rb +10 -4
- data/lib/graphql/introspection/schema_type.rb +12 -5
- data/lib/graphql/introspection/type_type.rb +25 -12
- data/lib/graphql/introspection.rb +6 -2
- data/lib/graphql/language/block_string.rb +37 -25
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +78 -65
- data/lib/graphql/language/lexer.rb +345 -1467
- data/lib/graphql/language/nodes.rb +145 -91
- data/lib/graphql/language/parser.rb +701 -1921
- data/lib/graphql/language/printer.rb +351 -155
- data/lib/graphql/language/sanitized_printer.rb +25 -27
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/token.rb +0 -4
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +22 -23
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +60 -28
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +109 -189
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +14 -29
- data/lib/graphql/query/validation_pipeline.rb +15 -39
- data/lib/graphql/query/variable_validation_error.rb +2 -2
- data/lib/graphql/query/variables.rb +35 -17
- data/lib/graphql/query.rb +78 -65
- data/lib/graphql/railtie.rb +8 -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 -16
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop.rb +4 -0
- data/lib/graphql/schema/addition.rb +78 -45
- data/lib/graphql/schema/always_visible.rb +10 -0
- data/lib/graphql/schema/argument.rb +134 -80
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +60 -38
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +2 -2
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +2 -2
- data/lib/graphql/schema/directive.rb +33 -21
- data/lib/graphql/schema/enum.rb +93 -46
- data/lib/graphql/schema/enum_value.rb +4 -21
- 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 +432 -337
- data/lib/graphql/schema/field_extension.rb +86 -2
- data/lib/graphql/schema/find_inherited_value.rb +3 -7
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/has_single_input_argument.rb +156 -0
- data/lib/graphql/schema/input_object.rb +88 -90
- data/lib/graphql/schema/interface.rb +19 -59
- data/lib/graphql/schema/introspection_system.rb +6 -9
- data/lib/graphql/schema/late_bound_type.rb +8 -2
- data/lib/graphql/schema/list.rb +18 -7
- data/lib/graphql/schema/loader.rb +3 -3
- data/lib/graphql/schema/member/base_dsl_methods.rb +18 -19
- data/lib/graphql/schema/member/build_type.rb +16 -13
- data/lib/graphql/schema/member/has_arguments.rb +288 -84
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +149 -31
- data/lib/graphql/schema/member/has_interfaces.rb +143 -0
- 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 +17 -0
- data/lib/graphql/schema/member/validates_input.rb +6 -6
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +0 -9
- data/lib/graphql/schema/non_null.rb +7 -7
- data/lib/graphql/schema/object.rb +30 -119
- data/lib/graphql/schema/printer.rb +23 -25
- data/lib/graphql/schema/relay_classic_mutation.rb +13 -90
- data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
- data/lib/graphql/schema/resolver.rb +101 -102
- data/lib/graphql/schema/scalar.rb +20 -21
- data/lib/graphql/schema/subscription.rb +45 -17
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +1 -1
- data/lib/graphql/schema/type_membership.rb +21 -4
- data/lib/graphql/schema/union.rb +15 -15
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -5
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
- data/lib/graphql/schema/validator/required_validator.rb +29 -15
- data/lib/graphql/schema/validator.rb +35 -27
- data/lib/graphql/schema/warden.rb +259 -132
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +658 -989
- data/lib/graphql/static_validation/all_rules.rb +3 -1
- data/lib/graphql/static_validation/base_visitor.rb +14 -28
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +21 -4
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +1 -1
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +11 -5
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +13 -13
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +12 -4
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +54 -28
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- 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 +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -3
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -4
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +13 -7
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +13 -7
- data/lib/graphql/static_validation/validation_context.rb +16 -6
- data/lib/graphql/static_validation/validator.rb +11 -27
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +46 -9
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +38 -1
- data/lib/graphql/subscriptions/event.rb +75 -37
- data/lib/graphql/subscriptions/serialize.rb +25 -3
- data/lib/graphql/subscriptions.rb +59 -47
- data/lib/graphql/testing/helpers.rb +129 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/appoptics_trace.rb +251 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -2
- data/lib/graphql/tracing/appsignal_trace.rb +77 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +15 -0
- data/lib/graphql/tracing/data_dog_trace.rb +183 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +25 -15
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +10 -28
- data/lib/graphql/tracing/legacy_trace.rb +69 -0
- data/lib/graphql/tracing/new_relic_trace.rb +75 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/notifications_tracing.rb +59 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +46 -49
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +4 -2
- data/lib/graphql/tracing/prometheus_trace.rb +89 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +3 -3
- data/lib/graphql/tracing/scout_trace.rb +72 -0
- data/lib/graphql/tracing/sentry_trace.rb +112 -0
- data/lib/graphql/tracing/statsd_trace.rb +56 -0
- data/lib/graphql/tracing/trace.rb +76 -0
- data/lib/graphql/tracing.rb +20 -41
- data/lib/graphql/type_kinds.rb +6 -3
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/iso_8601_date.rb +17 -6
- data/lib/graphql/types/iso_8601_date_time.rb +12 -1
- 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 +82 -32
- data/lib/graphql/types/relay/edge_behaviors.rb +36 -7
- data/lib/graphql/types/relay/has_node_field.rb +2 -2
- data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +7 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +2 -2
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +33 -95
- data/readme.md +13 -6
- metadata +102 -185
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/field_usage.rb +0 -45
- data/lib/graphql/analysis/max_query_complexity.rb +0 -26
- data/lib/graphql/analysis/max_query_depth.rb +0 -26
- data/lib/graphql/analysis/query_complexity.rb +0 -88
- data/lib/graphql/analysis/query_depth.rb +0 -43
- 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/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -230
- 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 -240
- 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 -47
- data/lib/graphql/deprecation.rb +0 -13
- 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 -111
- data/lib/graphql/enum_type.rb +0 -129
- 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 -262
- data/lib/graphql/language/parser.y +0 -543
- 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 -41
- 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 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- 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/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- 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/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 -27
- data/lib/graphql/types/relay/node_field.rb +0 -25
- data/lib/graphql/types/relay/nodes_field.rb +0 -27
- 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,47 +9,18 @@ module GraphQL
|
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class Runtime
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# @return [nil, Array<String>]
|
20
|
-
attr_accessor :graphql_non_null_field_names
|
21
|
-
# @return [nil, true]
|
22
|
-
attr_accessor :graphql_non_null_list_items
|
23
|
-
end
|
24
|
-
|
25
|
-
class GraphQLResultHash < Hash
|
26
|
-
include GraphQLResult
|
27
|
-
|
28
|
-
attr_accessor :graphql_merged_into
|
29
|
-
|
30
|
-
def []=(key, value)
|
31
|
-
# This is a hack.
|
32
|
-
# Basically, this object is merged into the root-level result at some point.
|
33
|
-
# But the problem is, some lazies are created whose closures retain reference to _this_
|
34
|
-
# object. When those lazies are resolved, they cause an update to this object.
|
35
|
-
#
|
36
|
-
# In order to return a proper top-level result, we have to update that top-level result object.
|
37
|
-
# In order to return a proper partial result (eg, for a directive), we have to update this object, too.
|
38
|
-
# Yowza.
|
39
|
-
if (t = @graphql_merged_into)
|
40
|
-
t[key] = value
|
41
|
-
end
|
42
|
-
super
|
12
|
+
class CurrentState
|
13
|
+
def initialize
|
14
|
+
@current_object = nil
|
15
|
+
@current_field = nil
|
16
|
+
@current_arguments = nil
|
17
|
+
@current_result_name = nil
|
18
|
+
@current_result = nil
|
19
|
+
@was_authorized_by_scope_items = nil
|
43
20
|
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class GraphQLResultArray < Array
|
47
|
-
include GraphQLResult
|
48
|
-
end
|
49
21
|
|
50
|
-
|
51
|
-
|
22
|
+
attr_accessor :current_result, :current_result_name,
|
23
|
+
:current_arguments, :current_field, :current_object, :was_authorized_by_scope_items
|
52
24
|
end
|
53
25
|
|
54
26
|
# @return [GraphQL::Query]
|
@@ -60,31 +32,30 @@ module GraphQL
|
|
60
32
|
# @return [GraphQL::Query::Context]
|
61
33
|
attr_reader :context
|
62
34
|
|
63
|
-
|
64
|
-
attr_reader :response
|
65
|
-
|
66
|
-
def initialize(query:)
|
35
|
+
def initialize(query:, lazies_at_depth:)
|
67
36
|
@query = query
|
37
|
+
@current_trace = query.current_trace
|
68
38
|
@dataloader = query.multiplex.dataloader
|
39
|
+
@lazies_at_depth = lazies_at_depth
|
69
40
|
@schema = query.schema
|
70
41
|
@context = query.context
|
71
|
-
@
|
72
|
-
@interpreter_context = @context.namespace(:interpreter)
|
73
|
-
@response = GraphQLResultHash.new
|
42
|
+
@response = GraphQLResultHash.new(nil, nil, false)
|
74
43
|
# Identify runtime directives by checking which of this schema's directives have overridden `def self.resolve`
|
75
44
|
@runtime_directive_names = []
|
76
45
|
noop_resolve_owner = GraphQL::Schema::Directive.singleton_class
|
77
|
-
schema.directives
|
46
|
+
@schema_directives = schema.directives
|
47
|
+
@schema_directives.each do |name, dir_defn|
|
78
48
|
if dir_defn.method(:resolve).owner != noop_resolve_owner
|
79
49
|
@runtime_directive_names << name
|
80
50
|
end
|
81
51
|
end
|
82
|
-
# A cache of { Class => { String => Schema::Field } }
|
83
|
-
# Which assumes that MyObject.get_field("myField") will return the same field
|
84
|
-
# during the lifetime of a query
|
85
|
-
@fields_cache = Hash.new { |h, k| h[k] = {} }
|
86
52
|
# { Class => Boolean }
|
87
53
|
@lazy_cache = {}
|
54
|
+
@lazy_cache.compare_by_identity
|
55
|
+
end
|
56
|
+
|
57
|
+
def final_result
|
58
|
+
@response && @response.graphql_result_data
|
88
59
|
end
|
89
60
|
|
90
61
|
def inspect
|
@@ -108,17 +79,19 @@ module GraphQL
|
|
108
79
|
root_operation = query.selected_operation
|
109
80
|
root_op_type = root_operation.operation_type || "query"
|
110
81
|
root_type = schema.root_type_for_operation(root_op_type)
|
111
|
-
path = []
|
112
|
-
set_all_interpreter_context(query.root_value, nil, nil, path)
|
113
|
-
object_proxy = authorized_new(root_type, query.root_value, context)
|
114
|
-
object_proxy = schema.sync_lazy(object_proxy)
|
115
82
|
|
116
|
-
|
83
|
+
st = get_current_runtime_state
|
84
|
+
st.current_object = query.root_value
|
85
|
+
st.current_result = @response
|
86
|
+
runtime_object = root_type.wrap(query.root_value, context)
|
87
|
+
runtime_object = schema.sync_lazy(runtime_object)
|
88
|
+
|
89
|
+
if runtime_object.nil?
|
117
90
|
# Root .authorized? returned false.
|
118
91
|
@response = nil
|
119
92
|
else
|
120
|
-
|
121
|
-
gathered_selections = gather_selections(
|
93
|
+
call_method_on_directives(:resolve, runtime_object, root_operation.directives) do # execute query level directives
|
94
|
+
gathered_selections = gather_selections(runtime_object, root_type, root_operation.selections)
|
122
95
|
# This is kind of a hack -- `gathered_selections` is an Array if any of the selections
|
123
96
|
# require isolation during execution (because of runtime directives). In that case,
|
124
97
|
# make a new, isolated result hash for writing the result into. (That isolated response
|
@@ -128,7 +101,7 @@ module GraphQL
|
|
128
101
|
# directly evaluated and the results can be written right into the main response hash.
|
129
102
|
tap_or_each(gathered_selections) do |selections, is_selection_array|
|
130
103
|
if is_selection_array
|
131
|
-
selection_response = GraphQLResultHash.new
|
104
|
+
selection_response = GraphQLResultHash.new(nil, nil, false)
|
132
105
|
final_response = @response
|
133
106
|
else
|
134
107
|
selection_response = @response
|
@@ -136,53 +109,35 @@ module GraphQL
|
|
136
109
|
end
|
137
110
|
|
138
111
|
@dataloader.append_job {
|
139
|
-
|
140
|
-
|
112
|
+
st = get_current_runtime_state
|
113
|
+
st.current_object = query.root_value
|
114
|
+
st.current_result_name = nil
|
115
|
+
st.current_result = selection_response
|
116
|
+
# This is a less-frequent case; use a fast check since it's often not there.
|
117
|
+
if (directives = selections[:graphql_directives])
|
118
|
+
selections.delete(:graphql_directives)
|
119
|
+
end
|
120
|
+
call_method_on_directives(:resolve, runtime_object, directives) do
|
141
121
|
evaluate_selections(
|
142
|
-
|
143
|
-
context.scoped_context,
|
144
|
-
object_proxy,
|
122
|
+
runtime_object,
|
145
123
|
root_type,
|
146
124
|
root_op_type == "mutation",
|
147
125
|
selections,
|
148
126
|
selection_response,
|
149
127
|
final_response,
|
128
|
+
nil,
|
129
|
+
st,
|
150
130
|
)
|
151
131
|
end
|
152
132
|
}
|
153
133
|
end
|
154
134
|
end
|
155
135
|
end
|
156
|
-
delete_interpreter_context(:current_path)
|
157
|
-
delete_interpreter_context(:current_field)
|
158
|
-
delete_interpreter_context(:current_object)
|
159
|
-
delete_interpreter_context(:current_arguments)
|
160
136
|
nil
|
161
137
|
end
|
162
138
|
|
163
|
-
|
164
|
-
def deep_merge_selection_result(from_result, into_result)
|
165
|
-
from_result.each do |key, value|
|
166
|
-
if !into_result.key?(key)
|
167
|
-
into_result[key] = value
|
168
|
-
else
|
169
|
-
case value
|
170
|
-
when Hash
|
171
|
-
deep_merge_selection_result(value, into_result[key])
|
172
|
-
else
|
173
|
-
# We have to assume that, since this passed the `fields_will_merge` selection,
|
174
|
-
# that the old and new values are the same.
|
175
|
-
# There's no special handling of arrays because currently, there's no way to split the execution
|
176
|
-
# of a list over several concurrent flows.
|
177
|
-
into_result[key] = value
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
from_result.graphql_merged_into = into_result
|
182
|
-
nil
|
183
|
-
end
|
139
|
+
def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = {})
|
184
140
|
|
185
|
-
def gather_selections(owner_object, owner_type, selections, selections_to_run = nil, selections_by_name = GraphQLSelectionSet.new)
|
186
141
|
selections.each do |node|
|
187
142
|
# Skip gathering this if the directive says so
|
188
143
|
if !directives_include?(node, owner_object, owner_type)
|
@@ -208,8 +163,8 @@ module GraphQL
|
|
208
163
|
else
|
209
164
|
# This is an InlineFragment or a FragmentSpread
|
210
165
|
if @runtime_directive_names.any? && node.directives.any? { |d| @runtime_directive_names.include?(d.name) }
|
211
|
-
next_selections =
|
212
|
-
next_selections
|
166
|
+
next_selections = {}
|
167
|
+
next_selections[:graphql_directives] = node.directives
|
213
168
|
if selections_to_run
|
214
169
|
selections_to_run << next_selections
|
215
170
|
else
|
@@ -224,14 +179,10 @@ module GraphQL
|
|
224
179
|
case node
|
225
180
|
when GraphQL::Language::Nodes::InlineFragment
|
226
181
|
if node.type
|
227
|
-
type_defn = schema.get_type(node.type.name)
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
if t == owner_type
|
232
|
-
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
233
|
-
break
|
234
|
-
end
|
182
|
+
type_defn = schema.get_type(node.type.name, context)
|
183
|
+
|
184
|
+
if query.warden.possible_types(type_defn).include?(owner_type)
|
185
|
+
gather_selections(owner_object, owner_type, node.selections, selections_to_run, next_selections)
|
235
186
|
end
|
236
187
|
else
|
237
188
|
# it's an untyped fragment, definitely continue
|
@@ -239,13 +190,9 @@ module GraphQL
|
|
239
190
|
end
|
240
191
|
when GraphQL::Language::Nodes::FragmentSpread
|
241
192
|
fragment_def = query.fragments[node.name]
|
242
|
-
type_defn =
|
243
|
-
|
244
|
-
|
245
|
-
if t == owner_type
|
246
|
-
gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
|
247
|
-
break
|
248
|
-
end
|
193
|
+
type_defn = query.get_type(fragment_def.type.name)
|
194
|
+
if query.warden.possible_types(type_defn).include?(owner_type)
|
195
|
+
gather_selections(owner_object, owner_type, fragment_def.selections, selections_to_run, next_selections)
|
249
196
|
end
|
250
197
|
else
|
251
198
|
raise "Invariant: unexpected selection class: #{node.class}"
|
@@ -255,33 +202,39 @@ module GraphQL
|
|
255
202
|
selections_to_run || selections_by_name
|
256
203
|
end
|
257
204
|
|
258
|
-
NO_ARGS =
|
205
|
+
NO_ARGS = GraphQL::EmptyObjects::EMPTY_HASH
|
259
206
|
|
260
207
|
# @return [void]
|
261
|
-
def evaluate_selections(
|
262
|
-
set_all_interpreter_context(owner_object, nil, nil, path)
|
263
|
-
|
208
|
+
def evaluate_selections(owner_object, owner_type, is_eager_selection, gathered_selections, selections_result, target_result, parent_object, runtime_state) # rubocop:disable Metrics/ParameterLists
|
264
209
|
finished_jobs = 0
|
265
210
|
enqueued_jobs = gathered_selections.size
|
266
211
|
gathered_selections.each do |result_name, field_ast_nodes_or_ast_node|
|
267
212
|
@dataloader.append_job {
|
213
|
+
runtime_state = get_current_runtime_state
|
268
214
|
evaluate_selection(
|
269
|
-
|
215
|
+
result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_selection, selections_result, parent_object, runtime_state
|
270
216
|
)
|
271
217
|
finished_jobs += 1
|
272
218
|
if target_result && finished_jobs == enqueued_jobs
|
273
|
-
|
219
|
+
selections_result.merge_into(target_result)
|
274
220
|
end
|
275
221
|
}
|
222
|
+
# Field resolution may pause the fiber,
|
223
|
+
# so it wouldn't get to the `Resolve` call that happens below.
|
224
|
+
# So instead trigger a run from this outer context.
|
225
|
+
if is_eager_selection
|
226
|
+
@dataloader.clear_cache
|
227
|
+
@dataloader.run
|
228
|
+
@dataloader.clear_cache
|
229
|
+
end
|
276
230
|
end
|
277
231
|
|
278
232
|
selections_result
|
279
233
|
end
|
280
234
|
|
281
|
-
attr_reader :progress_path
|
282
|
-
|
283
235
|
# @return [void]
|
284
|
-
def evaluate_selection(
|
236
|
+
def evaluate_selection(result_name, field_ast_nodes_or_ast_node, owner_object, owner_type, is_eager_field, selections_result, parent_object, runtime_state) # rubocop:disable Metrics/ParameterLists
|
237
|
+
return if dead_result?(selections_result)
|
285
238
|
# As a performance optimization, the hash key will be a `Node` if
|
286
239
|
# there's only one selection of the field. But if there are multiple
|
287
240
|
# selections of the field, it will be an Array of nodes
|
@@ -293,65 +246,50 @@ module GraphQL
|
|
293
246
|
ast_node = field_ast_nodes_or_ast_node
|
294
247
|
end
|
295
248
|
field_name = ast_node.name
|
296
|
-
field_defn =
|
297
|
-
is_introspection = false
|
298
|
-
if field_defn.nil?
|
299
|
-
field_defn = if owner_type == schema.query && (entry_point_field = schema.introspection_system.entry_point(name: field_name))
|
300
|
-
is_introspection = true
|
301
|
-
entry_point_field
|
302
|
-
elsif (dynamic_field = schema.introspection_system.dynamic_field(name: field_name))
|
303
|
-
is_introspection = true
|
304
|
-
dynamic_field
|
305
|
-
else
|
306
|
-
raise "Invariant: no field for #{owner_type}.#{field_name}"
|
307
|
-
end
|
308
|
-
end
|
309
|
-
return_type = field_defn.type
|
310
|
-
|
311
|
-
next_path = path.dup
|
312
|
-
next_path << result_name
|
313
|
-
next_path.freeze
|
249
|
+
field_defn = query.warden.get_field(owner_type, field_name)
|
314
250
|
|
315
|
-
# This seems janky, but we need to know
|
316
|
-
# the field's return type at this path in order
|
317
|
-
# to propagate `null`
|
318
|
-
if return_type.non_null?
|
319
|
-
(selections_result.graphql_non_null_field_names ||= []).push(result_name)
|
320
|
-
end
|
321
251
|
# Set this before calling `run_with_directives`, so that the directive can have the latest path
|
322
|
-
|
252
|
+
runtime_state.current_field = field_defn
|
253
|
+
runtime_state.current_result = selections_result
|
254
|
+
runtime_state.current_result_name = result_name
|
323
255
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
if is_introspection
|
328
|
-
object = authorized_new(field_defn.owner, object, context)
|
256
|
+
if field_defn.dynamic_introspection
|
257
|
+
owner_object = field_defn.owner.wrap(owner_object, context)
|
329
258
|
end
|
330
259
|
|
331
|
-
|
332
|
-
if
|
333
|
-
|
334
|
-
|
260
|
+
return_type = field_defn.type
|
261
|
+
if !field_defn.any_arguments?
|
262
|
+
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
|
263
|
+
if field_defn.extras.size == 0
|
264
|
+
evaluate_selection_with_resolved_keyword_args(
|
265
|
+
NO_ARGS, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, return_type.non_null?, runtime_state
|
266
|
+
)
|
267
|
+
else
|
268
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, runtime_state)
|
269
|
+
end
|
335
270
|
else
|
336
|
-
|
337
|
-
|
338
|
-
evaluate_selection_with_args(resolved_arguments, field_defn,
|
271
|
+
@query.arguments_cache.dataload_for(ast_node, field_defn, owner_object) do |resolved_arguments|
|
272
|
+
runtime_state = get_current_runtime_state # This might be in a different fiber
|
273
|
+
evaluate_selection_with_args(resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, owner_object, is_eager_field, result_name, selections_result, parent_object, return_type, runtime_state)
|
339
274
|
end
|
340
275
|
end
|
341
276
|
end
|
342
277
|
|
343
|
-
def evaluate_selection_with_args(
|
344
|
-
|
345
|
-
|
346
|
-
after_lazy(kwarg_arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, scoped_context: context.scoped_context, owner_object: object, arguments: kwarg_arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
|
278
|
+
def evaluate_selection_with_args(arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type, runtime_state) # rubocop:disable Metrics/ParameterLists
|
279
|
+
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|
|
280
|
+
return_type_non_null = return_type.non_null?
|
347
281
|
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
|
348
|
-
continue_value(
|
282
|
+
continue_value(resolved_arguments, owner_type, field_defn, return_type_non_null, ast_node, result_name, selection_result)
|
349
283
|
next
|
350
284
|
end
|
351
285
|
|
352
|
-
kwarg_arguments = if
|
353
|
-
|
354
|
-
|
286
|
+
kwarg_arguments = if field_defn.extras.empty?
|
287
|
+
if resolved_arguments.empty?
|
288
|
+
# We can avoid allocating the `{ Symbol => Object }` hash in this case
|
289
|
+
NO_ARGS
|
290
|
+
else
|
291
|
+
resolved_arguments.keyword_arguments
|
292
|
+
end
|
355
293
|
else
|
356
294
|
# Bundle up the extras, then make a new arguments instance
|
357
295
|
# that includes the extras, too.
|
@@ -361,9 +299,9 @@ module GraphQL
|
|
361
299
|
when :ast_node
|
362
300
|
extra_args[:ast_node] = ast_node
|
363
301
|
when :execution_errors
|
364
|
-
extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node,
|
302
|
+
extra_args[:execution_errors] = ExecutionErrors.new(context, ast_node, current_path)
|
365
303
|
when :path
|
366
|
-
extra_args[:path] =
|
304
|
+
extra_args[:path] = current_path
|
367
305
|
when :lookahead
|
368
306
|
if !field_ast_nodes
|
369
307
|
field_ast_nodes = [ast_node]
|
@@ -378,10 +316,8 @@ module GraphQL
|
|
378
316
|
# Use this flag to tell Interpreter::Arguments to add itself
|
379
317
|
# to the keyword args hash _before_ freezing everything.
|
380
318
|
extra_args[:argument_details] = :__arguments_add_self
|
381
|
-
when :
|
382
|
-
|
383
|
-
# but it has no use here (and it's always `nil`).
|
384
|
-
# Stop adding it here to avoid the overhead of `.merge_extras` below.
|
319
|
+
when :parent
|
320
|
+
extra_args[:parent] = parent_object
|
385
321
|
else
|
386
322
|
extra_args[extra] = field_defn.fetch_extra(extra, context)
|
387
323
|
end
|
@@ -392,71 +328,82 @@ module GraphQL
|
|
392
328
|
resolved_arguments.keyword_arguments
|
393
329
|
end
|
394
330
|
|
395
|
-
|
331
|
+
evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type, return_type_non_null, runtime_state)
|
332
|
+
end
|
333
|
+
end
|
396
334
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
335
|
+
def evaluate_selection_with_resolved_keyword_args(kwarg_arguments, resolved_arguments, field_defn, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type, return_type_non_null, runtime_state) # rubocop:disable Metrics/ParameterLists
|
336
|
+
runtime_state.current_field = field_defn
|
337
|
+
runtime_state.current_object = object
|
338
|
+
runtime_state.current_arguments = resolved_arguments
|
339
|
+
runtime_state.current_result_name = result_name
|
340
|
+
runtime_state.current_result = selection_result
|
341
|
+
# Optimize for the case that field is selected only once
|
342
|
+
if field_ast_nodes.nil? || field_ast_nodes.size == 1
|
343
|
+
next_selections = ast_node.selections
|
344
|
+
directives = ast_node.directives
|
345
|
+
else
|
346
|
+
next_selections = []
|
347
|
+
directives = []
|
348
|
+
field_ast_nodes.each { |f|
|
349
|
+
next_selections.concat(f.selections)
|
350
|
+
directives.concat(f.directives)
|
351
|
+
}
|
352
|
+
end
|
409
353
|
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
354
|
+
field_result = call_method_on_directives(:resolve, object, directives) do
|
355
|
+
if directives.any?
|
356
|
+
# This might be executed in a different context; reset this info
|
357
|
+
runtime_state = get_current_runtime_state
|
358
|
+
runtime_state.current_field = field_defn
|
359
|
+
runtime_state.current_object = object
|
360
|
+
runtime_state.current_arguments = resolved_arguments
|
361
|
+
runtime_state.current_result_name = result_name
|
362
|
+
runtime_state.current_result = selection_result
|
363
|
+
end
|
364
|
+
# Actually call the field resolver and capture the result
|
365
|
+
app_result = begin
|
366
|
+
@current_trace.execute_field(field: field_defn, ast_node: ast_node, query: query, object: object, arguments: kwarg_arguments) do
|
367
|
+
field_defn.resolve(object, kwarg_arguments, context)
|
420
368
|
end
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
369
|
+
rescue GraphQL::ExecutionError => err
|
370
|
+
err
|
371
|
+
rescue StandardError => err
|
372
|
+
begin
|
373
|
+
query.handle_or_reraise(err)
|
374
|
+
rescue GraphQL::ExecutionError => ex_err
|
375
|
+
ex_err
|
426
376
|
end
|
427
377
|
end
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
# Return this from `after_lazy` because it might be another lazy that needs to be resolved
|
436
|
-
field_result
|
378
|
+
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|
|
379
|
+
continue_value = continue_value(inner_result, owner_type, field_defn, return_type_non_null, ast_node, result_name, selection_result)
|
380
|
+
if HALT != continue_value
|
381
|
+
was_scoped = runtime_state.was_authorized_by_scope_items
|
382
|
+
runtime_state.was_authorized_by_scope_items = nil
|
383
|
+
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)
|
384
|
+
end
|
437
385
|
end
|
438
386
|
end
|
387
|
+
|
388
|
+
# If this field is a root mutation field, immediately resolve
|
389
|
+
# all of its child fields before moving on to the next root mutation field.
|
390
|
+
# (Subselections of this mutation will still be resolved level-by-level.)
|
391
|
+
if is_eager_field
|
392
|
+
Interpreter::Resolve.resolve_all([field_result], @dataloader)
|
393
|
+
else
|
394
|
+
# Return this from `after_lazy` because it might be another lazy that needs to be resolved
|
395
|
+
field_result
|
396
|
+
end
|
439
397
|
end
|
440
398
|
|
399
|
+
|
441
400
|
def dead_result?(selection_result)
|
442
|
-
|
443
|
-
while r
|
444
|
-
if r.graphql_dead
|
445
|
-
return true
|
446
|
-
else
|
447
|
-
r = r.graphql_parent
|
448
|
-
end
|
449
|
-
end
|
450
|
-
false
|
401
|
+
selection_result.graphql_dead # || ((parent = selection_result.graphql_parent) && parent.graphql_dead)
|
451
402
|
end
|
452
403
|
|
453
|
-
def set_result(selection_result, result_name, value)
|
404
|
+
def set_result(selection_result, result_name, value, is_child_result, is_non_null)
|
454
405
|
if !dead_result?(selection_result)
|
455
|
-
if value.nil? &&
|
456
|
-
( # there are two conditions under which `nil` is not allowed in the response:
|
457
|
-
(selection_result.graphql_non_null_list_items) || # this value would be written into a list that doesn't allow nils
|
458
|
-
((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
|
459
|
-
)
|
406
|
+
if value.nil? && is_non_null
|
460
407
|
# This is an invalid nil that should be propagated
|
461
408
|
# One caller of this method passes a block,
|
462
409
|
# namely when application code returns a `nil` to GraphQL and it doesn't belong there.
|
@@ -466,33 +413,60 @@ module GraphQL
|
|
466
413
|
# TODO the code is trying to tell me something.
|
467
414
|
yield if block_given?
|
468
415
|
parent = selection_result.graphql_parent
|
469
|
-
name_in_parent = selection_result.graphql_result_name
|
470
416
|
if parent.nil? # This is a top-level result hash
|
471
417
|
@response = nil
|
472
418
|
else
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
419
|
+
name_in_parent = selection_result.graphql_result_name
|
420
|
+
is_non_null_in_parent = selection_result.graphql_is_non_null_in_parent
|
421
|
+
set_result(parent, name_in_parent, nil, false, is_non_null_in_parent)
|
422
|
+
set_graphql_dead(selection_result)
|
477
423
|
end
|
424
|
+
elsif is_child_result
|
425
|
+
selection_result.set_child_result(result_name, value)
|
478
426
|
else
|
479
|
-
selection_result
|
427
|
+
selection_result.set_leaf(result_name, value)
|
480
428
|
end
|
481
429
|
end
|
482
430
|
end
|
483
431
|
|
432
|
+
# Mark this node and any already-registered children as dead,
|
433
|
+
# so that it accepts no more writes.
|
434
|
+
def set_graphql_dead(selection_result)
|
435
|
+
case selection_result
|
436
|
+
when GraphQLResultArray
|
437
|
+
selection_result.graphql_dead = true
|
438
|
+
selection_result.values.each { |v| set_graphql_dead(v) }
|
439
|
+
when GraphQLResultHash
|
440
|
+
selection_result.graphql_dead = true
|
441
|
+
selection_result.each { |k, v| set_graphql_dead(v) }
|
442
|
+
else
|
443
|
+
# It's a scalar, no way to mark it dead.
|
444
|
+
end
|
445
|
+
end
|
446
|
+
|
447
|
+
def current_path
|
448
|
+
st = get_current_runtime_state
|
449
|
+
result = st.current_result
|
450
|
+
path = result && result.path
|
451
|
+
if path && (rn = st.current_result_name)
|
452
|
+
path = path.dup
|
453
|
+
path.push(rn)
|
454
|
+
end
|
455
|
+
path
|
456
|
+
end
|
457
|
+
|
484
458
|
HALT = Object.new
|
485
|
-
def continue_value(
|
459
|
+
def continue_value(value, parent_type, field, is_non_null, ast_node, result_name, selection_result) # rubocop:disable Metrics/ParameterLists
|
486
460
|
case value
|
487
461
|
when nil
|
488
462
|
if is_non_null
|
489
|
-
set_result(selection_result, result_name, nil) do
|
463
|
+
set_result(selection_result, result_name, nil, false, is_non_null) do
|
490
464
|
# This block is called if `result_name` is not dead. (Maybe a previous invalid nil caused it be marked dead.)
|
491
465
|
err = parent_type::InvalidNullError.new(parent_type, field, value)
|
492
466
|
schema.type_error(err, context)
|
493
467
|
end
|
494
468
|
else
|
495
|
-
set_result(selection_result, result_name, nil)
|
469
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
496
470
|
end
|
497
471
|
HALT
|
498
472
|
when GraphQL::Error
|
@@ -500,13 +474,25 @@ module GraphQL
|
|
500
474
|
# to avoid the overhead of checking three different classes
|
501
475
|
# every time.
|
502
476
|
if value.is_a?(GraphQL::ExecutionError)
|
503
|
-
if !dead_result?(selection_result)
|
504
|
-
value.path ||=
|
477
|
+
if selection_result.nil? || !dead_result?(selection_result)
|
478
|
+
value.path ||= current_path
|
505
479
|
value.ast_node ||= ast_node
|
506
480
|
context.errors << value
|
507
|
-
|
481
|
+
if selection_result
|
482
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
483
|
+
end
|
508
484
|
end
|
509
485
|
HALT
|
486
|
+
elsif value.is_a?(GraphQL::UnauthorizedFieldError)
|
487
|
+
value.field ||= field
|
488
|
+
# this hook might raise & crash, or it might return
|
489
|
+
# a replacement value
|
490
|
+
next_value = begin
|
491
|
+
schema.unauthorized_field(value)
|
492
|
+
rescue GraphQL::ExecutionError => err
|
493
|
+
err
|
494
|
+
end
|
495
|
+
continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
|
510
496
|
elsif value.is_a?(GraphQL::UnauthorizedError)
|
511
497
|
# this hook might raise & crash, or it might return
|
512
498
|
# a replacement value
|
@@ -515,8 +501,19 @@ module GraphQL
|
|
515
501
|
rescue GraphQL::ExecutionError => err
|
516
502
|
err
|
517
503
|
end
|
518
|
-
continue_value(
|
519
|
-
elsif GraphQL::Execution::
|
504
|
+
continue_value(next_value, parent_type, field, is_non_null, ast_node, result_name, selection_result)
|
505
|
+
elsif GraphQL::Execution::SKIP == value
|
506
|
+
# It's possible a lazy was already written here
|
507
|
+
case selection_result
|
508
|
+
when GraphQLResultHash
|
509
|
+
selection_result.delete(result_name)
|
510
|
+
when GraphQLResultArray
|
511
|
+
selection_result.graphql_skip_at(result_name)
|
512
|
+
when nil
|
513
|
+
# this can happen with directives
|
514
|
+
else
|
515
|
+
raise "Invariant: unexpected result class #{selection_result.class} (#{selection_result.inspect})"
|
516
|
+
end
|
520
517
|
HALT
|
521
518
|
else
|
522
519
|
# What could this actually _be_? Anyhow,
|
@@ -525,14 +522,22 @@ module GraphQL
|
|
525
522
|
end
|
526
523
|
when Array
|
527
524
|
# It's an array full of execution errors; add them all.
|
528
|
-
if value.any? && value.all?
|
529
|
-
|
525
|
+
if value.any? && value.all?(GraphQL::ExecutionError)
|
526
|
+
list_type_at_all = (field && (field.type.list?))
|
527
|
+
if selection_result.nil? || !dead_result?(selection_result)
|
530
528
|
value.each_with_index do |error, index|
|
531
529
|
error.ast_node ||= ast_node
|
532
|
-
error.path ||=
|
530
|
+
error.path ||= current_path + (list_type_at_all ? [index] : [])
|
533
531
|
context.errors << error
|
534
532
|
end
|
535
|
-
|
533
|
+
if selection_result
|
534
|
+
if list_type_at_all
|
535
|
+
result_without_errors = value.map { |v| v.is_a?(GraphQL::ExecutionError) ? nil : v }
|
536
|
+
set_result(selection_result, result_name, result_without_errors, false, is_non_null)
|
537
|
+
else
|
538
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
539
|
+
end
|
540
|
+
end
|
536
541
|
end
|
537
542
|
HALT
|
538
543
|
else
|
@@ -540,7 +545,7 @@ module GraphQL
|
|
540
545
|
end
|
541
546
|
when GraphQL::Execution::Interpreter::RawValue
|
542
547
|
# Write raw value directly to the response without resolving nested objects
|
543
|
-
set_result(selection_result, result_name, value.resolve)
|
548
|
+
set_result(selection_result, result_name, value.resolve, false, is_non_null)
|
544
549
|
HALT
|
545
550
|
else
|
546
551
|
value
|
@@ -555,7 +560,7 @@ module GraphQL
|
|
555
560
|
# Location information from `path` and `ast_node`.
|
556
561
|
#
|
557
562
|
# @return [Lazy, Array, Hash, Object] Lazy, Array, and Hash are all traversed to resolve lazy values later
|
558
|
-
def continue_field(
|
563
|
+
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
|
559
564
|
if current_type.non_null?
|
560
565
|
current_type = current_type.of_type
|
561
566
|
is_non_null = true
|
@@ -563,40 +568,47 @@ module GraphQL
|
|
563
568
|
|
564
569
|
case current_type.kind.name
|
565
570
|
when "SCALAR", "ENUM"
|
566
|
-
r =
|
567
|
-
|
571
|
+
r = begin
|
572
|
+
current_type.coerce_result(value, context)
|
573
|
+
rescue StandardError => err
|
574
|
+
schema.handle_or_reraise(context, err)
|
575
|
+
end
|
576
|
+
set_result(selection_result, result_name, r, false, is_non_null)
|
568
577
|
r
|
569
578
|
when "UNION", "INTERFACE"
|
570
|
-
resolved_type_or_lazy
|
571
|
-
|
579
|
+
resolved_type_or_lazy = resolve_type(current_type, value)
|
580
|
+
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|
|
581
|
+
if resolved_type_result.is_a?(Array) && resolved_type_result.length == 2
|
582
|
+
resolved_type, resolved_value = resolved_type_result
|
583
|
+
else
|
584
|
+
resolved_type = resolved_type_result
|
585
|
+
resolved_value = value
|
586
|
+
end
|
572
587
|
|
573
|
-
after_lazy(resolved_type_or_lazy, owner: current_type, path: path, ast_node: ast_node, scoped_context: context.scoped_context, field: field, owner_object: owner_object, arguments: arguments, trace: false, result_name: result_name, result: selection_result) do |resolved_type|
|
574
588
|
possible_types = query.possible_types(current_type)
|
575
|
-
|
576
589
|
if !possible_types.include?(resolved_type)
|
577
590
|
parent_type = field.owner_type
|
578
591
|
err_class = current_type::UnresolvedTypeError
|
579
592
|
type_error = err_class.new(resolved_value, field, parent_type, resolved_type, possible_types)
|
580
593
|
schema.type_error(type_error, context)
|
581
|
-
set_result(selection_result, result_name, nil)
|
594
|
+
set_result(selection_result, result_name, nil, false, is_non_null)
|
582
595
|
nil
|
583
596
|
else
|
584
|
-
continue_field(
|
597
|
+
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)
|
585
598
|
end
|
586
599
|
end
|
587
600
|
when "OBJECT"
|
588
601
|
object_proxy = begin
|
589
|
-
|
602
|
+
was_scoped ? current_type.wrap_scoped(value, context) : current_type.wrap(value, context)
|
590
603
|
rescue GraphQL::ExecutionError => err
|
591
604
|
err
|
592
605
|
end
|
593
|
-
after_lazy(object_proxy,
|
594
|
-
continue_value = continue_value(
|
606
|
+
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|
|
607
|
+
continue_value = continue_value(inner_object, owner_type, field, is_non_null, ast_node, result_name, selection_result)
|
595
608
|
if HALT != continue_value
|
596
|
-
response_hash = GraphQLResultHash.new
|
597
|
-
response_hash
|
598
|
-
|
599
|
-
set_result(selection_result, result_name, response_hash)
|
609
|
+
response_hash = GraphQLResultHash.new(result_name, selection_result, is_non_null)
|
610
|
+
set_result(selection_result, result_name, response_hash, true, is_non_null)
|
611
|
+
|
600
612
|
gathered_selections = gather_selections(continue_value, current_type, next_selections)
|
601
613
|
# There are two possibilities for `gathered_selections`:
|
602
614
|
# 1. All selections of this object should be evaluated together (there are no runtime directives modifying execution).
|
@@ -608,25 +620,31 @@ module GraphQL
|
|
608
620
|
# (Technically, it's possible that one of those entries _doesn't_ require isolation.)
|
609
621
|
tap_or_each(gathered_selections) do |selections, is_selection_array|
|
610
622
|
if is_selection_array
|
611
|
-
this_result = GraphQLResultHash.new
|
612
|
-
this_result.graphql_parent = selection_result
|
613
|
-
this_result.graphql_result_name = result_name
|
623
|
+
this_result = GraphQLResultHash.new(result_name, selection_result, is_non_null)
|
614
624
|
final_result = response_hash
|
615
625
|
else
|
616
626
|
this_result = response_hash
|
617
627
|
final_result = nil
|
618
628
|
end
|
619
|
-
|
620
|
-
|
629
|
+
# reset this mutable state
|
630
|
+
# Unset `result_name` here because it's already included in the new response hash
|
631
|
+
runtime_state.current_object = continue_value
|
632
|
+
runtime_state.current_result_name = nil
|
633
|
+
runtime_state.current_result = this_result
|
634
|
+
# This is a less-frequent case; use a fast check since it's often not there.
|
635
|
+
if (directives = selections[:graphql_directives])
|
636
|
+
selections.delete(:graphql_directives)
|
637
|
+
end
|
638
|
+
call_method_on_directives(:resolve, continue_value, directives) do
|
621
639
|
evaluate_selections(
|
622
|
-
path,
|
623
|
-
context.scoped_context,
|
624
640
|
continue_value,
|
625
641
|
current_type,
|
626
642
|
false,
|
627
643
|
selections,
|
628
644
|
this_result,
|
629
645
|
final_result,
|
646
|
+
owner_object.object,
|
647
|
+
runtime_state,
|
630
648
|
)
|
631
649
|
this_result
|
632
650
|
end
|
@@ -635,63 +653,95 @@ module GraphQL
|
|
635
653
|
end
|
636
654
|
when "LIST"
|
637
655
|
inner_type = current_type.of_type
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
response_list
|
642
|
-
set_result(selection_result, result_name, response_list)
|
643
|
-
|
644
|
-
|
645
|
-
scoped_context = context.scoped_context
|
646
|
-
begin
|
656
|
+
# This is true for objects, unions, and interfaces
|
657
|
+
use_dataloader_job = !inner_type.unwrap.kind.input?
|
658
|
+
inner_type_non_null = inner_type.non_null?
|
659
|
+
response_list = GraphQLResultArray.new(result_name, selection_result, is_non_null)
|
660
|
+
set_result(selection_result, result_name, response_list, true, is_non_null)
|
661
|
+
idx = nil
|
662
|
+
list_value = begin
|
647
663
|
value.each do |inner_value|
|
648
|
-
|
649
|
-
next_path << idx
|
664
|
+
idx ||= 0
|
650
665
|
this_idx = idx
|
651
|
-
next_path.freeze
|
652
666
|
idx += 1
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
if HALT != continue_value
|
657
|
-
continue_field(next_path, continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list)
|
667
|
+
if use_dataloader_job
|
668
|
+
@dataloader.append_job do
|
669
|
+
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type, was_scoped, runtime_state)
|
658
670
|
end
|
671
|
+
else
|
672
|
+
resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type, was_scoped, runtime_state)
|
659
673
|
end
|
660
674
|
end
|
675
|
+
|
676
|
+
response_list
|
661
677
|
rescue NoMethodError => err
|
662
678
|
# Ruby 2.2 doesn't have NoMethodError#receiver, can't check that one in this case. (It's been EOL since 2017.)
|
663
679
|
if err.name == :each && (err.respond_to?(:receiver) ? err.receiver == value : true)
|
664
680
|
# This happens when the GraphQL schema doesn't match the implementation. Help the dev debug.
|
665
|
-
raise ListResultFailedError.new(value: value, field: field, path:
|
681
|
+
raise ListResultFailedError.new(value: value, field: field, path: current_path)
|
666
682
|
else
|
667
683
|
# This was some other NoMethodError -- let it bubble to reveal the real error.
|
668
684
|
raise
|
669
685
|
end
|
686
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
687
|
+
ex_err
|
688
|
+
rescue StandardError => err
|
689
|
+
begin
|
690
|
+
query.handle_or_reraise(err)
|
691
|
+
rescue GraphQL::ExecutionError => ex_err
|
692
|
+
ex_err
|
693
|
+
end
|
670
694
|
end
|
671
|
-
|
672
|
-
|
695
|
+
# Detect whether this error came while calling `.each` (before `idx` is set) or while running list *items* (after `idx` is set)
|
696
|
+
error_is_non_null = idx.nil? ? is_non_null : inner_type.non_null?
|
697
|
+
continue_value(list_value, owner_type, field, error_is_non_null, ast_node, result_name, selection_result)
|
673
698
|
else
|
674
699
|
raise "Invariant: Unhandled type kind #{current_type.kind} (#{current_type})"
|
675
700
|
end
|
676
701
|
end
|
677
702
|
|
678
|
-
def
|
703
|
+
def resolve_list_item(inner_value, inner_type, inner_type_non_null, ast_node, field, owner_object, arguments, this_idx, response_list, next_selections, owner_type, was_scoped, runtime_state) # rubocop:disable Metrics/ParameterLists
|
704
|
+
runtime_state.current_result_name = this_idx
|
705
|
+
runtime_state.current_result = response_list
|
706
|
+
call_method_on_directives(:resolve_each, owner_object, ast_node.directives) do
|
707
|
+
# This will update `response_list` with the lazy
|
708
|
+
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|
|
709
|
+
continue_value = continue_value(inner_inner_value, owner_type, field, inner_type_non_null, ast_node, this_idx, response_list)
|
710
|
+
if HALT != continue_value
|
711
|
+
continue_field(continue_value, owner_type, field, inner_type, ast_node, next_selections, false, owner_object, arguments, this_idx, response_list, was_scoped, runtime_state)
|
712
|
+
end
|
713
|
+
end
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
def call_method_on_directives(method_name, object, directives, &block)
|
679
718
|
return yield if directives.nil? || directives.empty?
|
680
|
-
run_directive(object, directives, 0, &block)
|
719
|
+
run_directive(method_name, object, directives, 0, &block)
|
681
720
|
end
|
682
721
|
|
683
|
-
def run_directive(object, directives, idx, &block)
|
722
|
+
def run_directive(method_name, object, directives, idx, &block)
|
684
723
|
dir_node = directives[idx]
|
685
724
|
if !dir_node
|
686
725
|
yield
|
687
726
|
else
|
688
|
-
dir_defn =
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
727
|
+
dir_defn = @schema_directives.fetch(dir_node.name)
|
728
|
+
raw_dir_args = arguments(nil, dir_defn, dir_node)
|
729
|
+
dir_args = continue_value(
|
730
|
+
raw_dir_args, # value
|
731
|
+
dir_defn, # parent_type
|
732
|
+
nil, # field
|
733
|
+
false, # is_non_null
|
734
|
+
dir_node, # ast_node
|
735
|
+
nil, # result_name
|
736
|
+
nil, # selection_result
|
737
|
+
)
|
738
|
+
|
739
|
+
if dir_args == HALT
|
740
|
+
nil
|
741
|
+
else
|
742
|
+
dir_defn.public_send(method_name, object, dir_args, context) do
|
743
|
+
run_directive(method_name, object, directives, idx + 1, &block)
|
744
|
+
end
|
695
745
|
end
|
696
746
|
end
|
697
747
|
end
|
@@ -699,7 +749,7 @@ module GraphQL
|
|
699
749
|
# Check {Schema::Directive.include?} for each directive that's present
|
700
750
|
def directives_include?(node, graphql_object, parent_type)
|
701
751
|
node.directives.each do |dir_node|
|
702
|
-
dir_defn =
|
752
|
+
dir_defn = @schema_directives.fetch(dir_node.name)
|
703
753
|
args = arguments(graphql_object, dir_defn, dir_node)
|
704
754
|
if !dir_defn.include?(graphql_object, args, context)
|
705
755
|
return false
|
@@ -708,59 +758,85 @@ module GraphQL
|
|
708
758
|
true
|
709
759
|
end
|
710
760
|
|
711
|
-
def
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
@context[:current_field] = @interpreter_context[:current_field] = field
|
717
|
-
end
|
718
|
-
if arguments
|
719
|
-
@context[:current_arguments] = @interpreter_context[:current_arguments] = arguments
|
761
|
+
def get_current_runtime_state
|
762
|
+
current_state = Thread.current[:__graphql_runtime_info] ||= begin
|
763
|
+
per_query_state = {}
|
764
|
+
per_query_state.compare_by_identity
|
765
|
+
per_query_state
|
720
766
|
end
|
721
|
-
|
722
|
-
|
767
|
+
|
768
|
+
current_state[@query] ||= CurrentState.new
|
769
|
+
end
|
770
|
+
|
771
|
+
def minimal_after_lazy(value, &block)
|
772
|
+
if lazy?(value)
|
773
|
+
GraphQL::Execution::Lazy.new do
|
774
|
+
result = @schema.sync_lazy(value)
|
775
|
+
# The returned result might also be lazy, so check it, too
|
776
|
+
minimal_after_lazy(result, &block)
|
777
|
+
end
|
778
|
+
else
|
779
|
+
yield(value)
|
723
780
|
end
|
724
781
|
end
|
725
782
|
|
726
783
|
# @param obj [Object] Some user-returned value that may want to be batched
|
727
|
-
# @param path [Array<String>]
|
728
784
|
# @param field [GraphQL::Schema::Field]
|
729
785
|
# @param eager [Boolean] Set to `true` for mutation root fields only
|
730
786
|
# @param trace [Boolean] If `false`, don't wrap this with field tracing
|
731
787
|
# @return [GraphQL::Execution::Lazy, Object] If loading `object` will be deferred, it's a wrapper over it.
|
732
|
-
def after_lazy(lazy_obj,
|
788
|
+
def after_lazy(lazy_obj, field:, owner_object:, arguments:, ast_node:, result:, result_name:, eager: false, runtime_state:, trace: true, &block)
|
733
789
|
if lazy?(lazy_obj)
|
734
|
-
|
735
|
-
|
736
|
-
|
790
|
+
orig_result = result
|
791
|
+
was_authorized_by_scope_items = runtime_state.was_authorized_by_scope_items
|
792
|
+
lazy = GraphQL::Execution::Lazy.new(field: field) do
|
793
|
+
# This block might be called in a new fiber;
|
794
|
+
# In that case, this will initialize a new state
|
795
|
+
# to avoid conflicting with the parent fiber.
|
796
|
+
runtime_state = get_current_runtime_state
|
797
|
+
runtime_state.current_object = owner_object
|
798
|
+
runtime_state.current_field = field
|
799
|
+
runtime_state.current_arguments = arguments
|
800
|
+
runtime_state.current_result_name = result_name
|
801
|
+
runtime_state.current_result = orig_result
|
802
|
+
runtime_state.was_authorized_by_scope_items = was_authorized_by_scope_items
|
737
803
|
# Wrap the execution of _this_ method with tracing,
|
738
804
|
# but don't wrap the continuation below
|
739
805
|
inner_obj = begin
|
740
|
-
|
741
|
-
|
742
|
-
query.trace("execute_field_lazy", {owner: owner, field: field, path: path, query: query, object: owner_object, arguments: arguments, ast_node: ast_node}) do
|
743
|
-
schema.sync_lazy(lazy_obj)
|
744
|
-
end
|
745
|
-
else
|
806
|
+
if trace
|
807
|
+
@current_trace.execute_field_lazy(field: field, query: query, object: owner_object, arguments: arguments, ast_node: ast_node) do
|
746
808
|
schema.sync_lazy(lazy_obj)
|
747
809
|
end
|
810
|
+
else
|
811
|
+
schema.sync_lazy(lazy_obj)
|
812
|
+
end
|
813
|
+
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => ex_err
|
814
|
+
ex_err
|
815
|
+
rescue StandardError => err
|
816
|
+
begin
|
817
|
+
query.handle_or_reraise(err)
|
818
|
+
rescue GraphQL::ExecutionError => ex_err
|
819
|
+
ex_err
|
748
820
|
end
|
749
|
-
rescue GraphQL::ExecutionError, GraphQL::UnauthorizedError => err
|
750
|
-
err
|
751
821
|
end
|
752
|
-
yield(inner_obj)
|
822
|
+
yield(inner_obj, runtime_state)
|
753
823
|
end
|
754
824
|
|
755
825
|
if eager
|
756
826
|
lazy.value
|
757
827
|
else
|
758
|
-
set_result(result, result_name, lazy)
|
828
|
+
set_result(result, result_name, lazy, false, false) # is_non_null is irrelevant here
|
829
|
+
current_depth = 0
|
830
|
+
while result
|
831
|
+
current_depth += 1
|
832
|
+
result = result.graphql_parent
|
833
|
+
end
|
834
|
+
@lazies_at_depth[current_depth] << lazy
|
759
835
|
lazy
|
760
836
|
end
|
761
837
|
else
|
762
|
-
|
763
|
-
yield(lazy_obj)
|
838
|
+
# Don't need to reset state here because it _wasn't_ lazy.
|
839
|
+
yield(lazy_obj, runtime_state)
|
764
840
|
end
|
765
841
|
end
|
766
842
|
|
@@ -773,27 +849,25 @@ module GraphQL
|
|
773
849
|
end
|
774
850
|
end
|
775
851
|
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
@context.delete(key)
|
852
|
+
def delete_all_interpreter_context
|
853
|
+
per_query_state = Thread.current[:__graphql_runtime_info]
|
854
|
+
if per_query_state
|
855
|
+
per_query_state.delete(@query)
|
856
|
+
if per_query_state.size == 0
|
857
|
+
Thread.current[:__graphql_runtime_info] = nil
|
858
|
+
end
|
859
|
+
end
|
860
|
+
nil
|
786
861
|
end
|
787
862
|
|
788
|
-
def resolve_type(type, value
|
789
|
-
|
790
|
-
resolved_type, resolved_value = query.trace("resolve_type", trace_payload) do
|
863
|
+
def resolve_type(type, value)
|
864
|
+
resolved_type, resolved_value = @current_trace.resolve_type(query: query, type: type, object: value) do
|
791
865
|
query.resolve_type(type, value)
|
792
866
|
end
|
793
867
|
|
794
868
|
if lazy?(resolved_type)
|
795
869
|
GraphQL::Execution::Lazy.new do
|
796
|
-
|
870
|
+
@current_trace.resolve_type_lazy(query: query, type: type, object: value) do
|
797
871
|
schema.sync_lazy(resolved_type)
|
798
872
|
end
|
799
873
|
end
|
@@ -802,14 +876,13 @@ module GraphQL
|
|
802
876
|
end
|
803
877
|
end
|
804
878
|
|
805
|
-
def authorized_new(type, value, context)
|
806
|
-
type.authorized_new(value, context)
|
807
|
-
end
|
808
|
-
|
809
879
|
def lazy?(object)
|
810
|
-
|
811
|
-
|
812
|
-
|
880
|
+
obj_class = object.class
|
881
|
+
is_lazy = @lazy_cache[obj_class]
|
882
|
+
if is_lazy.nil?
|
883
|
+
is_lazy = @lazy_cache[obj_class] = @schema.lazy?(object)
|
884
|
+
end
|
885
|
+
is_lazy
|
813
886
|
end
|
814
887
|
end
|
815
888
|
end
|