graphql 2.6.11 → 2.6.13
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/.rdoc_options +4 -0
- data/lib/generators/graphql/core.rb +1 -0
- data/lib/generators/graphql/detailed_trace_generator.rb +1 -0
- data/lib/generators/graphql/enum_generator.rb +1 -0
- data/lib/generators/graphql/field_extractor.rb +1 -0
- data/lib/generators/graphql/input_generator.rb +1 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +1 -0
- data/lib/generators/graphql/install_generator.rb +1 -0
- data/lib/generators/graphql/interface_generator.rb +1 -0
- data/lib/generators/graphql/loader_generator.rb +8 -2
- data/lib/generators/graphql/mutation_create_generator.rb +8 -2
- data/lib/generators/graphql/mutation_delete_generator.rb +8 -2
- data/lib/generators/graphql/mutation_generator.rb +8 -2
- data/lib/generators/graphql/mutation_update_generator.rb +8 -2
- data/lib/generators/graphql/object_generator.rb +1 -0
- data/lib/generators/graphql/orm_mutations_base.rb +8 -2
- data/lib/generators/graphql/relay.rb +1 -0
- data/lib/generators/graphql/relay_generator.rb +1 -0
- data/lib/generators/graphql/scalar_generator.rb +1 -0
- data/lib/generators/graphql/type_generator.rb +38 -8
- data/lib/generators/graphql/union_generator.rb +1 -0
- data/lib/graphql/analysis/analyzer.rb +35 -9
- data/lib/graphql/analysis/field_usage.rb +1 -0
- data/lib/graphql/analysis/max_query_complexity.rb +2 -1
- data/lib/graphql/analysis/max_query_depth.rb +1 -0
- data/lib/graphql/analysis/query_complexity.rb +57 -20
- data/lib/graphql/analysis/query_depth.rb +17 -12
- data/lib/graphql/analysis/visitor.rb +79 -16
- data/lib/graphql/analysis.rb +23 -6
- data/lib/graphql/analysis_error.rb +1 -0
- data/lib/graphql/autoload.rb +30 -7
- data/lib/graphql/backtrace/table.rb +21 -5
- data/lib/graphql/backtrace/traced_error.rb +8 -3
- data/lib/graphql/backtrace.rb +14 -9
- data/lib/graphql/coercion_error.rb +1 -0
- data/lib/graphql/current.rb +44 -19
- data/lib/graphql/dashboard/application_controller.rb +1 -0
- data/lib/graphql/dashboard/detailed_traces.rb +1 -0
- data/lib/graphql/dashboard/installable.rb +1 -0
- data/lib/graphql/dashboard/landings_controller.rb +1 -0
- data/lib/graphql/dashboard/limiters.rb +1 -0
- data/lib/graphql/dashboard/operation_store.rb +1 -0
- data/lib/graphql/dashboard/statics_controller.rb +1 -0
- data/lib/graphql/dashboard/subscriptions.rb +1 -0
- data/lib/graphql/dashboard.rb +36 -22
- data/lib/graphql/dataloader/active_record_association_source.rb +1 -0
- data/lib/graphql/dataloader/active_record_source.rb +1 -0
- data/lib/graphql/dataloader/async_dataloader.rb +10 -7
- data/lib/graphql/dataloader/null_dataloader.rb +4 -3
- data/lib/graphql/dataloader/request.rb +8 -2
- data/lib/graphql/dataloader/request_all.rb +8 -2
- data/lib/graphql/dataloader/source.rb +127 -35
- data/lib/graphql/dataloader.rb +93 -42
- data/lib/graphql/date_encoding_error.rb +2 -1
- data/lib/graphql/dig.rb +12 -3
- data/lib/graphql/duration_encoding_error.rb +2 -1
- data/lib/graphql/execution/directive_checks.rb +8 -3
- data/lib/graphql/execution/errors.rb +20 -6
- data/lib/graphql/execution/field_resolve_step.rb +40 -13
- data/lib/graphql/execution/finalize.rb +12 -6
- data/lib/graphql/execution/input_values.rb +2 -1
- data/lib/graphql/execution/interpreter/argument_value.rb +17 -5
- data/lib/graphql/execution/interpreter/arguments.rb +24 -9
- data/lib/graphql/execution/interpreter/arguments_cache.rb +2 -1
- data/lib/graphql/execution/interpreter/execution_errors.rb +1 -0
- data/lib/graphql/execution/interpreter/handles_raw_value.rb +1 -0
- data/lib/graphql/execution/interpreter/resolve.rb +18 -8
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +4 -1
- data/lib/graphql/execution/interpreter/runtime.rb +72 -25
- data/lib/graphql/execution/interpreter.rb +15 -6
- data/lib/graphql/execution/lazy/lazy_method_map.rb +21 -8
- data/lib/graphql/execution/lazy.rb +34 -10
- data/lib/graphql/execution/load_argument_step.rb +1 -0
- data/lib/graphql/execution/lookahead.rb +137 -54
- data/lib/graphql/execution/multiplex.rb +4 -4
- data/lib/graphql/execution/next.rb +7 -0
- data/lib/graphql/execution/prepare_object_step.rb +1 -0
- data/lib/graphql/execution/resolve_type_step.rb +2 -1
- data/lib/graphql/execution/runner.rb +9 -3
- data/lib/graphql/execution/selections_step.rb +3 -2
- data/lib/graphql/execution.rb +2 -2
- data/lib/graphql/execution_error.rb +19 -10
- data/lib/graphql/float_decoding_error.rb +1 -0
- data/lib/graphql/float_encoding_error.rb +7 -2
- data/lib/graphql/integer_decoding_error.rb +2 -1
- data/lib/graphql/integer_encoding_error.rb +8 -3
- data/lib/graphql/introspection/base_object.rb +3 -1
- data/lib/graphql/introspection/directive_location_enum.rb +1 -0
- data/lib/graphql/introspection/directive_type.rb +1 -0
- data/lib/graphql/introspection/dynamic_fields.rb +1 -0
- data/lib/graphql/introspection/entry_points.rb +1 -0
- data/lib/graphql/introspection/enum_value_type.rb +1 -0
- data/lib/graphql/introspection/field_type.rb +1 -0
- data/lib/graphql/introspection/input_value_type.rb +1 -0
- data/lib/graphql/introspection/introspection_query.rb +1 -0
- data/lib/graphql/introspection/schema_type.rb +1 -0
- data/lib/graphql/introspection/type_kind_enum.rb +1 -0
- data/lib/graphql/introspection/type_type.rb +1 -0
- data/lib/graphql/introspection.rb +1 -0
- data/lib/graphql/invalid_name_error.rb +1 -0
- data/lib/graphql/invalid_null_error.rb +19 -6
- data/lib/graphql/language/block_string.rb +2 -1
- data/lib/graphql/language/cache.rb +10 -4
- data/lib/graphql/language/comment.rb +1 -0
- data/lib/graphql/language/definition_slice.rb +1 -0
- data/lib/graphql/language/document_from_schema_definition.rb +9 -10
- data/lib/graphql/language/generation.rb +23 -9
- data/lib/graphql/language/lexer.rb +5 -0
- data/lib/graphql/language/nodes.rb +2094 -419
- data/lib/graphql/language/parser.rb +24 -17
- data/lib/graphql/language/printer.rb +31 -16
- data/lib/graphql/language/sanitized_printer.rb +16 -5
- data/lib/graphql/language/static_visitor.rb +19 -4
- data/lib/graphql/language/visitor.rb +51 -29
- data/lib/graphql/language.rb +13 -7
- data/lib/graphql/load_application_object_failed_error.rb +14 -5
- data/lib/graphql/name_validator.rb +1 -0
- data/lib/graphql/pagination/active_record_relation_connection.rb +1 -0
- data/lib/graphql/pagination/array_connection.rb +20 -6
- data/lib/graphql/pagination/connection.rb +178 -48
- data/lib/graphql/pagination/connections.rb +21 -14
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -0
- data/lib/graphql/pagination/relation_connection.rb +123 -22
- data/lib/graphql/pagination/sequel_dataset_connection.rb +1 -0
- data/lib/graphql/pagination.rb +1 -0
- data/lib/graphql/parse_error.rb +1 -0
- data/lib/graphql/query/context/scoped_context.rb +2 -1
- data/lib/graphql/query/context.rb +106 -35
- data/lib/graphql/query/fingerprint.rb +15 -7
- data/lib/graphql/query/input_validation_result.rb +1 -0
- data/lib/graphql/query/null_context.rb +1 -0
- data/lib/graphql/query/partial.rb +28 -15
- data/lib/graphql/query/result.rb +15 -5
- data/lib/graphql/query/validation_pipeline.rb +16 -6
- data/lib/graphql/query/variable_validation_error.rb +1 -0
- data/lib/graphql/query/variables.rb +9 -2
- data/lib/graphql/query.rb +193 -49
- data/lib/graphql/railtie.rb +7 -3
- data/lib/graphql/rake_task/validate.rb +72 -17
- data/lib/graphql/rake_task.rb +55 -23
- data/lib/graphql/relay/range_add.rb +32 -21
- data/lib/graphql/relay.rb +1 -0
- data/lib/graphql/rubocop/graphql/base_cop.rb +1 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +9 -6
- data/lib/graphql/rubocop/graphql/default_required_true.rb +9 -6
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +12 -8
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +9 -5
- data/lib/graphql/rubocop.rb +1 -0
- data/lib/graphql/runtime_error.rb +1 -0
- data/lib/graphql/runtime_type_error.rb +1 -0
- data/lib/graphql/schema/addition.rb +18 -6
- data/lib/graphql/schema/always_visible.rb +1 -0
- data/lib/graphql/schema/argument.rb +265 -42
- data/lib/graphql/schema/base_64_encoder.rb +2 -2
- data/lib/graphql/schema/build_from_definition/resolve_map/default_resolve.rb +1 -0
- data/lib/graphql/schema/build_from_definition/resolve_map.rb +2 -2
- data/lib/graphql/schema/build_from_definition.rb +94 -27
- data/lib/graphql/schema/built_in_types.rb +1 -0
- data/lib/graphql/schema/directive/deprecated.rb +1 -0
- data/lib/graphql/schema/directive/feature.rb +39 -22
- data/lib/graphql/schema/directive/flagged.rb +6 -1
- data/lib/graphql/schema/directive/include.rb +1 -0
- data/lib/graphql/schema/directive/one_of.rb +1 -0
- data/lib/graphql/schema/directive/skip.rb +1 -0
- data/lib/graphql/schema/directive/specified_by.rb +1 -0
- data/lib/graphql/schema/directive/transform.rb +17 -8
- data/lib/graphql/schema/directive.rb +12 -7
- data/lib/graphql/schema/enum.rb +99 -38
- data/lib/graphql/schema/enum_value.rb +21 -13
- data/lib/graphql/schema/field/connection_extension.rb +10 -2
- data/lib/graphql/schema/field/scope_extension.rb +1 -0
- data/lib/graphql/schema/field.rb +621 -109
- data/lib/graphql/schema/field_extension.rb +89 -34
- data/lib/graphql/schema/find_inherited_value.rb +5 -3
- data/lib/graphql/schema/finder.rb +22 -8
- data/lib/graphql/schema/has_single_input_argument.rb +39 -6
- data/lib/graphql/schema/input_object.rb +40 -13
- data/lib/graphql/schema/interface.rb +33 -17
- data/lib/graphql/schema/introspection_system.rb +7 -3
- data/lib/graphql/schema/late_bound_type.rb +2 -2
- data/lib/graphql/schema/list.rb +15 -4
- data/lib/graphql/schema/loader.rb +23 -12
- data/lib/graphql/schema/member/base_dsl_methods.rb +58 -12
- data/lib/graphql/schema/member/build_type.rb +16 -5
- data/lib/graphql/schema/member/graphql_type_names.rb +10 -6
- data/lib/graphql/schema/member/has_arguments.rb +115 -48
- data/lib/graphql/schema/member/has_ast_node.rb +1 -0
- data/lib/graphql/schema/member/has_authorization.rb +5 -0
- data/lib/graphql/schema/member/has_dataloader.rb +91 -34
- data/lib/graphql/schema/member/has_deprecation_reason.rb +15 -2
- data/lib/graphql/schema/member/has_directives.rb +38 -10
- data/lib/graphql/schema/member/has_fields.rb +151 -70
- data/lib/graphql/schema/member/has_interfaces.rb +10 -2
- data/lib/graphql/schema/member/has_path.rb +14 -5
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +1 -0
- data/lib/graphql/schema/member/has_validators.rb +19 -4
- data/lib/graphql/schema/member/relay_shortcuts.rb +10 -2
- data/lib/graphql/schema/member/scoped.rb +14 -3
- data/lib/graphql/schema/member/type_system_helpers.rb +36 -6
- data/lib/graphql/schema/member/validates_input.rb +1 -0
- data/lib/graphql/schema/member.rb +9 -2
- data/lib/graphql/schema/mutation.rb +50 -46
- data/lib/graphql/schema/non_null.rb +21 -5
- data/lib/graphql/schema/object.rb +33 -12
- data/lib/graphql/schema/printer.rb +52 -31
- data/lib/graphql/schema/ractor_shareable.rb +6 -2
- data/lib/graphql/schema/relay_classic_mutation.rb +3 -3
- data/lib/graphql/schema/resolver/has_payload_type.rb +29 -7
- data/lib/graphql/schema/resolver.rb +156 -45
- data/lib/graphql/schema/scalar.rb +1 -0
- data/lib/graphql/schema/subscription.rb +67 -28
- data/lib/graphql/schema/timeout.rb +65 -25
- data/lib/graphql/schema/type_expression.rb +14 -5
- data/lib/graphql/schema/type_membership.rb +29 -10
- data/lib/graphql/schema/union.rb +4 -2
- data/lib/graphql/schema/unique_within_type.rb +24 -5
- data/lib/graphql/schema/validator/all_validator.rb +17 -9
- data/lib/graphql/schema/validator/allow_blank_validator.rb +8 -2
- data/lib/graphql/schema/validator/allow_null_validator.rb +8 -2
- data/lib/graphql/schema/validator/exclusion_validator.rb +14 -5
- data/lib/graphql/schema/validator/format_validator.rb +21 -10
- data/lib/graphql/schema/validator/inclusion_validator.rb +15 -6
- data/lib/graphql/schema/validator/length_validator.rb +23 -12
- data/lib/graphql/schema/validator/numericality_validator.rb +29 -16
- data/lib/graphql/schema/validator/required_validator.rb +45 -31
- data/lib/graphql/schema/validator.rb +89 -25
- data/lib/graphql/schema/visibility/migration.rb +14 -7
- data/lib/graphql/schema/visibility/profile.rb +65 -20
- data/lib/graphql/schema/visibility/visit.rb +12 -10
- data/lib/graphql/schema/visibility.rb +24 -20
- data/lib/graphql/schema/warden.rb +117 -31
- data/lib/graphql/schema/wrapper.rb +4 -1
- data/lib/graphql/schema.rb +1046 -300
- data/lib/graphql/static_validation/all_rules.rb +2 -1
- data/lib/graphql/static_validation/base_visitor.rb +59 -9
- data/lib/graphql/static_validation/definition_dependencies.rb +27 -7
- data/lib/graphql/static_validation/error.rb +3 -0
- data/lib/graphql/static_validation/interpreter_visitor.rb +1 -0
- data/lib/graphql/static_validation/literal_validator.rb +1 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +4 -0
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible_error.rb +1 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +3 -0
- data/lib/graphql/static_validation/rules/argument_names_are_unique_error.rb +1 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +3 -0
- data/lib/graphql/static_validation/rules/arguments_are_defined_error.rb +1 -0
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +3 -0
- data/lib/graphql/static_validation/rules/directives_are_defined_error.rb +1 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +3 -0
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +3 -0
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +9 -1
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +295 -134
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +14 -2
- data/lib/graphql/static_validation/rules/fragment_names_are_unique.rb +3 -0
- data/lib/graphql/static_validation/rules/fragment_names_are_unique_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -0
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +3 -0
- data/lib/graphql/static_validation/rules/fragment_types_exist_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +3 -0
- data/lib/graphql/static_validation/rules/fragments_are_finite_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fragments_are_named.rb +3 -0
- data/lib/graphql/static_validation/rules/fragments_are_named_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +3 -0
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types_error.rb +1 -0
- data/lib/graphql/static_validation/rules/fragments_are_used.rb +3 -0
- data/lib/graphql/static_validation/rules/fragments_are_used_error.rb +1 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique.rb +3 -0
- data/lib/graphql/static_validation/rules/input_object_names_are_unique_error.rb +1 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +3 -0
- data/lib/graphql/static_validation/rules/mutation_root_exists_error.rb +1 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +3 -0
- data/lib/graphql/static_validation/rules/no_definitions_are_present_error.rb +1 -0
- data/lib/graphql/static_validation/rules/not_single_subscription_error.rb +1 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +4 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +1 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid.rb +3 -0
- data/lib/graphql/static_validation/rules/operation_names_are_valid_error.rb +1 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +3 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +1 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +4 -1
- data/lib/graphql/static_validation/rules/required_arguments_are_present_error.rb +1 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +4 -0
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present_error.rb +1 -0
- data/lib/graphql/static_validation/rules/subscription_root_exists_and_single_subscription_selection.rb +43 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists_error.rb +1 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +3 -0
- data/lib/graphql/static_validation/rules/unique_directives_per_location_error.rb +1 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +3 -0
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed_error.rb +1 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +3 -0
- data/lib/graphql/static_validation/rules/variable_names_are_unique_error.rb +1 -0
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +207 -51
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed_error.rb +1 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +3 -0
- data/lib/graphql/static_validation/rules/variables_are_input_types_error.rb +1 -0
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined.rb +6 -3
- data/lib/graphql/static_validation/rules/variables_are_used_and_defined_error.rb +1 -0
- data/lib/graphql/static_validation/validation_context.rb +3 -2
- data/lib/graphql/static_validation/validation_timeout_error.rb +1 -0
- data/lib/graphql/static_validation/validator.rb +41 -16
- data/lib/graphql/static_validation.rb +1 -0
- data/lib/graphql/string_encoding_error.rb +1 -0
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +85 -65
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +10 -4
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +1 -0
- data/lib/graphql/subscriptions/event.rb +25 -6
- data/lib/graphql/subscriptions/serialize.rb +58 -19
- data/lib/graphql/subscriptions.rb +172 -46
- data/lib/graphql/testing/helpers.rb +17 -4
- data/lib/graphql/testing/mock_action_cable.rb +55 -33
- data/lib/graphql/testing.rb +1 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +17 -9
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +2 -1
- data/lib/graphql/tracing/appoptics_trace.rb +2 -1
- data/lib/graphql/tracing/appoptics_tracing.rb +2 -1
- data/lib/graphql/tracing/appsignal_trace.rb +16 -7
- data/lib/graphql/tracing/appsignal_tracing.rb +7 -3
- data/lib/graphql/tracing/call_legacy_tracers.rb +1 -0
- data/lib/graphql/tracing/data_dog_trace.rb +17 -6
- data/lib/graphql/tracing/data_dog_tracing.rb +10 -3
- data/lib/graphql/tracing/detailed_trace/active_record_backend.rb +1 -0
- data/lib/graphql/tracing/detailed_trace/memory_backend.rb +1 -0
- data/lib/graphql/tracing/detailed_trace/redis_backend.rb +1 -0
- data/lib/graphql/tracing/detailed_trace.rb +105 -42
- data/lib/graphql/tracing/legacy_hooks_trace.rb +5 -0
- data/lib/graphql/tracing/legacy_trace.rb +1 -0
- data/lib/graphql/tracing/monitor_trace.rb +17 -11
- data/lib/graphql/tracing/new_relic_trace.rb +17 -8
- data/lib/graphql/tracing/new_relic_tracing.rb +7 -3
- data/lib/graphql/tracing/notifications_trace.rb +11 -8
- data/lib/graphql/tracing/notifications_tracing.rb +23 -7
- data/lib/graphql/tracing/null_trace.rb +1 -0
- data/lib/graphql/tracing/perfetto_trace/trace_pb.rb +1 -0
- data/lib/graphql/tracing/perfetto_trace.rb +41 -19
- data/lib/graphql/tracing/platform_trace.rb +3 -1
- data/lib/graphql/tracing/platform_tracing.rb +16 -7
- data/lib/graphql/tracing/prometheus_trace/graphql_collector.rb +1 -0
- data/lib/graphql/tracing/prometheus_trace.rb +22 -13
- data/lib/graphql/tracing/prometheus_tracing.rb +1 -0
- data/lib/graphql/tracing/scout_trace.rb +10 -4
- data/lib/graphql/tracing/scout_tracing.rb +7 -3
- data/lib/graphql/tracing/sentry_trace.rb +12 -5
- data/lib/graphql/tracing/statsd_trace.rb +12 -6
- data/lib/graphql/tracing/statsd_tracing.rb +7 -1
- data/lib/graphql/tracing/trace.rb +231 -58
- data/lib/graphql/tracing.rb +25 -9
- data/lib/graphql/type_kinds.rb +2 -1
- data/lib/graphql/types/big_int.rb +1 -0
- data/lib/graphql/types/boolean.rb +1 -0
- data/lib/graphql/types/float.rb +1 -0
- data/lib/graphql/types/id.rb +1 -0
- data/lib/graphql/types/int.rb +2 -1
- data/lib/graphql/types/iso_8601_date.rb +21 -4
- data/lib/graphql/types/iso_8601_date_time.rb +33 -6
- data/lib/graphql/types/iso_8601_duration.rb +42 -9
- data/lib/graphql/types/json.rb +1 -0
- data/lib/graphql/types/relay/base_connection.rb +38 -32
- data/lib/graphql/types/relay/base_edge.rb +15 -9
- data/lib/graphql/types/relay/connection_behaviors.rb +19 -3
- data/lib/graphql/types/relay/edge_behaviors.rb +17 -4
- data/lib/graphql/types/relay/has_node_field.rb +6 -1
- data/lib/graphql/types/relay/has_nodes_field.rb +6 -1
- data/lib/graphql/types/relay/node.rb +1 -0
- data/lib/graphql/types/relay/node_behaviors.rb +5 -1
- data/lib/graphql/types/relay/page_info.rb +1 -0
- data/lib/graphql/types/relay/page_info_behaviors.rb +1 -0
- data/lib/graphql/types/relay.rb +4 -3
- data/lib/graphql/types/string.rb +1 -0
- data/lib/graphql/types.rb +1 -0
- data/lib/graphql/unauthorized_enum_value_error.rb +4 -1
- data/lib/graphql/unauthorized_error.rb +11 -4
- data/lib/graphql/unauthorized_field_error.rb +4 -1
- data/lib/graphql/unresolved_type_error.rb +16 -5
- data/lib/graphql/version.rb +2 -1
- data/lib/graphql.rb +37 -9
- data/readme.md +1 -1
- metadata +89 -5
- data/.yardopts +0 -5
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
2
3
|
|
|
3
4
|
module GraphQL
|
|
4
5
|
class Dataloader
|
|
@@ -23,8 +24,7 @@ module GraphQL
|
|
|
23
24
|
create_pending_run
|
|
24
25
|
end
|
|
25
26
|
|
|
26
|
-
#
|
|
27
|
-
attr_reader :pending_sources
|
|
27
|
+
attr_reader :pending_sources # :nodoc:
|
|
28
28
|
|
|
29
29
|
def create_pending_run
|
|
30
30
|
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
|
@@ -206,7 +206,7 @@ module GraphQL
|
|
|
206
206
|
|
|
207
207
|
def run_isolated
|
|
208
208
|
previous_run = current_task_run
|
|
209
|
-
prev_pending_keys = {}
|
|
209
|
+
prev_pending_keys = {} #: Hash[GraphQL::Dataloader::Source, Hash[untyped, untyped]]
|
|
210
210
|
# Clear pending loads but keep already-cached records
|
|
211
211
|
# in case they are useful to the given block.
|
|
212
212
|
@source_cache.each do |source_class, batched_sources|
|
|
@@ -218,7 +218,7 @@ module GraphQL
|
|
|
218
218
|
end
|
|
219
219
|
end
|
|
220
220
|
|
|
221
|
-
res = nil
|
|
221
|
+
res = nil #: untyped
|
|
222
222
|
create_pending_run
|
|
223
223
|
@pending_run.jobs << -> { res = yield }
|
|
224
224
|
run
|
|
@@ -229,6 +229,7 @@ module GraphQL
|
|
|
229
229
|
# clear the one created in #run:
|
|
230
230
|
@pending_run = nil
|
|
231
231
|
end
|
|
232
|
+
prev_pending_keys = prev_pending_keys #: as !nil
|
|
232
233
|
prev_pending_keys.each do |source_instance, pending|
|
|
233
234
|
pending.each do |key, value|
|
|
234
235
|
next if source_instance.results.key?(key)
|
|
@@ -244,16 +245,18 @@ module GraphQL
|
|
|
244
245
|
run = @pending_run || current_task_run || raise(GraphQL::Error, "No available Run, GraphQL-Ruby internal bug")
|
|
245
246
|
@pending_run = nil
|
|
246
247
|
run.trace = trace
|
|
247
|
-
first_pass = true
|
|
248
|
+
first_pass = true #: bool
|
|
248
249
|
trace&.begin_dataloader(self)
|
|
249
250
|
fiber_vars = get_fiber_variables
|
|
250
|
-
raised_error = nil
|
|
251
|
+
raised_error = nil #: StandardError?
|
|
251
252
|
jobs = run.jobs
|
|
252
253
|
Sync do |_maybe_new_task|
|
|
253
254
|
# Make sure there's a new task instance to hold `.graphql_...` state:
|
|
254
255
|
task = Async::Task.new do |root_task|
|
|
255
256
|
run.root_task = root_task
|
|
256
257
|
root_task.graphql_async_dataloader_run = run
|
|
258
|
+
# Tasks inherit the spawning fiber's storage; give this run its own execution state.
|
|
259
|
+
Fiber[:__graphql_runtime_info] = nil
|
|
257
260
|
set_fiber_variables(fiber_vars)
|
|
258
261
|
|
|
259
262
|
while first_pass || run.running? || !jobs.empty?
|
|
@@ -289,7 +292,7 @@ module GraphQL
|
|
|
289
292
|
private
|
|
290
293
|
|
|
291
294
|
def run_queue(run, condition, mode)
|
|
292
|
-
opened_queues = false
|
|
295
|
+
opened_queues = false #: bool
|
|
293
296
|
|
|
294
297
|
if condition.waiting?
|
|
295
298
|
opened_queues = true
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
2
3
|
|
|
3
4
|
module GraphQL
|
|
4
5
|
class Dataloader
|
|
5
6
|
# GraphQL-Ruby uses this when Dataloader isn't enabled.
|
|
6
7
|
#
|
|
7
8
|
# It runs execution code inline and gathers lazy objects (eg. Promises)
|
|
8
|
-
# and resolves them during
|
|
9
|
+
# and resolves them during [run](rdoc-ref:#run).
|
|
9
10
|
class NullDataloader < Dataloader
|
|
10
11
|
def initialize(*)
|
|
11
12
|
@lazies_at_depth = Hash.new { |h,k| h[k] = [] }
|
|
@@ -20,7 +21,7 @@ module GraphQL
|
|
|
20
21
|
def run(trace_query_lazy: nil)
|
|
21
22
|
with_trace_query_lazy(trace_query_lazy) do
|
|
22
23
|
while !@lazies_at_depth.empty?
|
|
23
|
-
smallest_depth = nil
|
|
24
|
+
smallest_depth = nil #: Integer?
|
|
24
25
|
@lazies_at_depth.each_key do |depth_key|
|
|
25
26
|
smallest_depth ||= depth_key
|
|
26
27
|
if depth_key < smallest_depth
|
|
@@ -40,7 +41,7 @@ module GraphQL
|
|
|
40
41
|
# Reuse this instance because execution code may already have a reference to _this_ `dataloader` inside the given block.
|
|
41
42
|
prev_lazies_at_depth = @lazies_at_depth
|
|
42
43
|
@lazies_at_depth = @lazies_at_depth.dup.clear
|
|
43
|
-
res = nil
|
|
44
|
+
res = nil #: untyped
|
|
44
45
|
append_job {
|
|
45
46
|
res = yield
|
|
46
47
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
2
3
|
module GraphQL
|
|
3
4
|
class Dataloader
|
|
4
|
-
#
|
|
5
|
+
# See [Source#request](rdoc-ref:Source#request) which returns an instance of this
|
|
5
6
|
class Request
|
|
6
7
|
def initialize(source, key)
|
|
7
8
|
@source = source
|
|
@@ -10,7 +11,12 @@ module GraphQL
|
|
|
10
11
|
|
|
11
12
|
# Call this method to cause the current Fiber to wait for the results of this request.
|
|
12
13
|
#
|
|
13
|
-
#
|
|
14
|
+
# **Returns**
|
|
15
|
+
#
|
|
16
|
+
# - `Object` — the object loaded for `key`
|
|
17
|
+
#
|
|
18
|
+
# :call-seq:
|
|
19
|
+
# load() -> Object
|
|
14
20
|
def load
|
|
15
21
|
@source.load(@key)
|
|
16
22
|
end
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
2
3
|
module GraphQL
|
|
3
4
|
class Dataloader
|
|
4
|
-
#
|
|
5
|
+
# See [Source#request_all](rdoc-ref:Source#request_all) which returns an instance of this.
|
|
5
6
|
class RequestAll < Request
|
|
6
7
|
def initialize(source, keys)
|
|
7
8
|
@source = source
|
|
@@ -10,7 +11,12 @@ module GraphQL
|
|
|
10
11
|
|
|
11
12
|
# Call this method to cause the current Fiber to wait for the results of this request.
|
|
12
13
|
#
|
|
13
|
-
#
|
|
14
|
+
# **Returns**
|
|
15
|
+
#
|
|
16
|
+
# - `Array<Object>` — One object for each of `keys`
|
|
17
|
+
#
|
|
18
|
+
# :call-seq:
|
|
19
|
+
# load() -> Array[Object]
|
|
14
20
|
def load
|
|
15
21
|
@source.load_all(@keys)
|
|
16
22
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
2
3
|
|
|
3
4
|
module GraphQL
|
|
4
5
|
class Dataloader
|
|
5
6
|
class Source
|
|
6
|
-
# Called by
|
|
7
|
-
#
|
|
8
|
-
def setup(dataloader)
|
|
7
|
+
# Called by [Dataloader](rdoc-ref:Dataloader) to prepare the [Source](rdoc-ref:Source)'s internal state
|
|
8
|
+
def setup(dataloader) # :nodoc:
|
|
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
|
|
@@ -17,7 +17,12 @@ module GraphQL
|
|
|
17
17
|
|
|
18
18
|
attr_reader :dataloader
|
|
19
19
|
|
|
20
|
-
#
|
|
20
|
+
# **Returns**
|
|
21
|
+
#
|
|
22
|
+
# - `Dataloader::Request` — a pending request for a value from `key`. Call `.load` on that object to wait for the result.
|
|
23
|
+
#
|
|
24
|
+
# :call-seq:
|
|
25
|
+
# request(value) -> Dataloader::Request
|
|
21
26
|
def request(value)
|
|
22
27
|
res_key = result_key_for(value)
|
|
23
28
|
add_pending_key(res_key, value)
|
|
@@ -27,25 +32,46 @@ module GraphQL
|
|
|
27
32
|
# Implement this method to return a stable identifier if different
|
|
28
33
|
# key objects should load the same data value.
|
|
29
34
|
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
35
|
+
# **Parameters**
|
|
36
|
+
#
|
|
37
|
+
# - `value` (`Object`) — A value passed to `.request` or `.load`, for which a value will be loaded
|
|
38
|
+
#
|
|
39
|
+
# **Returns**
|
|
40
|
+
#
|
|
41
|
+
# - `Object` — The key for tracking this pending data
|
|
42
|
+
#
|
|
43
|
+
# :call-seq:
|
|
44
|
+
# result_key_for(Object value) -> Object
|
|
32
45
|
def result_key_for(value)
|
|
33
46
|
value
|
|
34
47
|
end
|
|
35
48
|
|
|
36
|
-
# Implement this method if varying values given to
|
|
37
|
-
# or normalized before being handed off to your
|
|
49
|
+
# Implement this method if varying values given to [load](rdoc-ref:load) (etc) should be consolidated
|
|
50
|
+
# or normalized before being handed off to your [fetch](rdoc-ref:fetch) implementation.
|
|
38
51
|
#
|
|
39
|
-
# This is different than
|
|
40
|
-
# but this method changes the value passed into
|
|
52
|
+
# This is different than [result_key_for](rdoc-ref:result_key_for) because _that_ method handles unification inside Dataloader's cache,
|
|
53
|
+
# but this method changes the value passed into [fetch](rdoc-ref:fetch).
|
|
41
54
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
55
|
+
# **Parameters**
|
|
56
|
+
#
|
|
57
|
+
# - `value` (`Object`) — The value passed to [load](rdoc-ref:load), [load_all](rdoc-ref:load_all), [request](rdoc-ref:request), or [request_all](rdoc-ref:request_all)
|
|
58
|
+
#
|
|
59
|
+
# **Returns**
|
|
60
|
+
#
|
|
61
|
+
# - `Object` — The value given to [fetch](rdoc-ref:fetch)
|
|
62
|
+
#
|
|
63
|
+
# :call-seq:
|
|
64
|
+
# normalize_fetch_key(Object value) -> Object
|
|
44
65
|
def normalize_fetch_key(value)
|
|
45
66
|
value
|
|
46
67
|
end
|
|
47
68
|
|
|
48
|
-
#
|
|
69
|
+
# **Returns**
|
|
70
|
+
#
|
|
71
|
+
# - `Dataloader::Request` — a pending request for a values from `keys`. Call `.load` on that object to wait for the results.
|
|
72
|
+
#
|
|
73
|
+
# :call-seq:
|
|
74
|
+
# request_all(values) -> Dataloader::Request
|
|
49
75
|
def request_all(values)
|
|
50
76
|
values.each do |v|
|
|
51
77
|
res_key = result_key_for(v)
|
|
@@ -54,8 +80,16 @@ module GraphQL
|
|
|
54
80
|
Dataloader::RequestAll.new(self, values)
|
|
55
81
|
end
|
|
56
82
|
|
|
57
|
-
#
|
|
58
|
-
#
|
|
83
|
+
# **Parameters**
|
|
84
|
+
#
|
|
85
|
+
# - `value` (`Object`) — A loading value which will be passed to [fetch](rdoc-ref:#fetch) if it isn't already in the internal cache.
|
|
86
|
+
#
|
|
87
|
+
# **Returns**
|
|
88
|
+
#
|
|
89
|
+
# - `Object` — The result from [fetch](rdoc-ref:#fetch) for `key`. If `key` hasn't been loaded yet, the Fiber will yield until it's loaded.
|
|
90
|
+
#
|
|
91
|
+
# :call-seq:
|
|
92
|
+
# load(Object value) -> Object
|
|
59
93
|
def load(value)
|
|
60
94
|
result_key = result_key_for(value)
|
|
61
95
|
if @results.key?(result_key)
|
|
@@ -67,8 +101,16 @@ module GraphQL
|
|
|
67
101
|
end
|
|
68
102
|
end
|
|
69
103
|
|
|
70
|
-
#
|
|
71
|
-
#
|
|
104
|
+
# **Parameters**
|
|
105
|
+
#
|
|
106
|
+
# - `values` (`Array<Object>`) — Loading keys which will be passed to `#fetch` (or read from the internal cache).
|
|
107
|
+
#
|
|
108
|
+
# **Returns**
|
|
109
|
+
#
|
|
110
|
+
# - `Object` — The result from [fetch](rdoc-ref:#fetch) for `keys`. If `keys` haven't been loaded yet, the Fiber will yield until they're loaded.
|
|
111
|
+
#
|
|
112
|
+
# :call-seq:
|
|
113
|
+
# load_all(Array[Object] values) -> Object
|
|
72
114
|
def load_all(values)
|
|
73
115
|
result_keys = []
|
|
74
116
|
pending_keys = []
|
|
@@ -89,8 +131,17 @@ module GraphQL
|
|
|
89
131
|
end
|
|
90
132
|
|
|
91
133
|
# Subclasses must implement this method to return a value for each of `keys`
|
|
92
|
-
#
|
|
93
|
-
#
|
|
134
|
+
#
|
|
135
|
+
# **Parameters**
|
|
136
|
+
#
|
|
137
|
+
# - `keys` (`Array<Object>`) — keys passed to [load](rdoc-ref:#load), [load all](rdoc-ref:#load_all), [request](rdoc-ref:#request), or [request all](rdoc-ref:#request_all)
|
|
138
|
+
#
|
|
139
|
+
# **Returns**
|
|
140
|
+
#
|
|
141
|
+
# - `Array<Object>` — A loaded value for each of `keys`. The array must match one-for-one to the list of `keys`.
|
|
142
|
+
#
|
|
143
|
+
# :call-seq:
|
|
144
|
+
# fetch(Array[Object] keys) -> Array[Object]
|
|
94
145
|
def fetch(keys)
|
|
95
146
|
# somehow retrieve these from the backend
|
|
96
147
|
raise "Implement `#{self.class}#fetch(#{keys.inspect}) to return a record for each of the keys"
|
|
@@ -99,7 +150,13 @@ module GraphQL
|
|
|
99
150
|
MAX_ITERATIONS = 1000
|
|
100
151
|
# Wait for a batch, if there's anything to batch.
|
|
101
152
|
# Then run the batch and update the cache.
|
|
102
|
-
#
|
|
153
|
+
#
|
|
154
|
+
# **Returns**
|
|
155
|
+
#
|
|
156
|
+
# - `void`
|
|
157
|
+
#
|
|
158
|
+
# :call-seq:
|
|
159
|
+
# sync(pending_result_keys) -> void
|
|
103
160
|
def sync(pending_result_keys)
|
|
104
161
|
@dataloader.queue_pending_source(self) if pending?
|
|
105
162
|
@dataloader.yield(self)
|
|
@@ -114,15 +171,29 @@ module GraphQL
|
|
|
114
171
|
nil
|
|
115
172
|
end
|
|
116
173
|
|
|
117
|
-
#
|
|
174
|
+
# **Returns**
|
|
175
|
+
#
|
|
176
|
+
# - `Boolean` — True if this source has any pending requests for data.
|
|
177
|
+
#
|
|
178
|
+
# :call-seq:
|
|
179
|
+
# pending?() -> bool
|
|
118
180
|
def pending?
|
|
119
181
|
!@pending.empty?
|
|
120
182
|
end
|
|
121
183
|
|
|
122
184
|
# Add these key-value pairs to this source's cache
|
|
123
185
|
# (future loads will use these merged values).
|
|
124
|
-
#
|
|
125
|
-
#
|
|
186
|
+
#
|
|
187
|
+
# **Parameters**
|
|
188
|
+
#
|
|
189
|
+
# - `new_results` (`Hash<Object => Object>`) — key-value pairs to cache in this source
|
|
190
|
+
#
|
|
191
|
+
# **Returns**
|
|
192
|
+
#
|
|
193
|
+
# - `void`
|
|
194
|
+
#
|
|
195
|
+
# :call-seq:
|
|
196
|
+
# merge(Hash[Object, Object] new_results) -> void
|
|
126
197
|
def merge(new_results)
|
|
127
198
|
new_results.each do |new_k, new_v|
|
|
128
199
|
key = result_key_for(new_k)
|
|
@@ -131,10 +202,12 @@ module GraphQL
|
|
|
131
202
|
nil
|
|
132
203
|
end
|
|
133
204
|
|
|
134
|
-
# Called by
|
|
135
|
-
#
|
|
136
|
-
#
|
|
137
|
-
|
|
205
|
+
# Called by [GraphQL::Dataloader](rdoc-ref:GraphQL::Dataloader) to resolve and pending requests to this source.
|
|
206
|
+
#
|
|
207
|
+
# **Returns**
|
|
208
|
+
#
|
|
209
|
+
# - `void`
|
|
210
|
+
def run_pending_keys # :nodoc:
|
|
138
211
|
@fetching.each_key { |k| @pending.delete(k) }
|
|
139
212
|
return if @pending.empty?
|
|
140
213
|
fetch_h = @pending
|
|
@@ -167,9 +240,17 @@ module GraphQL
|
|
|
167
240
|
# this method to call `.to_sql` on them, thus merging `.load(...)` calls when they apply
|
|
168
241
|
# to equivalent relations.
|
|
169
242
|
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
#
|
|
243
|
+
# **Parameters**
|
|
244
|
+
#
|
|
245
|
+
# - `batch_args` (`Array<Object>`)
|
|
246
|
+
# - `batch_kwargs` (`Hash`)
|
|
247
|
+
#
|
|
248
|
+
# **Returns**
|
|
249
|
+
#
|
|
250
|
+
# - `Object`
|
|
251
|
+
#
|
|
252
|
+
# :call-seq:
|
|
253
|
+
# batch_key_for(Array[Object] *batch_args, Hash **batch_kwargs) -> Object
|
|
173
254
|
def self.batch_key_for(*batch_args, **batch_kwargs)
|
|
174
255
|
if batch_kwargs.any? # rubocop:disable Development/NoneWithoutBlockCop
|
|
175
256
|
[*batch_args, **batch_kwargs]
|
|
@@ -179,7 +260,13 @@ module GraphQL
|
|
|
179
260
|
end
|
|
180
261
|
|
|
181
262
|
# Clear any already-loaded objects for this source
|
|
182
|
-
#
|
|
263
|
+
#
|
|
264
|
+
# **Returns**
|
|
265
|
+
#
|
|
266
|
+
# - `void`
|
|
267
|
+
#
|
|
268
|
+
# :call-seq:
|
|
269
|
+
# clear_cache() -> void
|
|
183
270
|
def clear_cache
|
|
184
271
|
@results.clear
|
|
185
272
|
nil
|
|
@@ -199,10 +286,15 @@ module GraphQL
|
|
|
199
286
|
end
|
|
200
287
|
|
|
201
288
|
# Reads and returns the result for the key from the internal cache, or raises an error if the result was an error
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
|
|
289
|
+
#
|
|
290
|
+
# **Parameters**
|
|
291
|
+
#
|
|
292
|
+
# - `key` (`Object`) — key passed to [load](rdoc-ref:#load) or [load all](rdoc-ref:#load_all)
|
|
293
|
+
#
|
|
294
|
+
# **Returns**
|
|
295
|
+
#
|
|
296
|
+
# - `Object` — The result from [fetch](rdoc-ref:#fetch) for `key`.
|
|
297
|
+
def result_for(key) # :nodoc:
|
|
206
298
|
if !@results.key?(key)
|
|
207
299
|
raise GraphQL::InvariantError, <<-ERR
|
|
208
300
|
Fetching result for a key on #{self.class} that hasn't been loaded yet (#{key.inspect}, loaded: #{@results.keys})
|
data/lib/graphql/dataloader.rb
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
# typed: true
|
|
2
3
|
|
|
3
4
|
require "graphql/dataloader/null_dataloader"
|
|
4
5
|
require "graphql/dataloader/request"
|
|
@@ -8,22 +9,27 @@ require "graphql/dataloader/active_record_association_source"
|
|
|
8
9
|
require "graphql/dataloader/active_record_source"
|
|
9
10
|
|
|
10
11
|
module GraphQL
|
|
11
|
-
# This plugin supports Fiber-based concurrency, along with
|
|
12
|
+
# This plugin supports Fiber-based concurrency, along with [GraphQL::Dataloader::Source](rdoc-ref:GraphQL::Dataloader::Source).
|
|
12
13
|
#
|
|
13
|
-
#
|
|
14
|
+
# **Examples**
|
|
14
15
|
#
|
|
15
|
-
#
|
|
16
|
-
# use GraphQL::Dataloader
|
|
17
|
-
# end
|
|
16
|
+
# **Example: Installing Dataloader**
|
|
18
17
|
#
|
|
19
|
-
#
|
|
18
|
+
# ```ruby
|
|
19
|
+
# class MySchema < GraphQL::Schema
|
|
20
|
+
# use GraphQL::Dataloader
|
|
21
|
+
# end
|
|
22
|
+
# ```
|
|
20
23
|
#
|
|
21
|
-
#
|
|
24
|
+
# **Example: Waiting for batch-loaded data in a GraphQL field**
|
|
22
25
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# end
|
|
26
|
+
# ```ruby
|
|
27
|
+
# field :team, Types::Team, null: true
|
|
26
28
|
#
|
|
29
|
+
# def team
|
|
30
|
+
# dataloader.with(Sources::Record, Team).load(object.team_id)
|
|
31
|
+
# end
|
|
32
|
+
# ```
|
|
27
33
|
class Dataloader
|
|
28
34
|
class << self
|
|
29
35
|
attr_accessor :default_nonblocking, :default_fiber_limit
|
|
@@ -49,7 +55,7 @@ module GraphQL
|
|
|
49
55
|
# then run all enqueued jobs and return the result of the block.
|
|
50
56
|
def self.with_dataloading(&block)
|
|
51
57
|
dataloader = self.new
|
|
52
|
-
result = nil
|
|
58
|
+
result = nil #: untyped
|
|
53
59
|
dataloader.append_job {
|
|
54
60
|
result = block.call(dataloader)
|
|
55
61
|
}
|
|
@@ -69,7 +75,9 @@ module GraphQL
|
|
|
69
75
|
@lazies_at_depth = Hash.new { |h, k| h[k] = [] }
|
|
70
76
|
end
|
|
71
77
|
|
|
72
|
-
#
|
|
78
|
+
# **Returns**
|
|
79
|
+
#
|
|
80
|
+
# - `Integer, nil`
|
|
73
81
|
attr_reader :fiber_limit
|
|
74
82
|
|
|
75
83
|
def nonblocking?
|
|
@@ -79,7 +87,12 @@ module GraphQL
|
|
|
79
87
|
# This is called before the fiber is spawned, from the parent context (i.e. from
|
|
80
88
|
# the thread or fiber that it is scheduled from).
|
|
81
89
|
#
|
|
82
|
-
#
|
|
90
|
+
# **Returns**
|
|
91
|
+
#
|
|
92
|
+
# - `Hash<Symbol, Object>` — Current fiber-local variables
|
|
93
|
+
#
|
|
94
|
+
# :call-seq:
|
|
95
|
+
# get_fiber_variables() -> Hash[Symbol, Object]
|
|
83
96
|
def get_fiber_variables
|
|
84
97
|
fiber_vars = {}
|
|
85
98
|
Thread.current.keys.each do |fiber_var_key|
|
|
@@ -92,8 +105,16 @@ module GraphQL
|
|
|
92
105
|
#
|
|
93
106
|
# This is called within the fiber, right after it is spawned.
|
|
94
107
|
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
108
|
+
# **Parameters**
|
|
109
|
+
#
|
|
110
|
+
# - `vars` (`Hash<Symbol, Object>`) — Fiber-local variables from [get_fiber_variables](rdoc-ref:get_fiber_variables)
|
|
111
|
+
#
|
|
112
|
+
# **Returns**
|
|
113
|
+
#
|
|
114
|
+
# - `void`
|
|
115
|
+
#
|
|
116
|
+
# :call-seq:
|
|
117
|
+
# set_fiber_variables(Hash[Symbol, Object] vars) -> void
|
|
97
118
|
def set_fiber_variables(vars)
|
|
98
119
|
vars.each { |k, v| Thread.current[k] = v }
|
|
99
120
|
nil
|
|
@@ -106,12 +127,17 @@ module GraphQL
|
|
|
106
127
|
|
|
107
128
|
# Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
|
|
108
129
|
#
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
#
|
|
112
|
-
#
|
|
130
|
+
# **Parameters**
|
|
131
|
+
#
|
|
132
|
+
# - `source_class` (`Class<GraphQL::Dataloader::Source>`) — The source class to load
|
|
133
|
+
# - `batch_parameters` (`Array<Object>`)
|
|
134
|
+
#
|
|
135
|
+
# **Returns**
|
|
136
|
+
#
|
|
137
|
+
# - `GraphQL::Dataloader::Source` — An instance of [source_class](rdoc-ref:source_class), initialized with `self, *batch_parameters`, and cached for the lifetime of this [Multiplex](rdoc-ref:Multiplex).
|
|
113
138
|
if (RUBY_ENGINE == "ruby" && RUBY_VERSION < "3") || RUBY_ENGINE == "truffleruby" # truffle-ruby wasn't doing well with the implementation below
|
|
114
|
-
|
|
139
|
+
# `define_method` so that Sorbet doesn't see this as a conflicting definition of `#with`
|
|
140
|
+
define_method(:with) do |source_class, *batch_args|
|
|
115
141
|
batch_key = source_class.batch_key_for(*batch_args)
|
|
116
142
|
@source_cache[source_class][batch_key] ||= begin
|
|
117
143
|
source = source_class.new(*batch_args)
|
|
@@ -133,7 +159,12 @@ module GraphQL
|
|
|
133
159
|
#
|
|
134
160
|
# Dataloader will resume the fiber after the requested data has been loaded (by another Fiber).
|
|
135
161
|
#
|
|
136
|
-
#
|
|
162
|
+
# **Returns**
|
|
163
|
+
#
|
|
164
|
+
# - `void`
|
|
165
|
+
#
|
|
166
|
+
# :call-seq:
|
|
167
|
+
# yield(source:) -> void
|
|
137
168
|
def yield(source = Fiber[:__graphql_current_dataloader_source])
|
|
138
169
|
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
|
139
170
|
trace&.dataloader_fiber_yield(source)
|
|
@@ -142,24 +173,28 @@ module GraphQL
|
|
|
142
173
|
nil
|
|
143
174
|
end
|
|
144
175
|
|
|
145
|
-
|
|
146
|
-
def append_job(callable = nil, &job)
|
|
176
|
+
def append_job(callable = nil, &job) # :nodoc:
|
|
147
177
|
# Given a block, queue it up to be worked through when `#run` is called.
|
|
148
178
|
# (If the dataloader is already running, then a Fiber will pick this up later.)
|
|
149
179
|
@pending_jobs.push(callable || job)
|
|
150
180
|
nil
|
|
151
181
|
end
|
|
152
182
|
|
|
153
|
-
#
|
|
154
|
-
def queue_pending_source(source)
|
|
183
|
+
def queue_pending_source(source) # :nodoc:
|
|
155
184
|
if @pending_source_set.add?(source)
|
|
156
185
|
@pending_sources << source
|
|
157
186
|
end
|
|
158
187
|
nil
|
|
159
188
|
end
|
|
160
189
|
|
|
161
|
-
# Clear any already-loaded objects from
|
|
162
|
-
#
|
|
190
|
+
# Clear any already-loaded objects from [Source](rdoc-ref:Source) caches
|
|
191
|
+
#
|
|
192
|
+
# **Returns**
|
|
193
|
+
#
|
|
194
|
+
# - `void`
|
|
195
|
+
#
|
|
196
|
+
# :call-seq:
|
|
197
|
+
# clear_cache() -> void
|
|
163
198
|
def clear_cache
|
|
164
199
|
@source_cache.each do |_source_class, batched_sources|
|
|
165
200
|
batched_sources.each_value(&:clear_cache)
|
|
@@ -185,7 +220,7 @@ module GraphQL
|
|
|
185
220
|
end
|
|
186
221
|
|
|
187
222
|
@pending_jobs = []
|
|
188
|
-
res = nil
|
|
223
|
+
res = nil #: untyped
|
|
189
224
|
# Make sure the block is inside a Fiber, so it can `Fiber.yield`
|
|
190
225
|
append_job {
|
|
191
226
|
res = yield
|
|
@@ -195,7 +230,8 @@ module GraphQL
|
|
|
195
230
|
ensure
|
|
196
231
|
@pending_jobs = prev_queue
|
|
197
232
|
@lazies_at_depth = prev_lazies_at_depth
|
|
198
|
-
prev_pending_keys
|
|
233
|
+
prev_pending_keys #: as !nil
|
|
234
|
+
.each do |source_instance, pending|
|
|
199
235
|
pending.each do |key, value|
|
|
200
236
|
next if source_instance.results.key?(key)
|
|
201
237
|
|
|
@@ -205,7 +241,12 @@ module GraphQL
|
|
|
205
241
|
end
|
|
206
242
|
end
|
|
207
243
|
|
|
208
|
-
#
|
|
244
|
+
# **Parameters**
|
|
245
|
+
#
|
|
246
|
+
# - `trace_query_lazy` (`nil, Execution::Multiplex`)
|
|
247
|
+
#
|
|
248
|
+
# :call-seq:
|
|
249
|
+
# run(nil | Execution::Multiplex trace_query_lazy:)
|
|
209
250
|
def run(trace_query_lazy: nil)
|
|
210
251
|
trace = Fiber[:__graphql_current_multiplex]&.current_trace
|
|
211
252
|
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
|
@@ -213,7 +254,7 @@ module GraphQL
|
|
|
213
254
|
next_job_fibers = []
|
|
214
255
|
source_fibers = []
|
|
215
256
|
next_source_fibers = []
|
|
216
|
-
first_pass = true
|
|
257
|
+
first_pass = true #: bool
|
|
217
258
|
manager = spawn_fiber do
|
|
218
259
|
trace&.begin_dataloader(self)
|
|
219
260
|
while first_pass || !job_fibers.empty?
|
|
@@ -255,14 +296,15 @@ module GraphQL
|
|
|
255
296
|
f.resume
|
|
256
297
|
end
|
|
257
298
|
|
|
258
|
-
#
|
|
259
|
-
def lazy_at_depth(depth, lazy)
|
|
299
|
+
def lazy_at_depth(depth, lazy) # :nodoc:
|
|
260
300
|
@lazies_at_depth[depth] << lazy
|
|
261
301
|
end
|
|
262
302
|
|
|
263
303
|
def spawn_fiber
|
|
264
304
|
fiber_vars = get_fiber_variables
|
|
265
305
|
Fiber.new(blocking: !@nonblocking) do
|
|
306
|
+
# Fibers inherit the spawning fiber's storage; give each one its own execution state.
|
|
307
|
+
Fiber[:__graphql_runtime_info] = nil
|
|
266
308
|
set_fiber_variables(fiber_vars)
|
|
267
309
|
yield
|
|
268
310
|
ensure
|
|
@@ -271,11 +313,20 @@ module GraphQL
|
|
|
271
313
|
end
|
|
272
314
|
|
|
273
315
|
# Pre-warm the Dataloader cache with ActiveRecord objects which were loaded elsewhere.
|
|
274
|
-
# These will be used by
|
|
316
|
+
# These will be used by [Dataloader::ActiveRecordSource](rdoc-ref:Dataloader::ActiveRecordSource), [Dataloader::ActiveRecordAssociationSource](rdoc-ref:Dataloader::ActiveRecordAssociationSource) and their helper
|
|
275
317
|
# methods, `dataload_record` and `dataload_association`.
|
|
276
|
-
#
|
|
277
|
-
#
|
|
278
|
-
#
|
|
318
|
+
#
|
|
319
|
+
# **Parameters**
|
|
320
|
+
#
|
|
321
|
+
# - `records` (`Array<ActiveRecord::Base>`) — Already-loaded records to warm the cache with
|
|
322
|
+
# - `index_by` (`Symbol`) — The attribute to use as the cache key. (Should match `find_by:` when using [ActiveRecordSource](rdoc-ref:ActiveRecordSource))
|
|
323
|
+
#
|
|
324
|
+
# **Returns**
|
|
325
|
+
#
|
|
326
|
+
# - `void`
|
|
327
|
+
#
|
|
328
|
+
# :call-seq:
|
|
329
|
+
# merge_records(Array[ActiveRecord::Base] records, Symbol index_by:) -> void
|
|
279
330
|
def merge_records(records, index_by: :id)
|
|
280
331
|
records_by_class = Hash.new { |h, k| h[k] = {} }
|
|
281
332
|
records.each do |r|
|
|
@@ -315,11 +366,11 @@ module GraphQL
|
|
|
315
366
|
join_queues(job_fibers, next_job_fibers)
|
|
316
367
|
|
|
317
368
|
while (!source_fibers.empty? || !@pending_sources.empty?)
|
|
318
|
-
while (
|
|
319
|
-
if
|
|
320
|
-
|
|
321
|
-
if !
|
|
322
|
-
next_source_fibers <<
|
|
369
|
+
while (source_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)))
|
|
370
|
+
if source_f.alive?
|
|
371
|
+
source_finished = run_fiber(source_f)
|
|
372
|
+
if !source_finished
|
|
373
|
+
next_source_fibers << source_f
|
|
323
374
|
end
|
|
324
375
|
end
|
|
325
376
|
end
|