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