graphql 1.13.24 → 2.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/graphql/install/mutation_root_generator.rb +2 -2
- data/lib/generators/graphql/install/templates/base_mutation.erb +2 -0
- data/lib/generators/graphql/install/templates/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +50 -1
- data/lib/generators/graphql/mutation_delete_generator.rb +1 -1
- data/lib/generators/graphql/mutation_update_generator.rb +1 -1
- data/lib/generators/graphql/orm_mutations_base.rb +1 -1
- data/lib/generators/graphql/relay.rb +21 -18
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +2 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/schema.erb +8 -0
- data/lib/generators/graphql/type_generator.rb +1 -1
- data/lib/graphql/analysis/analyzer.rb +90 -0
- data/lib/graphql/analysis/field_usage.rb +65 -28
- data/lib/graphql/analysis/max_query_complexity.rb +11 -17
- data/lib/graphql/analysis/max_query_depth.rb +13 -19
- data/lib/graphql/analysis/query_complexity.rb +236 -61
- data/lib/graphql/analysis/query_depth.rb +38 -23
- data/lib/graphql/analysis/visitor.rb +280 -0
- data/lib/graphql/analysis.rb +93 -6
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/table.rb +118 -73
- data/lib/graphql/backtrace.rb +2 -25
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +57 -0
- data/lib/graphql/dashboard/detailed_traces.rb +47 -0
- data/lib/graphql/dashboard/installable.rb +22 -0
- data/lib/graphql/dashboard/limiters.rb +93 -0
- data/lib/graphql/dashboard/operation_store.rb +199 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.css +6 -0
- data/lib/graphql/dashboard/statics/bootstrap-5.3.3.min.js +7 -0
- data/lib/graphql/dashboard/statics/charts.min.css +1 -0
- data/lib/graphql/dashboard/statics/dashboard.css +30 -0
- data/lib/graphql/dashboard/statics/dashboard.js +143 -0
- data/lib/graphql/dashboard/statics/header-icon.png +0 -0
- data/lib/graphql/dashboard/statics/icon.png +0 -0
- data/lib/graphql/dashboard/subscriptions.rb +96 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/detailed_traces/traces/index.html.erb +45 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/landings/show.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/limiters/limiters/show.html.erb +62 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/not_installed.html.erb +18 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/_form.html.erb +23 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/edit.html.erb +21 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/index.html.erb +69 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/clients/new.html.erb +7 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/index.html.erb +39 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/index_entries/show.html.erb +32 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/index.html.erb +81 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/operation_store/operations/show.html.erb +71 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/subscriptions/show.html.erb +41 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/index.html.erb +55 -0
- data/lib/graphql/dashboard/views/graphql/dashboard/subscriptions/topics/show.html.erb +40 -0
- data/lib/graphql/dashboard/views/layouts/graphql/dashboard/application.html.erb +108 -0
- data/lib/graphql/dashboard.rb +158 -0
- data/lib/graphql/dataloader/active_record_association_source.rb +84 -0
- data/lib/graphql/dataloader/active_record_source.rb +47 -0
- data/lib/graphql/dataloader/async_dataloader.rb +101 -0
- data/lib/graphql/dataloader/null_dataloader.rb +11 -2
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +103 -47
- data/lib/graphql/dataloader.rb +174 -148
- data/lib/graphql/dig.rb +3 -2
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -82
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +1 -1
- data/lib/graphql/execution/interpreter/arguments_cache.rb +30 -35
- data/lib/graphql/execution/interpreter/resolve.rb +32 -2
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +215 -0
- data/lib/graphql/execution/interpreter/runtime.rb +525 -502
- data/lib/graphql/execution/interpreter.rb +127 -81
- data/lib/graphql/execution/lazy.rb +7 -21
- data/lib/graphql/execution/lookahead.rb +133 -55
- data/lib/graphql/execution/multiplex.rb +6 -176
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/introspection/directive_location_enum.rb +1 -1
- data/lib/graphql/introspection/directive_type.rb +1 -1
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +10 -17
- data/lib/graphql/introspection/field_type.rb +1 -1
- data/lib/graphql/introspection/schema_type.rb +8 -11
- data/lib/graphql/introspection/type_type.rb +13 -6
- data/lib/graphql/introspection.rb +4 -3
- data/lib/graphql/invalid_name_error.rb +1 -1
- data/lib/graphql/invalid_null_error.rb +20 -17
- data/lib/graphql/language/block_string.rb +34 -18
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +114 -80
- data/lib/graphql/language/lexer.rb +375 -1489
- data/lib/graphql/language/nodes.rb +189 -104
- data/lib/graphql/language/parser.rb +807 -1941
- data/lib/graphql/language/printer.rb +366 -163
- data/lib/graphql/language/sanitized_printer.rb +21 -23
- data/lib/graphql/language/static_visitor.rb +171 -0
- data/lib/graphql/language/visitor.rb +189 -138
- data/lib/graphql/language.rb +62 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/pagination/active_record_relation_connection.rb +0 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +3 -28
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +2 -0
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +131 -225
- data/lib/graphql/query/input_validation_result.rb +1 -1
- data/lib/graphql/query/null_context.rb +11 -33
- data/lib/graphql/query/partial.rb +179 -0
- data/lib/graphql/query/validation_pipeline.rb +14 -37
- data/lib/graphql/query/variable_validation_error.rb +1 -1
- data/lib/graphql/query/variables.rb +6 -19
- data/lib/graphql/query.rb +162 -98
- data/lib/graphql/railtie.rb +15 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -20
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -1
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +2 -0
- data/lib/graphql/schema/addition.rb +70 -33
- data/lib/graphql/schema/always_visible.rb +15 -0
- data/lib/graphql/schema/argument.rb +104 -59
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +154 -74
- data/lib/graphql/schema/directive/flagged.rb +4 -2
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +1 -1
- data/lib/graphql/schema/directive.rb +47 -24
- data/lib/graphql/schema/enum.rb +137 -65
- data/lib/graphql/schema/enum_value.rb +11 -26
- data/lib/graphql/schema/field/connection_extension.rb +6 -16
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +399 -404
- data/lib/graphql/schema/field_extension.rb +2 -5
- data/lib/graphql/schema/find_inherited_value.rb +2 -7
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +144 -99
- data/lib/graphql/schema/interface.rb +34 -51
- data/lib/graphql/schema/introspection_system.rb +12 -26
- data/lib/graphql/schema/late_bound_type.rb +12 -2
- data/lib/graphql/schema/list.rb +3 -9
- data/lib/graphql/schema/loader.rb +4 -6
- data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
- data/lib/graphql/schema/member/build_type.rb +15 -9
- data/lib/graphql/schema/member/has_arguments.rb +192 -96
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_dataloader.rb +62 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +18 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +119 -39
- data/lib/graphql/schema/member/has_interfaces.rb +66 -23
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +32 -2
- data/lib/graphql/schema/member/validates_input.rb +4 -4
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +7 -9
- data/lib/graphql/schema/non_null.rb +1 -7
- data/lib/graphql/schema/object.rb +42 -49
- data/lib/graphql/schema/printer.rb +12 -8
- data/lib/graphql/schema/ractor_shareable.rb +79 -0
- data/lib/graphql/schema/relay_classic_mutation.rb +12 -124
- data/lib/graphql/schema/resolver/has_payload_type.rb +20 -10
- data/lib/graphql/schema/resolver.rb +96 -81
- data/lib/graphql/schema/scalar.rb +10 -30
- data/lib/graphql/schema/subscription.rb +60 -14
- data/lib/graphql/schema/timeout.rb +44 -31
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +3 -0
- data/lib/graphql/schema/union.rb +12 -19
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/required_validator.rb +60 -10
- data/lib/graphql/schema/validator.rb +5 -3
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +445 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +311 -0
- data/lib/graphql/schema/warden.rb +318 -94
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +1148 -1085
- data/lib/graphql/static_validation/all_rules.rb +4 -3
- data/lib/graphql/static_validation/base_visitor.rb +11 -27
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -1
- data/lib/graphql/static_validation/error.rb +2 -2
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -2
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +14 -12
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +48 -6
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +90 -27
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +10 -2
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +25 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +26 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +19 -9
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +2 -2
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +21 -5
- data/lib/graphql/static_validation/validator.rb +12 -26
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +14 -6
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
- data/lib/graphql/subscriptions/event.rb +24 -12
- data/lib/graphql/subscriptions/serialize.rb +3 -1
- data/lib/graphql/subscriptions.rb +48 -32
- data/lib/graphql/testing/helpers.rb +158 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +27 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +1 -1
- data/lib/graphql/tracing/appoptics_trace.rb +259 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +9 -2
- data/lib/graphql/tracing/appsignal_trace.rb +54 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +2 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +71 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +3 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +60 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +72 -0
- data/lib/graphql/tracing/detailed_trace.rb +93 -0
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
- data/lib/graphql/tracing/legacy_trace.rb +12 -0
- data/lib/graphql/tracing/monitor_trace.rb +283 -0
- data/lib/graphql/tracing/new_relic_trace.rb +68 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +195 -0
- data/lib/graphql/tracing/notifications_tracing.rb +2 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/perfetto_trace/trace.proto +141 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +33 -0
- data/lib/graphql/tracing/perfetto_trace.rb +734 -0
- data/lib/graphql/tracing/platform_trace.rb +123 -0
- data/lib/graphql/tracing/platform_tracing.rb +28 -41
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
- data/lib/graphql/tracing/prometheus_trace.rb +93 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
- data/lib/graphql/tracing/scout_trace.rb +49 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +80 -0
- data/lib/graphql/tracing/statsd_trace.rb +48 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +186 -0
- data/lib/graphql/tracing.rb +32 -52
- data/lib/graphql/type_kinds.rb +8 -4
- data/lib/graphql/types/iso_8601_date.rb +4 -1
- data/lib/graphql/types/iso_8601_date_time.rb +4 -0
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +65 -23
- data/lib/graphql/types/relay/edge_behaviors.rb +33 -5
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +1 -1
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +76 -123
- data/readme.md +13 -3
- metadata +225 -142
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -55
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -230
- data/lib/graphql/analysis/ast/query_depth.rb +0 -56
- data/lib/graphql/analysis/ast/visitor.rb +0 -269
- data/lib/graphql/analysis/ast.rb +0 -91
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/inspect_result.rb +0 -50
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backtrace/tracer.rb +0 -81
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -232
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -255
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -55
- data/lib/graphql/deprecation.rb +0 -9
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -107
- data/lib/graphql/enum_type.rb +0 -133
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -260
- data/lib/graphql/language/parser.y +0 -550
- data/lib/graphql/language/token.rb +0 -34
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -54
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -39
- data/lib/graphql/relay/global_id_resolve.rb +0 -17
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/member/accepts_definition.rb +0 -164
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -58
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/null_mask.rb +0 -11
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +0 -17
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -31
- data/lib/graphql/types/relay/node_field.rb +0 -24
- data/lib/graphql/types/relay/nodes_field.rb +0 -43
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -7,9 +7,9 @@ module GraphQL
|
|
7
7
|
# @api private
|
8
8
|
def setup(dataloader)
|
9
9
|
# These keys have been requested but haven't been fetched yet
|
10
|
-
@
|
10
|
+
@pending = {}
|
11
11
|
# These keys have been passed to `fetch` but haven't been finished yet
|
12
|
-
@
|
12
|
+
@fetching = {}
|
13
13
|
# { key => result }
|
14
14
|
@results = {}
|
15
15
|
@dataloader = dataloader
|
@@ -18,42 +18,78 @@ module GraphQL
|
|
18
18
|
attr_reader :dataloader
|
19
19
|
|
20
20
|
# @return [Dataloader::Request] a pending request for a value from `key`. Call `.load` on that object to wait for the result.
|
21
|
-
def request(
|
22
|
-
|
23
|
-
|
21
|
+
def request(value)
|
22
|
+
res_key = result_key_for(value)
|
23
|
+
if !@results.key?(res_key)
|
24
|
+
@pending[res_key] ||= normalize_fetch_key(value)
|
24
25
|
end
|
25
|
-
Dataloader::Request.new(self,
|
26
|
+
Dataloader::Request.new(self, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Implement this method to return a stable identifier if different
|
30
|
+
# key objects should load the same data value.
|
31
|
+
#
|
32
|
+
# @param value [Object] A value passed to `.request` or `.load`, for which a value will be loaded
|
33
|
+
# @return [Object] The key for tracking this pending data
|
34
|
+
def result_key_for(value)
|
35
|
+
value
|
36
|
+
end
|
37
|
+
|
38
|
+
# Implement this method if varying values given to {load} (etc) should be consolidated
|
39
|
+
# or normalized before being handed off to your {fetch} implementation.
|
40
|
+
#
|
41
|
+
# This is different than {result_key_for} because _that_ method handles unification inside Dataloader's cache,
|
42
|
+
# but this method changes the value passed into {fetch}.
|
43
|
+
#
|
44
|
+
# @param value [Object] The value passed to {load}, {load_all}, {request}, or {request_all}
|
45
|
+
# @return [Object] The value given to {fetch}
|
46
|
+
def normalize_fetch_key(value)
|
47
|
+
value
|
26
48
|
end
|
27
49
|
|
28
50
|
# @return [Dataloader::Request] a pending request for a values from `keys`. Call `.load` on that object to wait for the results.
|
29
|
-
def request_all(
|
30
|
-
|
31
|
-
|
32
|
-
|
51
|
+
def request_all(values)
|
52
|
+
values.each do |v|
|
53
|
+
res_key = result_key_for(v)
|
54
|
+
if !@results.key?(res_key)
|
55
|
+
@pending[res_key] ||= normalize_fetch_key(v)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
Dataloader::RequestAll.new(self, values)
|
33
59
|
end
|
34
60
|
|
35
|
-
# @param
|
61
|
+
# @param value [Object] A loading value which will be passed to {#fetch} if it isn't already in the internal cache.
|
36
62
|
# @return [Object] The result from {#fetch} for `key`. If `key` hasn't been loaded yet, the Fiber will yield until it's loaded.
|
37
|
-
def load(
|
38
|
-
|
39
|
-
|
63
|
+
def load(value)
|
64
|
+
result_key = result_key_for(value)
|
65
|
+
if @results.key?(result_key)
|
66
|
+
result_for(result_key)
|
40
67
|
else
|
41
|
-
@
|
42
|
-
sync
|
43
|
-
result_for(
|
68
|
+
@pending[result_key] ||= normalize_fetch_key(value)
|
69
|
+
sync([result_key])
|
70
|
+
result_for(result_key)
|
44
71
|
end
|
45
72
|
end
|
46
73
|
|
47
|
-
# @param
|
74
|
+
# @param values [Array<Object>] Loading keys which will be passed to `#fetch` (or read from the internal cache).
|
48
75
|
# @return [Object] The result from {#fetch} for `keys`. If `keys` haven't been loaded yet, the Fiber will yield until they're loaded.
|
49
|
-
def load_all(
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
76
|
+
def load_all(values)
|
77
|
+
result_keys = []
|
78
|
+
pending_keys = []
|
79
|
+
values.each { |v|
|
80
|
+
k = result_key_for(v)
|
81
|
+
result_keys << k
|
82
|
+
if !@results.key?(k)
|
83
|
+
@pending[k] ||= normalize_fetch_key(v)
|
84
|
+
pending_keys << k
|
85
|
+
end
|
86
|
+
}
|
87
|
+
|
88
|
+
if !pending_keys.empty?
|
89
|
+
sync(pending_keys)
|
54
90
|
end
|
55
91
|
|
56
|
-
|
92
|
+
result_keys.map { |k| result_for(k) }
|
57
93
|
end
|
58
94
|
|
59
95
|
# Subclasses must implement this method to return a value for each of `keys`
|
@@ -64,50 +100,60 @@ module GraphQL
|
|
64
100
|
raise "Implement `#{self.class}#fetch(#{keys.inspect}) to return a record for each of the keys"
|
65
101
|
end
|
66
102
|
|
103
|
+
MAX_ITERATIONS = 1000
|
67
104
|
# Wait for a batch, if there's anything to batch.
|
68
105
|
# Then run the batch and update the cache.
|
69
106
|
# @return [void]
|
70
|
-
def sync
|
71
|
-
|
72
|
-
@dataloader.yield
|
107
|
+
def sync(pending_result_keys)
|
108
|
+
@dataloader.yield(self)
|
73
109
|
iterations = 0
|
74
|
-
while
|
110
|
+
while pending_result_keys.any? { |key| !@results.key?(key) }
|
75
111
|
iterations += 1
|
76
|
-
if iterations >
|
77
|
-
raise "#{self.class}#sync tried
|
112
|
+
if iterations > MAX_ITERATIONS
|
113
|
+
raise "#{self.class}#sync tried #{MAX_ITERATIONS} times to load pending keys (#{pending_result_keys}), but they still weren't loaded. There is likely a circular dependency#{@dataloader.fiber_limit ? " or `fiber_limit: #{@dataloader.fiber_limit}` is set too low" : ""}."
|
78
114
|
end
|
79
|
-
@dataloader.yield
|
115
|
+
@dataloader.yield(self)
|
80
116
|
end
|
81
117
|
nil
|
82
118
|
end
|
83
119
|
|
84
120
|
# @return [Boolean] True if this source has any pending requests for data.
|
85
121
|
def pending?
|
86
|
-
!@
|
122
|
+
!@pending.empty?
|
123
|
+
end
|
124
|
+
|
125
|
+
# Add these key-value pairs to this source's cache
|
126
|
+
# (future loads will use these merged values).
|
127
|
+
# @param new_results [Hash<Object => Object>] key-value pairs to cache in this source
|
128
|
+
# @return [void]
|
129
|
+
def merge(new_results)
|
130
|
+
new_results.each do |new_k, new_v|
|
131
|
+
key = result_key_for(new_k)
|
132
|
+
@results[key] = new_v
|
133
|
+
end
|
134
|
+
nil
|
87
135
|
end
|
88
136
|
|
89
137
|
# Called by {GraphQL::Dataloader} to resolve and pending requests to this source.
|
90
138
|
# @api private
|
91
139
|
# @return [void]
|
92
140
|
def run_pending_keys
|
93
|
-
if !@
|
94
|
-
@
|
141
|
+
if !@fetching.empty?
|
142
|
+
@fetching.each_key { |k| @pending.delete(k) }
|
95
143
|
end
|
96
|
-
return if @
|
97
|
-
|
98
|
-
@
|
99
|
-
@
|
100
|
-
results = fetch(
|
101
|
-
|
144
|
+
return if @pending.empty?
|
145
|
+
fetch_h = @pending
|
146
|
+
@pending = {}
|
147
|
+
@fetching.merge!(fetch_h)
|
148
|
+
results = fetch(fetch_h.values)
|
149
|
+
fetch_h.each_with_index do |(key, _value), idx|
|
102
150
|
@results[key] = results[idx]
|
103
151
|
end
|
104
152
|
nil
|
105
153
|
rescue StandardError => error
|
106
|
-
|
154
|
+
fetch_h.each_key { |key| @results[key] = error }
|
107
155
|
ensure
|
108
|
-
|
109
|
-
@fetching_keys -= fetch_keys
|
110
|
-
end
|
156
|
+
fetch_h && fetch_h.each_key { |k| @fetching.delete(k) }
|
111
157
|
end
|
112
158
|
|
113
159
|
# These arguments are given to `dataloader.with(source_class, ...)`. The object
|
@@ -128,7 +174,14 @@ module GraphQL
|
|
128
174
|
[*batch_args, **batch_kwargs]
|
129
175
|
end
|
130
176
|
|
131
|
-
|
177
|
+
# Clear any already-loaded objects for this source
|
178
|
+
# @return [void]
|
179
|
+
def clear_cache
|
180
|
+
@results.clear
|
181
|
+
nil
|
182
|
+
end
|
183
|
+
|
184
|
+
attr_reader :pending, :results
|
132
185
|
|
133
186
|
private
|
134
187
|
|
@@ -145,8 +198,11 @@ This key should have been loaded already. This is a bug in GraphQL::Dataloader,
|
|
145
198
|
ERR
|
146
199
|
end
|
147
200
|
result = @results[key]
|
148
|
-
|
149
|
-
|
201
|
+
if result.is_a?(StandardError)
|
202
|
+
# Dup it because the rescuer may modify it.
|
203
|
+
# (This happens for GraphQL::ExecutionErrors, at least)
|
204
|
+
raise result.dup
|
205
|
+
end
|
150
206
|
|
151
207
|
result
|
152
208
|
end
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -4,6 +4,8 @@ require "graphql/dataloader/null_dataloader"
|
|
4
4
|
require "graphql/dataloader/request"
|
5
5
|
require "graphql/dataloader/request_all"
|
6
6
|
require "graphql/dataloader/source"
|
7
|
+
require "graphql/dataloader/active_record_association_source"
|
8
|
+
require "graphql/dataloader/active_record_source"
|
7
9
|
|
8
10
|
module GraphQL
|
9
11
|
# This plugin supports Fiber-based concurrency, along with {GraphQL::Dataloader::Source}.
|
@@ -24,17 +26,23 @@ module GraphQL
|
|
24
26
|
#
|
25
27
|
class Dataloader
|
26
28
|
class << self
|
27
|
-
attr_accessor :default_nonblocking
|
29
|
+
attr_accessor :default_nonblocking, :default_fiber_limit
|
28
30
|
end
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
AsyncDataloader
|
32
|
+
def self.use(schema, nonblocking: nil, fiber_limit: nil)
|
33
|
+
dataloader_class = if nonblocking
|
34
|
+
warn("`nonblocking: true` is deprecated from `GraphQL::Dataloader`, please use `GraphQL::Dataloader::AsyncDataloader` instead. Docs: https://graphql-ruby.org/dataloader/async_dataloader.")
|
35
|
+
Class.new(self) { self.default_nonblocking = true }
|
35
36
|
else
|
36
37
|
self
|
37
38
|
end
|
39
|
+
|
40
|
+
if fiber_limit
|
41
|
+
dataloader_class = Class.new(dataloader_class)
|
42
|
+
dataloader_class.default_fiber_limit = fiber_limit
|
43
|
+
end
|
44
|
+
|
45
|
+
schema.dataloader_class = dataloader_class
|
38
46
|
end
|
39
47
|
|
40
48
|
# Call the block with a Dataloader instance,
|
@@ -49,18 +57,50 @@ module GraphQL
|
|
49
57
|
result
|
50
58
|
end
|
51
59
|
|
52
|
-
def initialize(nonblocking: self.class.default_nonblocking)
|
60
|
+
def initialize(nonblocking: self.class.default_nonblocking, fiber_limit: self.class.default_fiber_limit)
|
53
61
|
@source_cache = Hash.new { |h, k| h[k] = {} }
|
54
62
|
@pending_jobs = []
|
55
63
|
if !nonblocking.nil?
|
56
64
|
@nonblocking = nonblocking
|
57
65
|
end
|
66
|
+
@fiber_limit = fiber_limit
|
58
67
|
end
|
59
68
|
|
69
|
+
# @return [Integer, nil]
|
70
|
+
attr_reader :fiber_limit
|
71
|
+
|
60
72
|
def nonblocking?
|
61
73
|
@nonblocking
|
62
74
|
end
|
63
75
|
|
76
|
+
# This is called before the fiber is spawned, from the parent context (i.e. from
|
77
|
+
# the thread or fiber that it is scheduled from).
|
78
|
+
#
|
79
|
+
# @return [Hash<Symbol, Object>] Current fiber-local variables
|
80
|
+
def get_fiber_variables
|
81
|
+
fiber_vars = {}
|
82
|
+
Thread.current.keys.each do |fiber_var_key|
|
83
|
+
fiber_vars[fiber_var_key] = Thread.current[fiber_var_key]
|
84
|
+
end
|
85
|
+
fiber_vars
|
86
|
+
end
|
87
|
+
|
88
|
+
# Set up the fiber variables in a new fiber.
|
89
|
+
#
|
90
|
+
# This is called within the fiber, right after it is spawned.
|
91
|
+
#
|
92
|
+
# @param vars [Hash<Symbol, Object>] Fiber-local variables from {get_fiber_variables}
|
93
|
+
# @return [void]
|
94
|
+
def set_fiber_variables(vars)
|
95
|
+
vars.each { |k, v| Thread.current[k] = v }
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# This method is called when Dataloader is finished using a fiber.
|
100
|
+
# Use it to perform any cleanup, such as releasing database connections (if required manually)
|
101
|
+
def cleanup_fiber
|
102
|
+
end
|
103
|
+
|
64
104
|
# Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
|
65
105
|
#
|
66
106
|
# @param source_class [Class<GraphQL::Dataloader::Source]
|
@@ -91,8 +131,11 @@ module GraphQL
|
|
91
131
|
# Dataloader will resume the fiber after the requested data has been loaded (by another Fiber).
|
92
132
|
#
|
93
133
|
# @return [void]
|
94
|
-
def yield
|
134
|
+
def yield(source = Fiber[:__graphql_current_dataloader_source])
|
135
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
136
|
+
trace&.dataloader_fiber_yield(source)
|
95
137
|
Fiber.yield
|
138
|
+
trace&.dataloader_fiber_resume(source)
|
96
139
|
nil
|
97
140
|
end
|
98
141
|
|
@@ -104,6 +147,15 @@ module GraphQL
|
|
104
147
|
nil
|
105
148
|
end
|
106
149
|
|
150
|
+
# Clear any already-loaded objects from {Source} caches
|
151
|
+
# @return [void]
|
152
|
+
def clear_cache
|
153
|
+
@source_cache.each do |_source_class, batched_sources|
|
154
|
+
batched_sources.each_value(&:clear_cache)
|
155
|
+
end
|
156
|
+
nil
|
157
|
+
end
|
158
|
+
|
107
159
|
# Use a self-contained queue for the work in the block.
|
108
160
|
def run_isolated
|
109
161
|
prev_queue = @pending_jobs
|
@@ -111,8 +163,8 @@ module GraphQL
|
|
111
163
|
@source_cache.each do |source_class, batched_sources|
|
112
164
|
batched_sources.each do |batch_args, batched_source_instance|
|
113
165
|
if batched_source_instance.pending?
|
114
|
-
prev_pending_keys[batched_source_instance] = batched_source_instance.
|
115
|
-
batched_source_instance.
|
166
|
+
prev_pending_keys[batched_source_instance] = batched_source_instance.pending.dup
|
167
|
+
batched_source_instance.pending.clear
|
116
168
|
end
|
117
169
|
end
|
118
170
|
end
|
@@ -127,125 +179,132 @@ module GraphQL
|
|
127
179
|
res
|
128
180
|
ensure
|
129
181
|
@pending_jobs = prev_queue
|
130
|
-
prev_pending_keys.each do |source_instance,
|
131
|
-
|
182
|
+
prev_pending_keys.each do |source_instance, pending|
|
183
|
+
pending.each do |key, value|
|
184
|
+
if !source_instance.results.key?(key)
|
185
|
+
source_instance.pending[key] = value
|
186
|
+
end
|
187
|
+
end
|
132
188
|
end
|
133
189
|
end
|
134
190
|
|
135
|
-
# @api private Move along, move along
|
136
191
|
def run
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
# A) Inside Fibers, run jobs from the queue one-by-one
|
143
|
-
# - When one of the jobs yields to the dataloader (`Fiber.yield`), then that fiber will pause
|
144
|
-
# - In that case, if there are still pending jobs, a new Fiber will be created to run jobs
|
145
|
-
# - Continue until all jobs have been _started_ by a Fiber. (Any number of those Fibers may be waiting to be resumed, after their data is loaded)
|
146
|
-
# B) Once all known jobs have been run until they are complete or paused for data, run all pending data sources.
|
147
|
-
# - Similarly, create a Fiber to consume pending sources and tell them to load their data.
|
148
|
-
# - If one of those Fibers pauses, then create a new Fiber to continue working through remaining pending sources.
|
149
|
-
# - When a source causes another source to become pending, run the newly-pending source _first_, since it's a dependency of the previous one.
|
150
|
-
# C) After all pending sources have been completely loaded (there are no more pending sources), resume any Fibers that were waiting for data.
|
151
|
-
# - Those Fibers assume that source caches will have been populated with the data they were waiting for.
|
152
|
-
# - Those Fibers may request data from a source again, in which case they will yeilded and be added to a new pending fiber list.
|
153
|
-
# D) Once all pending fibers have been resumed once, return to `A` above.
|
154
|
-
#
|
155
|
-
# For whatever reason, the best implementation I could find was to order the steps `[D, A, B, C]`, with a special case for skipping `D`
|
156
|
-
# on the first pass. I just couldn't find a better way to write the loops in a way that was DRY and easy to read.
|
157
|
-
#
|
158
|
-
pending_fibers = []
|
159
|
-
next_fibers = []
|
160
|
-
pending_source_fibers = []
|
192
|
+
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
193
|
+
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
194
|
+
job_fibers = []
|
195
|
+
next_job_fibers = []
|
196
|
+
source_fibers = []
|
161
197
|
next_source_fibers = []
|
162
198
|
first_pass = true
|
163
|
-
|
164
|
-
|
165
|
-
|
199
|
+
manager = spawn_fiber do
|
200
|
+
trace&.begin_dataloader(self)
|
201
|
+
while first_pass || !job_fibers.empty?
|
166
202
|
first_pass = false
|
167
|
-
else
|
168
|
-
# These fibers were previously waiting for sources to load data,
|
169
|
-
# resume them. (They might wait again, in which case, re-enqueue them.)
|
170
|
-
resume(f)
|
171
|
-
if f.alive?
|
172
|
-
next_fibers << f
|
173
|
-
end
|
174
|
-
end
|
175
203
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
204
|
+
while (f = (job_fibers.shift || (((next_job_fibers.size + job_fibers.size) < jobs_fiber_limit) && spawn_job_fiber(trace))))
|
205
|
+
if f.alive?
|
206
|
+
finished = run_fiber(f)
|
207
|
+
if !finished
|
208
|
+
next_job_fibers << f
|
209
|
+
end
|
182
210
|
end
|
183
|
-
}
|
184
|
-
resume(f)
|
185
|
-
# In this case, the job yielded. Queue it up to run again after
|
186
|
-
# we load whatever it's waiting for.
|
187
|
-
if f.alive?
|
188
|
-
next_fibers << f
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
if pending_fibers.empty?
|
193
|
-
# Now, run all Sources which have become pending _before_ resuming GraphQL execution.
|
194
|
-
# Sources might queue up other Sources, which is fine -- those will also run before resuming execution.
|
195
|
-
#
|
196
|
-
# This is where an evented approach would be even better -- can we tell which
|
197
|
-
# fibers are ready to continue, and continue execution there?
|
198
|
-
#
|
199
|
-
if (first_source_fiber = create_source_fiber)
|
200
|
-
pending_source_fibers << first_source_fiber
|
201
211
|
end
|
212
|
+
join_queues(job_fibers, next_job_fibers)
|
202
213
|
|
203
|
-
while
|
204
|
-
while (
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
pending_source_fibers << next_source_fiber
|
214
|
+
while (!source_fibers.empty? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) })
|
215
|
+
while (f = source_fibers.shift || (((job_fibers.size + source_fibers.size + next_source_fibers.size + next_job_fibers.size) < total_fiber_limit) && spawn_source_fiber(trace)))
|
216
|
+
if f.alive?
|
217
|
+
finished = run_fiber(f)
|
218
|
+
if !finished
|
219
|
+
next_source_fibers << f
|
220
|
+
end
|
211
221
|
end
|
212
222
|
end
|
213
|
-
join_queues(
|
214
|
-
next_source_fibers.clear
|
223
|
+
join_queues(source_fibers, next_source_fibers)
|
215
224
|
end
|
216
|
-
# Move newly-enqueued Fibers on to the list to be resumed.
|
217
|
-
# Clear out the list of next-round Fibers, so that
|
218
|
-
# any Fibers that pause can be put on it.
|
219
|
-
join_queues(pending_fibers, next_fibers)
|
220
|
-
next_fibers.clear
|
221
225
|
end
|
226
|
+
|
227
|
+
trace&.end_dataloader(self)
|
228
|
+
end
|
229
|
+
|
230
|
+
run_fiber(manager)
|
231
|
+
|
232
|
+
if manager.alive?
|
233
|
+
raise "Invariant: Manager fiber didn't terminate properly."
|
222
234
|
end
|
223
235
|
|
224
|
-
if
|
225
|
-
raise "Invariant: #{
|
226
|
-
elsif pending_fibers.any?
|
227
|
-
raise "Invariant: #{pending_fibers.size} pending fibers"
|
228
|
-
elsif next_fibers.any?
|
229
|
-
raise "Invariant: #{next_fibers.size} next fibers"
|
236
|
+
if !job_fibers.empty?
|
237
|
+
raise "Invariant: job fibers should have exited but #{job_fibers.size} remained"
|
230
238
|
end
|
231
|
-
|
239
|
+
if !source_fibers.empty?
|
240
|
+
raise "Invariant: source fibers should have exited but #{source_fibers.size} remained"
|
241
|
+
end
|
242
|
+
|
243
|
+
rescue UncaughtThrowError => e
|
244
|
+
throw e.tag, e.value
|
245
|
+
end
|
246
|
+
|
247
|
+
def run_fiber(f)
|
248
|
+
f.resume
|
249
|
+
end
|
250
|
+
|
251
|
+
def spawn_fiber
|
252
|
+
fiber_vars = get_fiber_variables
|
253
|
+
Fiber.new(blocking: !@nonblocking) {
|
254
|
+
set_fiber_variables(fiber_vars)
|
255
|
+
yield
|
256
|
+
cleanup_fiber
|
257
|
+
}
|
232
258
|
end
|
233
259
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
260
|
+
# Pre-warm the Dataloader cache with ActiveRecord objects which were loaded elsewhere.
|
261
|
+
# These will be used by {Dataloader::ActiveRecordSource}, {Dataloader::ActiveRecordAssociationSource} and their helper
|
262
|
+
# methods, `dataload_record` and `dataload_association`.
|
263
|
+
# @param records [Array<ActiveRecord::Base>] Already-loaded records to warm the cache with
|
264
|
+
# @param index_by [Symbol] The attribute to use as the cache key. (Should match `find_by:` when using {ActiveRecordSource})
|
265
|
+
# @return [void]
|
266
|
+
def merge_records(records, index_by: :id)
|
267
|
+
records_by_class = Hash.new { |h, k| h[k] = {} }
|
268
|
+
records.each do |r|
|
269
|
+
records_by_class[r.class][r.public_send(index_by)] = r
|
270
|
+
end
|
271
|
+
records_by_class.each do |r_class, records|
|
272
|
+
with(ActiveRecordSource, r_class).merge(records)
|
238
273
|
end
|
239
|
-
previous_queue.concat(next_queue)
|
240
274
|
end
|
241
275
|
|
242
276
|
private
|
243
277
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
278
|
+
def calculate_fiber_limit
|
279
|
+
total_fiber_limit = @fiber_limit || Float::INFINITY
|
280
|
+
if total_fiber_limit < 4
|
281
|
+
raise ArgumentError, "Dataloader fiber limit is too low (#{total_fiber_limit}), it must be at least 4"
|
282
|
+
end
|
283
|
+
total_fiber_limit -= 1 # deduct one fiber for `manager`
|
284
|
+
# Deduct at least one fiber for sources
|
285
|
+
jobs_fiber_limit = total_fiber_limit - 2
|
286
|
+
return jobs_fiber_limit, total_fiber_limit
|
287
|
+
end
|
288
|
+
|
289
|
+
def join_queues(prev_queue, new_queue)
|
290
|
+
@nonblocking && Fiber.scheduler.run
|
291
|
+
prev_queue.concat(new_queue)
|
292
|
+
new_queue.clear
|
293
|
+
end
|
294
|
+
|
295
|
+
def spawn_job_fiber(trace)
|
296
|
+
if !@pending_jobs.empty?
|
297
|
+
spawn_fiber do
|
298
|
+
trace&.dataloader_spawn_execution_fiber(@pending_jobs)
|
299
|
+
while job = @pending_jobs.shift
|
300
|
+
job.call
|
301
|
+
end
|
302
|
+
trace&.dataloader_fiber_exit
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def spawn_source_fiber(trace)
|
249
308
|
pending_sources = nil
|
250
309
|
@source_cache.each_value do |source_by_batch_params|
|
251
310
|
source_by_batch_params.each_value do |source|
|
@@ -257,52 +316,19 @@ module GraphQL
|
|
257
316
|
end
|
258
317
|
|
259
318
|
if pending_sources
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
pending_sources.each(&:run_pending_keys)
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
source_fiber
|
274
|
-
end
|
275
|
-
|
276
|
-
def resume(fiber)
|
277
|
-
fiber.resume
|
278
|
-
rescue UncaughtThrowError => e
|
279
|
-
throw e.tag, e.value
|
280
|
-
end
|
281
|
-
|
282
|
-
# Copies the thread local vars into the fiber thread local vars. Many
|
283
|
-
# gems (such as RequestStore, MiniRacer, etc.) rely on thread local vars
|
284
|
-
# to keep track of execution context, and without this they do not
|
285
|
-
# behave as expected.
|
286
|
-
#
|
287
|
-
# @see https://github.com/rmosolgo/graphql-ruby/issues/3449
|
288
|
-
def spawn_fiber
|
289
|
-
fiber_locals = {}
|
290
|
-
|
291
|
-
Thread.current.keys.each do |fiber_var_key|
|
292
|
-
fiber_locals[fiber_var_key] = Thread.current[fiber_var_key]
|
293
|
-
end
|
294
|
-
|
295
|
-
if @nonblocking
|
296
|
-
Fiber.new(blocking: false) do
|
297
|
-
fiber_locals.each { |k, v| Thread.current[k] = v }
|
298
|
-
yield
|
299
|
-
end
|
300
|
-
else
|
301
|
-
Fiber.new do
|
302
|
-
fiber_locals.each { |k, v| Thread.current[k] = v }
|
303
|
-
yield
|
319
|
+
spawn_fiber do
|
320
|
+
trace&.dataloader_spawn_source_fiber(pending_sources)
|
321
|
+
pending_sources.each do |source|
|
322
|
+
Fiber[:__graphql_current_dataloader_source] = source
|
323
|
+
trace&.begin_dataloader_source(source)
|
324
|
+
source.run_pending_keys
|
325
|
+
trace&.end_dataloader_source(source)
|
326
|
+
end
|
327
|
+
trace&.dataloader_fiber_exit
|
304
328
|
end
|
305
329
|
end
|
306
330
|
end
|
307
331
|
end
|
308
332
|
end
|
333
|
+
|
334
|
+
require "graphql/dataloader/async_dataloader"
|
data/lib/graphql/dig.rb
CHANGED
@@ -2,10 +2,11 @@
|
|
2
2
|
module GraphQL
|
3
3
|
module Dig
|
4
4
|
# implemented using the old activesupport #dig instead of the ruby built-in
|
5
|
-
# so we can use some of the magic in Schema::InputObject and
|
5
|
+
# so we can use some of the magic in Schema::InputObject and Interpreter::Arguments
|
6
6
|
# to handle stringified/symbolized keys.
|
7
7
|
#
|
8
|
-
# @param
|
8
|
+
# @param own_key [String, Symbol] A key to retrieve
|
9
|
+
# @param rest_keys [Array<[String, Symbol>] Retrieves the value object corresponding to the each key objects repeatedly
|
9
10
|
# @return [Object]
|
10
11
|
def dig(own_key, *rest_keys)
|
11
12
|
val = self[own_key]
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
# This error is raised when `Types::ISO8601Duration` is asked to return a value
|
4
|
+
# that cannot be parsed as an ISO8601-formatted duration by ActiveSupport::Duration.
|
5
|
+
#
|
6
|
+
# @see GraphQL::Types::ISO8601Duration which raises this error
|
7
|
+
class DurationEncodingError < GraphQL::RuntimeTypeError
|
8
|
+
# The value which couldn't be encoded
|
9
|
+
attr_reader :duration_value
|
10
|
+
|
11
|
+
def initialize(value)
|
12
|
+
@duration_value = value
|
13
|
+
super("Duration cannot be parsed: #{value}. \nDuration must be an ISO8601-formatted duration.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|