graphql 1.12.12 → 2.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of graphql might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/generators/graphql/core.rb +3 -8
- data/lib/generators/graphql/enum_generator.rb +4 -10
- data/lib/generators/graphql/field_extractor.rb +31 -0
- data/lib/generators/graphql/input_generator.rb +50 -0
- data/lib/generators/graphql/install/mutation_root_generator.rb +34 -0
- data/lib/generators/graphql/{templates → install/templates}/base_mutation.erb +2 -0
- data/lib/generators/graphql/{templates → install/templates}/mutation_type.erb +2 -0
- data/lib/generators/graphql/install_generator.rb +60 -4
- data/lib/generators/graphql/interface_generator.rb +7 -7
- data/lib/generators/graphql/mutation_create_generator.rb +22 -0
- data/lib/generators/graphql/mutation_delete_generator.rb +22 -0
- data/lib/generators/graphql/mutation_generator.rb +5 -30
- data/lib/generators/graphql/mutation_update_generator.rb +22 -0
- data/lib/generators/graphql/object_generator.rb +10 -38
- data/lib/generators/graphql/orm_mutations_base.rb +40 -0
- data/lib/generators/graphql/relay.rb +23 -12
- data/lib/generators/graphql/scalar_generator.rb +4 -2
- data/lib/generators/graphql/templates/base_argument.erb +2 -0
- data/lib/generators/graphql/templates/base_connection.erb +2 -0
- data/lib/generators/graphql/templates/base_edge.erb +2 -0
- data/lib/generators/graphql/templates/base_enum.erb +2 -0
- data/lib/generators/graphql/templates/base_field.erb +2 -0
- data/lib/generators/graphql/templates/base_input_object.erb +2 -0
- data/lib/generators/graphql/templates/base_interface.erb +2 -0
- data/lib/generators/graphql/templates/base_object.erb +2 -0
- data/lib/generators/graphql/templates/base_resolver.erb +8 -0
- data/lib/generators/graphql/templates/base_scalar.erb +2 -0
- data/lib/generators/graphql/templates/base_union.erb +2 -0
- data/lib/generators/graphql/templates/enum.erb +5 -1
- data/lib/generators/graphql/templates/graphql_controller.erb +2 -0
- data/lib/generators/graphql/templates/input.erb +9 -0
- data/lib/generators/graphql/templates/interface.erb +4 -2
- data/lib/generators/graphql/templates/loader.erb +2 -0
- data/lib/generators/graphql/templates/mutation.erb +3 -1
- data/lib/generators/graphql/templates/mutation_create.erb +20 -0
- data/lib/generators/graphql/templates/mutation_delete.erb +20 -0
- data/lib/generators/graphql/templates/mutation_update.erb +21 -0
- data/lib/generators/graphql/templates/node_type.erb +2 -0
- data/lib/generators/graphql/templates/object.erb +4 -2
- data/lib/generators/graphql/templates/query_type.erb +2 -0
- data/lib/generators/graphql/templates/scalar.erb +3 -1
- data/lib/generators/graphql/templates/schema.erb +22 -2
- data/lib/generators/graphql/templates/union.erb +4 -2
- data/lib/generators/graphql/type_generator.rb +46 -10
- data/lib/generators/graphql/union_generator.rb +5 -5
- data/lib/graphql/analysis/analyzer.rb +89 -0
- data/lib/graphql/analysis/field_usage.rb +65 -28
- data/lib/graphql/analysis/max_query_complexity.rb +11 -17
- data/lib/graphql/analysis/max_query_depth.rb +13 -19
- data/lib/graphql/analysis/query_complexity.rb +156 -61
- data/lib/graphql/analysis/query_depth.rb +38 -23
- data/lib/graphql/analysis/visitor.rb +283 -0
- data/lib/graphql/analysis.rb +90 -6
- data/lib/graphql/autoload.rb +38 -0
- data/lib/graphql/backtrace/inspect_result.rb +0 -12
- data/lib/graphql/backtrace/table.rb +4 -22
- data/lib/graphql/backtrace/trace.rb +93 -0
- data/lib/graphql/backtrace/tracer.rb +8 -6
- data/lib/graphql/backtrace.rb +3 -8
- data/lib/graphql/coercion_error.rb +1 -9
- data/lib/graphql/current.rb +52 -0
- data/lib/graphql/dataloader/async_dataloader.rb +89 -0
- data/lib/graphql/dataloader/null_dataloader.rb +4 -2
- data/lib/graphql/dataloader/request.rb +5 -0
- data/lib/graphql/dataloader/source.rb +125 -33
- data/lib/graphql/dataloader.rb +193 -143
- data/lib/graphql/date_encoding_error.rb +16 -0
- data/lib/graphql/dig.rb +1 -1
- data/lib/graphql/duration_encoding_error.rb +16 -0
- data/lib/graphql/execution/errors.rb +12 -81
- data/lib/graphql/execution/interpreter/argument_value.rb +5 -1
- data/lib/graphql/execution/interpreter/arguments.rb +2 -2
- data/lib/graphql/execution/interpreter/arguments_cache.rb +33 -36
- data/lib/graphql/execution/interpreter/resolve.rb +38 -4
- data/lib/graphql/execution/interpreter/runtime/graphql_result.rb +175 -0
- data/lib/graphql/execution/interpreter/runtime.rb +447 -403
- data/lib/graphql/execution/interpreter.rb +126 -80
- data/lib/graphql/execution/lazy.rb +11 -21
- data/lib/graphql/execution/lookahead.rb +133 -55
- data/lib/graphql/execution/multiplex.rb +4 -172
- data/lib/graphql/execution.rb +11 -4
- data/lib/graphql/integer_encoding_error.rb +18 -2
- data/lib/graphql/introspection/directive_location_enum.rb +2 -2
- data/lib/graphql/introspection/directive_type.rb +6 -4
- data/lib/graphql/introspection/dynamic_fields.rb +3 -8
- data/lib/graphql/introspection/entry_points.rb +11 -18
- data/lib/graphql/introspection/enum_value_type.rb +2 -2
- data/lib/graphql/introspection/field_type.rb +4 -4
- data/lib/graphql/introspection/input_value_type.rb +10 -4
- data/lib/graphql/introspection/schema_type.rb +17 -15
- data/lib/graphql/introspection/type_type.rb +29 -16
- data/lib/graphql/introspection.rb +6 -2
- data/lib/graphql/invalid_null_error.rb +1 -1
- data/lib/graphql/language/block_string.rb +37 -25
- data/lib/graphql/language/cache.rb +13 -0
- data/lib/graphql/language/comment.rb +18 -0
- data/lib/graphql/language/definition_slice.rb +1 -1
- data/lib/graphql/language/document_from_schema_definition.rb +122 -81
- data/lib/graphql/language/lexer.rb +364 -1467
- data/lib/graphql/language/nodes.rb +197 -106
- data/lib/graphql/language/parser.rb +799 -1920
- data/lib/graphql/language/printer.rb +372 -160
- data/lib/graphql/language/sanitized_printer.rb +25 -27
- data/lib/graphql/language/static_visitor.rb +167 -0
- data/lib/graphql/language/visitor.rb +188 -141
- data/lib/graphql/language.rb +62 -1
- data/lib/graphql/load_application_object_failed_error.rb +5 -1
- data/lib/graphql/name_validator.rb +0 -4
- data/lib/graphql/pagination/active_record_relation_connection.rb +37 -8
- data/lib/graphql/pagination/array_connection.rb +8 -6
- data/lib/graphql/pagination/connection.rb +61 -7
- data/lib/graphql/pagination/connections.rb +22 -23
- data/lib/graphql/pagination/mongoid_relation_connection.rb +1 -2
- data/lib/graphql/pagination/relation_connection.rb +60 -28
- data/lib/graphql/query/context/scoped_context.rb +101 -0
- data/lib/graphql/query/context.rb +146 -222
- data/lib/graphql/query/input_validation_result.rb +10 -1
- data/lib/graphql/query/null_context.rb +15 -32
- data/lib/graphql/query/validation_pipeline.rb +15 -39
- data/lib/graphql/query/variable_validation_error.rb +3 -3
- data/lib/graphql/query/variables.rb +35 -17
- data/lib/graphql/query.rb +149 -82
- data/lib/graphql/railtie.rb +15 -109
- data/lib/graphql/rake_task/validate.rb +1 -1
- data/lib/graphql/rake_task.rb +30 -11
- data/lib/graphql/relay/range_add.rb +9 -16
- data/lib/graphql/relay.rb +0 -15
- data/lib/graphql/rubocop/graphql/base_cop.rb +36 -0
- data/lib/graphql/rubocop/graphql/default_null_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/default_required_true.rb +43 -0
- data/lib/graphql/rubocop/graphql/field_type_in_block.rb +144 -0
- data/lib/graphql/rubocop/graphql/root_types_in_block.rb +38 -0
- data/lib/graphql/rubocop.rb +6 -0
- data/lib/graphql/schema/addition.rb +98 -54
- data/lib/graphql/schema/always_visible.rb +14 -0
- data/lib/graphql/schema/argument.rb +179 -82
- data/lib/graphql/schema/base_64_encoder.rb +3 -5
- data/lib/graphql/schema/build_from_definition.rb +77 -39
- data/lib/graphql/schema/directive/feature.rb +1 -1
- data/lib/graphql/schema/directive/flagged.rb +4 -4
- data/lib/graphql/schema/directive/include.rb +1 -1
- data/lib/graphql/schema/directive/one_of.rb +24 -0
- data/lib/graphql/schema/directive/skip.rb +1 -1
- data/lib/graphql/schema/directive/specified_by.rb +14 -0
- data/lib/graphql/schema/directive/transform.rb +2 -2
- data/lib/graphql/schema/directive.rb +36 -22
- data/lib/graphql/schema/enum.rb +158 -63
- data/lib/graphql/schema/enum_value.rb +12 -21
- data/lib/graphql/schema/field/connection_extension.rb +7 -17
- data/lib/graphql/schema/field/scope_extension.rb +8 -1
- data/lib/graphql/schema/field.rb +521 -359
- data/lib/graphql/schema/field_extension.rb +86 -2
- data/lib/graphql/schema/find_inherited_value.rb +3 -7
- data/lib/graphql/schema/finder.rb +5 -5
- data/lib/graphql/schema/has_single_input_argument.rb +160 -0
- data/lib/graphql/schema/input_object.rb +148 -99
- data/lib/graphql/schema/interface.rb +41 -64
- data/lib/graphql/schema/introspection_system.rb +12 -26
- data/lib/graphql/schema/late_bound_type.rb +12 -2
- data/lib/graphql/schema/list.rb +18 -7
- data/lib/graphql/schema/loader.rb +6 -5
- data/lib/graphql/schema/member/base_dsl_methods.rb +32 -18
- data/lib/graphql/schema/member/build_type.rb +16 -13
- data/lib/graphql/schema/member/has_arguments.rb +270 -86
- data/lib/graphql/schema/member/has_ast_node.rb +12 -0
- data/lib/graphql/schema/member/has_deprecation_reason.rb +3 -4
- data/lib/graphql/schema/member/has_directives.rb +81 -61
- data/lib/graphql/schema/member/has_fields.rb +169 -31
- data/lib/graphql/schema/member/has_interfaces.rb +143 -0
- data/lib/graphql/schema/member/has_unresolved_type_error.rb +5 -1
- data/lib/graphql/schema/member/has_validators.rb +32 -6
- data/lib/graphql/schema/member/relay_shortcuts.rb +47 -2
- data/lib/graphql/schema/member/scoped.rb +19 -0
- data/lib/graphql/schema/member/type_system_helpers.rb +16 -0
- data/lib/graphql/schema/member/validates_input.rb +6 -6
- data/lib/graphql/schema/member.rb +1 -6
- data/lib/graphql/schema/mutation.rb +7 -9
- data/lib/graphql/schema/non_null.rb +7 -7
- data/lib/graphql/schema/object.rb +38 -119
- data/lib/graphql/schema/printer.rb +24 -25
- data/lib/graphql/schema/relay_classic_mutation.rb +13 -91
- data/lib/graphql/schema/resolver/has_payload_type.rb +46 -11
- data/lib/graphql/schema/resolver.rb +118 -115
- data/lib/graphql/schema/scalar.rb +20 -21
- data/lib/graphql/schema/subscription.rb +95 -21
- data/lib/graphql/schema/timeout.rb +25 -29
- data/lib/graphql/schema/type_expression.rb +2 -2
- data/lib/graphql/schema/type_membership.rb +21 -4
- data/lib/graphql/schema/union.rb +16 -16
- data/lib/graphql/schema/unique_within_type.rb +1 -1
- data/lib/graphql/schema/validator/all_validator.rb +62 -0
- data/lib/graphql/schema/validator/allow_blank_validator.rb +29 -0
- data/lib/graphql/schema/validator/allow_null_validator.rb +26 -0
- data/lib/graphql/schema/validator/exclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/format_validator.rb +4 -5
- data/lib/graphql/schema/validator/inclusion_validator.rb +3 -1
- data/lib/graphql/schema/validator/length_validator.rb +5 -3
- data/lib/graphql/schema/validator/numericality_validator.rb +13 -2
- data/lib/graphql/schema/validator/required_validator.rb +56 -18
- data/lib/graphql/schema/validator.rb +38 -28
- data/lib/graphql/schema/visibility/migration.rb +188 -0
- data/lib/graphql/schema/visibility/profile.rb +359 -0
- data/lib/graphql/schema/visibility/visit.rb +190 -0
- data/lib/graphql/schema/visibility.rb +294 -0
- data/lib/graphql/schema/warden.rb +423 -134
- data/lib/graphql/schema/wrapper.rb +0 -5
- data/lib/graphql/schema.rb +1015 -1057
- data/lib/graphql/static_validation/all_rules.rb +3 -1
- data/lib/graphql/static_validation/base_visitor.rb +15 -28
- data/lib/graphql/static_validation/definition_dependencies.rb +7 -2
- data/lib/graphql/static_validation/error.rb +3 -1
- data/lib/graphql/static_validation/literal_validator.rb +24 -7
- data/lib/graphql/static_validation/rules/argument_literals_are_compatible.rb +1 -1
- data/lib/graphql/static_validation/rules/argument_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/arguments_are_defined.rb +4 -3
- data/lib/graphql/static_validation/rules/directives_are_defined.rb +13 -7
- data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +15 -13
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +12 -2
- data/lib/graphql/static_validation/rules/fields_have_appropriate_selections.rb +13 -5
- data/lib/graphql/static_validation/rules/fields_will_merge.rb +62 -35
- data/lib/graphql/static_validation/rules/fields_will_merge_error.rb +25 -4
- data/lib/graphql/static_validation/rules/fragment_spreads_are_possible.rb +3 -3
- data/lib/graphql/static_validation/rules/fragment_types_exist.rb +12 -2
- data/lib/graphql/static_validation/rules/fragments_are_finite.rb +2 -2
- data/lib/graphql/static_validation/rules/fragments_are_on_composite_types.rb +1 -1
- data/lib/graphql/static_validation/rules/mutation_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/no_definitions_are_present.rb +1 -1
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid.rb +66 -0
- data/lib/graphql/static_validation/rules/one_of_input_objects_are_valid_error.rb +29 -0
- data/lib/graphql/static_validation/rules/query_root_exists.rb +17 -0
- data/lib/graphql/static_validation/rules/query_root_exists_error.rb +26 -0
- data/lib/graphql/static_validation/rules/required_arguments_are_present.rb +7 -5
- data/lib/graphql/static_validation/rules/required_input_object_attributes_are_present.rb +5 -5
- data/lib/graphql/static_validation/rules/subscription_root_exists.rb +1 -1
- data/lib/graphql/static_validation/rules/unique_directives_per_location.rb +14 -8
- data/lib/graphql/static_validation/rules/variable_default_values_are_correctly_typed.rb +18 -27
- data/lib/graphql/static_validation/rules/variable_names_are_unique.rb +1 -1
- data/lib/graphql/static_validation/rules/variable_usages_are_allowed.rb +14 -8
- data/lib/graphql/static_validation/rules/variables_are_input_types.rb +11 -2
- data/lib/graphql/static_validation/validation_context.rb +32 -6
- data/lib/graphql/static_validation/validator.rb +11 -27
- data/lib/graphql/static_validation.rb +0 -3
- data/lib/graphql/string_encoding_error.rb +13 -3
- data/lib/graphql/subscriptions/action_cable_subscriptions.rb +49 -11
- data/lib/graphql/subscriptions/broadcast_analyzer.rb +11 -5
- data/lib/graphql/subscriptions/default_subscription_resolve_extension.rb +40 -1
- data/lib/graphql/subscriptions/event.rb +87 -38
- data/lib/graphql/subscriptions/serialize.rb +27 -3
- data/lib/graphql/subscriptions.rb +63 -49
- data/lib/graphql/testing/helpers.rb +155 -0
- data/lib/graphql/testing.rb +2 -0
- data/lib/graphql/tracing/active_support_notifications_trace.rb +16 -0
- data/lib/graphql/tracing/active_support_notifications_tracing.rb +6 -20
- data/lib/graphql/tracing/appoptics_trace.rb +253 -0
- data/lib/graphql/tracing/appoptics_tracing.rb +4 -2
- data/lib/graphql/tracing/appsignal_trace.rb +79 -0
- data/lib/graphql/tracing/appsignal_tracing.rb +17 -0
- data/lib/graphql/tracing/call_legacy_tracers.rb +66 -0
- data/lib/graphql/tracing/data_dog_trace.rb +185 -0
- data/lib/graphql/tracing/data_dog_tracing.rb +27 -15
- data/lib/graphql/{execution/instrumentation.rb → tracing/legacy_hooks_trace.rb} +11 -28
- data/lib/graphql/tracing/legacy_trace.rb +12 -0
- data/lib/graphql/tracing/new_relic_trace.rb +77 -0
- data/lib/graphql/tracing/new_relic_tracing.rb +2 -0
- data/lib/graphql/tracing/notifications_trace.rb +45 -0
- data/lib/graphql/tracing/notifications_tracing.rb +61 -0
- data/lib/graphql/tracing/null_trace.rb +9 -0
- data/lib/graphql/tracing/platform_trace.rb +118 -0
- data/lib/graphql/tracing/platform_tracing.rb +46 -49
- data/lib/graphql/tracing/{prometheus_tracing → prometheus_trace}/graphql_collector.rb +6 -2
- data/lib/graphql/tracing/prometheus_trace.rb +94 -0
- data/lib/graphql/tracing/prometheus_tracing.rb +5 -3
- data/lib/graphql/tracing/scout_trace.rb +74 -0
- data/lib/graphql/tracing/scout_tracing.rb +2 -0
- data/lib/graphql/tracing/sentry_trace.rb +114 -0
- data/lib/graphql/tracing/statsd_trace.rb +58 -0
- data/lib/graphql/tracing/statsd_tracing.rb +2 -0
- data/lib/graphql/tracing/trace.rb +79 -0
- data/lib/graphql/tracing.rb +29 -52
- data/lib/graphql/type_kinds.rb +7 -4
- data/lib/graphql/types/big_int.rb +5 -1
- data/lib/graphql/types/int.rb +1 -1
- data/lib/graphql/types/iso_8601_date.rb +17 -6
- data/lib/graphql/types/iso_8601_date_time.rb +12 -1
- data/lib/graphql/types/iso_8601_duration.rb +77 -0
- data/lib/graphql/types/relay/base_connection.rb +16 -6
- data/lib/graphql/types/relay/connection_behaviors.rb +92 -32
- data/lib/graphql/types/relay/edge_behaviors.rb +46 -7
- data/lib/graphql/types/relay/has_node_field.rb +2 -2
- data/lib/graphql/types/relay/has_nodes_field.rb +2 -2
- data/lib/graphql/types/relay/node_behaviors.rb +12 -2
- data/lib/graphql/types/relay/page_info_behaviors.rb +11 -2
- data/lib/graphql/types/relay.rb +0 -3
- data/lib/graphql/types/string.rb +2 -2
- data/lib/graphql/types.rb +18 -10
- data/lib/graphql/unauthorized_enum_value_error.rb +13 -0
- data/lib/graphql/unauthorized_error.rb +1 -1
- data/lib/graphql/version.rb +1 -1
- data/lib/graphql.rb +82 -137
- data/readme.md +13 -6
- metadata +127 -186
- data/lib/graphql/analysis/analyze_query.rb +0 -98
- data/lib/graphql/analysis/ast/analyzer.rb +0 -84
- data/lib/graphql/analysis/ast/field_usage.rb +0 -28
- data/lib/graphql/analysis/ast/max_query_complexity.rb +0 -23
- data/lib/graphql/analysis/ast/max_query_depth.rb +0 -22
- data/lib/graphql/analysis/ast/query_complexity.rb +0 -234
- data/lib/graphql/analysis/ast/query_depth.rb +0 -56
- data/lib/graphql/analysis/ast/visitor.rb +0 -268
- data/lib/graphql/analysis/ast.rb +0 -91
- data/lib/graphql/analysis/reducer_state.rb +0 -48
- data/lib/graphql/argument.rb +0 -131
- data/lib/graphql/authorization.rb +0 -82
- data/lib/graphql/backtrace/legacy_tracer.rb +0 -56
- data/lib/graphql/backwards_compatibility.rb +0 -61
- data/lib/graphql/base_type.rb +0 -230
- data/lib/graphql/boolean_type.rb +0 -2
- data/lib/graphql/compatibility/execution_specification/counter_schema.rb +0 -53
- data/lib/graphql/compatibility/execution_specification/specification_schema.rb +0 -200
- data/lib/graphql/compatibility/execution_specification.rb +0 -436
- data/lib/graphql/compatibility/lazy_execution_specification/lazy_schema.rb +0 -111
- data/lib/graphql/compatibility/lazy_execution_specification.rb +0 -215
- data/lib/graphql/compatibility/query_parser_specification/parse_error_specification.rb +0 -87
- data/lib/graphql/compatibility/query_parser_specification/query_assertions.rb +0 -79
- data/lib/graphql/compatibility/query_parser_specification.rb +0 -266
- data/lib/graphql/compatibility/schema_parser_specification.rb +0 -682
- data/lib/graphql/compatibility.rb +0 -5
- data/lib/graphql/define/assign_argument.rb +0 -12
- data/lib/graphql/define/assign_connection.rb +0 -13
- data/lib/graphql/define/assign_enum_value.rb +0 -18
- data/lib/graphql/define/assign_global_id_field.rb +0 -11
- data/lib/graphql/define/assign_mutation_function.rb +0 -34
- data/lib/graphql/define/assign_object_field.rb +0 -42
- data/lib/graphql/define/defined_object_proxy.rb +0 -53
- data/lib/graphql/define/instance_definable.rb +0 -240
- data/lib/graphql/define/no_definition_error.rb +0 -7
- data/lib/graphql/define/non_null_with_bang.rb +0 -16
- data/lib/graphql/define/type_definer.rb +0 -31
- data/lib/graphql/define.rb +0 -31
- data/lib/graphql/deprecated_dsl.rb +0 -47
- data/lib/graphql/deprecation.rb +0 -13
- data/lib/graphql/directive/deprecated_directive.rb +0 -2
- data/lib/graphql/directive/include_directive.rb +0 -2
- data/lib/graphql/directive/skip_directive.rb +0 -2
- data/lib/graphql/directive.rb +0 -111
- data/lib/graphql/enum_type.rb +0 -129
- data/lib/graphql/execution/execute.rb +0 -333
- data/lib/graphql/execution/flatten.rb +0 -40
- data/lib/graphql/execution/lazy/resolve.rb +0 -91
- data/lib/graphql/execution/typecast.rb +0 -50
- data/lib/graphql/field/resolve.rb +0 -59
- data/lib/graphql/field.rb +0 -226
- data/lib/graphql/filter.rb +0 -53
- data/lib/graphql/float_type.rb +0 -2
- data/lib/graphql/function.rb +0 -128
- data/lib/graphql/id_type.rb +0 -2
- data/lib/graphql/input_object_type.rb +0 -138
- data/lib/graphql/int_type.rb +0 -2
- data/lib/graphql/interface_type.rb +0 -72
- data/lib/graphql/internal_representation/document.rb +0 -27
- data/lib/graphql/internal_representation/node.rb +0 -206
- data/lib/graphql/internal_representation/print.rb +0 -51
- data/lib/graphql/internal_representation/rewrite.rb +0 -184
- data/lib/graphql/internal_representation/scope.rb +0 -88
- data/lib/graphql/internal_representation/visit.rb +0 -36
- data/lib/graphql/internal_representation.rb +0 -7
- data/lib/graphql/language/lexer.rl +0 -262
- data/lib/graphql/language/parser.y +0 -543
- data/lib/graphql/language/token.rb +0 -38
- data/lib/graphql/list_type.rb +0 -80
- data/lib/graphql/non_null_type.rb +0 -71
- data/lib/graphql/object_type.rb +0 -130
- data/lib/graphql/query/arguments.rb +0 -189
- data/lib/graphql/query/arguments_cache.rb +0 -24
- data/lib/graphql/query/executor.rb +0 -52
- data/lib/graphql/query/literal_input.rb +0 -136
- data/lib/graphql/query/serial_execution/field_resolution.rb +0 -92
- data/lib/graphql/query/serial_execution/operation_resolution.rb +0 -19
- data/lib/graphql/query/serial_execution/selection_resolution.rb +0 -23
- data/lib/graphql/query/serial_execution/value_resolution.rb +0 -87
- data/lib/graphql/query/serial_execution.rb +0 -40
- data/lib/graphql/relay/array_connection.rb +0 -83
- data/lib/graphql/relay/base_connection.rb +0 -189
- data/lib/graphql/relay/connection_instrumentation.rb +0 -54
- data/lib/graphql/relay/connection_resolve.rb +0 -43
- data/lib/graphql/relay/connection_type.rb +0 -41
- data/lib/graphql/relay/edge.rb +0 -27
- data/lib/graphql/relay/edge_type.rb +0 -19
- data/lib/graphql/relay/edges_instrumentation.rb +0 -40
- data/lib/graphql/relay/global_id_resolve.rb +0 -18
- data/lib/graphql/relay/mongo_relation_connection.rb +0 -50
- data/lib/graphql/relay/mutation/instrumentation.rb +0 -23
- data/lib/graphql/relay/mutation/resolve.rb +0 -56
- data/lib/graphql/relay/mutation/result.rb +0 -38
- data/lib/graphql/relay/mutation.rb +0 -106
- data/lib/graphql/relay/node.rb +0 -39
- data/lib/graphql/relay/page_info.rb +0 -7
- data/lib/graphql/relay/relation_connection.rb +0 -188
- data/lib/graphql/relay/type_extensions.rb +0 -32
- data/lib/graphql/scalar_type.rb +0 -91
- data/lib/graphql/schema/base_64_bp.rb +0 -26
- data/lib/graphql/schema/catchall_middleware.rb +0 -35
- data/lib/graphql/schema/default_parse_error.rb +0 -10
- data/lib/graphql/schema/default_type_error.rb +0 -17
- data/lib/graphql/schema/invalid_type_error.rb +0 -7
- data/lib/graphql/schema/member/accepts_definition.rb +0 -152
- data/lib/graphql/schema/member/cached_graphql_definition.rb +0 -31
- data/lib/graphql/schema/member/instrumentation.rb +0 -131
- data/lib/graphql/schema/middleware_chain.rb +0 -82
- data/lib/graphql/schema/possible_types.rb +0 -44
- data/lib/graphql/schema/rescue_middleware.rb +0 -60
- data/lib/graphql/schema/timeout_middleware.rb +0 -88
- data/lib/graphql/schema/traversal.rb +0 -228
- data/lib/graphql/schema/validation.rb +0 -313
- data/lib/graphql/static_validation/default_visitor.rb +0 -15
- data/lib/graphql/static_validation/no_validate_visitor.rb +0 -10
- data/lib/graphql/static_validation/type_stack.rb +0 -216
- data/lib/graphql/string_type.rb +0 -2
- data/lib/graphql/subscriptions/instrumentation.rb +0 -79
- data/lib/graphql/subscriptions/subscription_root.rb +0 -76
- data/lib/graphql/tracing/skylight_tracing.rb +0 -70
- data/lib/graphql/types/relay/default_relay.rb +0 -27
- data/lib/graphql/types/relay/node_field.rb +0 -25
- data/lib/graphql/types/relay/nodes_field.rb +0 -27
- data/lib/graphql/union_type.rb +0 -115
- data/lib/graphql/upgrader/member.rb +0 -937
- data/lib/graphql/upgrader/schema.rb +0 -38
@@ -6,7 +6,11 @@ module GraphQL
|
|
6
6
|
# Called by {Dataloader} to prepare the {Source}'s internal state
|
7
7
|
# @api private
|
8
8
|
def setup(dataloader)
|
9
|
-
|
9
|
+
# These keys have been requested but haven't been fetched yet
|
10
|
+
@pending = {}
|
11
|
+
# These keys have been passed to `fetch` but haven't been finished yet
|
12
|
+
@fetching = {}
|
13
|
+
# { key => result }
|
10
14
|
@results = {}
|
11
15
|
@dataloader = dataloader
|
12
16
|
end
|
@@ -14,42 +18,66 @@ module GraphQL
|
|
14
18
|
attr_reader :dataloader
|
15
19
|
|
16
20
|
# @return [Dataloader::Request] a pending request for a value from `key`. Call `.load` on that object to wait for the result.
|
17
|
-
def request(
|
18
|
-
|
19
|
-
|
21
|
+
def request(value)
|
22
|
+
res_key = result_key_for(value)
|
23
|
+
if !@results.key?(res_key)
|
24
|
+
@pending[res_key] ||= value
|
20
25
|
end
|
21
|
-
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
|
22
36
|
end
|
23
37
|
|
24
38
|
# @return [Dataloader::Request] a pending request for a values from `keys`. Call `.load` on that object to wait for the results.
|
25
|
-
def request_all(
|
26
|
-
|
27
|
-
|
28
|
-
|
39
|
+
def request_all(values)
|
40
|
+
values.each do |v|
|
41
|
+
res_key = result_key_for(v)
|
42
|
+
if !@results.key?(res_key)
|
43
|
+
@pending[res_key] ||= v
|
44
|
+
end
|
45
|
+
end
|
46
|
+
Dataloader::RequestAll.new(self, values)
|
29
47
|
end
|
30
48
|
|
31
|
-
# @param
|
49
|
+
# @param value [Object] A loading value which will be passed to {#fetch} if it isn't already in the internal cache.
|
32
50
|
# @return [Object] The result from {#fetch} for `key`. If `key` hasn't been loaded yet, the Fiber will yield until it's loaded.
|
33
|
-
def load(
|
34
|
-
|
35
|
-
|
51
|
+
def load(value)
|
52
|
+
result_key = result_key_for(value)
|
53
|
+
if @results.key?(result_key)
|
54
|
+
result_for(result_key)
|
36
55
|
else
|
37
|
-
@
|
38
|
-
sync
|
39
|
-
result_for(
|
56
|
+
@pending[result_key] ||= value
|
57
|
+
sync([result_key])
|
58
|
+
result_for(result_key)
|
40
59
|
end
|
41
60
|
end
|
42
61
|
|
43
|
-
# @param
|
62
|
+
# @param values [Array<Object>] Loading keys which will be passed to `#fetch` (or read from the internal cache).
|
44
63
|
# @return [Object] The result from {#fetch} for `keys`. If `keys` haven't been loaded yet, the Fiber will yield until they're loaded.
|
45
|
-
def load_all(
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
64
|
+
def load_all(values)
|
65
|
+
result_keys = []
|
66
|
+
pending_keys = []
|
67
|
+
values.each { |v|
|
68
|
+
k = result_key_for(v)
|
69
|
+
result_keys << k
|
70
|
+
if !@results.key?(k)
|
71
|
+
@pending[k] ||= v
|
72
|
+
pending_keys << k
|
73
|
+
end
|
74
|
+
}
|
75
|
+
|
76
|
+
if !pending_keys.empty?
|
77
|
+
sync(pending_keys)
|
50
78
|
end
|
51
79
|
|
52
|
-
|
80
|
+
result_keys.map { |k| result_for(k) }
|
53
81
|
end
|
54
82
|
|
55
83
|
# Subclasses must implement this method to return a value for each of `keys`
|
@@ -60,35 +88,89 @@ module GraphQL
|
|
60
88
|
raise "Implement `#{self.class}#fetch(#{keys.inspect}) to return a record for each of the keys"
|
61
89
|
end
|
62
90
|
|
91
|
+
MAX_ITERATIONS = 1000
|
63
92
|
# Wait for a batch, if there's anything to batch.
|
64
93
|
# Then run the batch and update the cache.
|
65
94
|
# @return [void]
|
66
|
-
def sync
|
95
|
+
def sync(pending_result_keys)
|
67
96
|
@dataloader.yield
|
97
|
+
iterations = 0
|
98
|
+
while pending_result_keys.any? { |key| !@results.key?(key) }
|
99
|
+
iterations += 1
|
100
|
+
if iterations > MAX_ITERATIONS
|
101
|
+
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" : ""}."
|
102
|
+
end
|
103
|
+
@dataloader.yield
|
104
|
+
end
|
105
|
+
nil
|
68
106
|
end
|
69
107
|
|
70
108
|
# @return [Boolean] True if this source has any pending requests for data.
|
71
109
|
def pending?
|
72
|
-
|
110
|
+
!@pending.empty?
|
111
|
+
end
|
112
|
+
|
113
|
+
# Add these key-value pairs to this source's cache
|
114
|
+
# (future loads will use these merged values).
|
115
|
+
# @param new_results [Hash<Object => Object>] key-value pairs to cache in this source
|
116
|
+
# @return [void]
|
117
|
+
def merge(new_results)
|
118
|
+
new_results.each do |new_k, new_v|
|
119
|
+
key = result_key_for(new_k)
|
120
|
+
@results[key] = new_v
|
121
|
+
end
|
122
|
+
nil
|
73
123
|
end
|
74
124
|
|
75
125
|
# Called by {GraphQL::Dataloader} to resolve and pending requests to this source.
|
76
126
|
# @api private
|
77
127
|
# @return [void]
|
78
128
|
def run_pending_keys
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
129
|
+
if !@fetching.empty?
|
130
|
+
@fetching.each_key { |k| @pending.delete(k) }
|
131
|
+
end
|
132
|
+
return if @pending.empty?
|
133
|
+
fetch_h = @pending
|
134
|
+
@pending = {}
|
135
|
+
@fetching.merge!(fetch_h)
|
136
|
+
results = fetch(fetch_h.values)
|
137
|
+
fetch_h.each_with_index do |(key, _value), idx|
|
84
138
|
@results[key] = results[idx]
|
85
139
|
end
|
140
|
+
nil
|
86
141
|
rescue StandardError => error
|
87
|
-
|
142
|
+
fetch_h.each_key { |key| @results[key] = error }
|
88
143
|
ensure
|
144
|
+
fetch_h && fetch_h.each_key { |k| @fetching.delete(k) }
|
145
|
+
end
|
146
|
+
|
147
|
+
# These arguments are given to `dataloader.with(source_class, ...)`. The object
|
148
|
+
# returned from this method is used to de-duplicate batch loads under the hood
|
149
|
+
# by using it as a Hash key.
|
150
|
+
#
|
151
|
+
# By default, the arguments are all put in an Array. To customize how this source's
|
152
|
+
# batches are merged, override this method to return something else.
|
153
|
+
#
|
154
|
+
# For example, if you pass `ActiveRecord::Relation`s to `.with(...)`, you could override
|
155
|
+
# this method to call `.to_sql` on them, thus merging `.load(...)` calls when they apply
|
156
|
+
# to equivalent relations.
|
157
|
+
#
|
158
|
+
# @param batch_args [Array<Object>]
|
159
|
+
# @param batch_kwargs [Hash]
|
160
|
+
# @return [Object]
|
161
|
+
def self.batch_key_for(*batch_args, **batch_kwargs)
|
162
|
+
[*batch_args, **batch_kwargs]
|
163
|
+
end
|
164
|
+
|
165
|
+
# Clear any already-loaded objects for this source
|
166
|
+
# @return [void]
|
167
|
+
def clear_cache
|
168
|
+
@results.clear
|
89
169
|
nil
|
90
170
|
end
|
91
171
|
|
172
|
+
attr_reader :pending, :results
|
173
|
+
|
92
174
|
private
|
93
175
|
|
94
176
|
# Reads and returns the result for the key from the internal cache, or raises an error if the result was an error
|
@@ -96,9 +178,19 @@ module GraphQL
|
|
96
178
|
# @return [Object] The result from {#fetch} for `key`.
|
97
179
|
# @api private
|
98
180
|
def result_for(key)
|
99
|
-
|
181
|
+
if !@results.key?(key)
|
182
|
+
raise GraphQL::InvariantError, <<-ERR
|
183
|
+
Fetching result for a key on #{self.class} that hasn't been loaded yet (#{key.inspect}, loaded: #{@results.keys})
|
100
184
|
|
101
|
-
|
185
|
+
This key should have been loaded already. This is a bug in GraphQL::Dataloader, please report it on GitHub: https://github.com/rmosolgo/graphql-ruby/issues/new.
|
186
|
+
ERR
|
187
|
+
end
|
188
|
+
result = @results[key]
|
189
|
+
if result.is_a?(StandardError)
|
190
|
+
# Dup it because the rescuer may modify it.
|
191
|
+
# (This happens for GraphQL::ExecutionErrors, at least)
|
192
|
+
raise result.dup
|
193
|
+
end
|
102
194
|
|
103
195
|
result
|
104
196
|
end
|
data/lib/graphql/dataloader.rb
CHANGED
@@ -23,23 +23,80 @@ module GraphQL
|
|
23
23
|
# end
|
24
24
|
#
|
25
25
|
class Dataloader
|
26
|
-
|
27
|
-
|
26
|
+
class << self
|
27
|
+
attr_accessor :default_nonblocking, :default_fiber_limit
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
def self.use(schema, nonblocking: nil, fiber_limit: nil)
|
31
|
+
dataloader_class = if nonblocking
|
32
|
+
warn("`nonblocking: true` is deprecated from `GraphQL::Dataloader`, please use `GraphQL::Dataloader::AsyncDataloader` instead. Docs: https://graphql-ruby.org/dataloader/async_dataloader.")
|
33
|
+
Class.new(self) { self.default_nonblocking = true }
|
34
|
+
else
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
if fiber_limit
|
39
|
+
dataloader_class = Class.new(dataloader_class)
|
40
|
+
dataloader_class.default_fiber_limit = fiber_limit
|
41
|
+
end
|
42
|
+
|
43
|
+
schema.dataloader_class = dataloader_class
|
44
|
+
end
|
45
|
+
|
46
|
+
# Call the block with a Dataloader instance,
|
47
|
+
# then run all enqueued jobs and return the result of the block.
|
48
|
+
def self.with_dataloading(&block)
|
49
|
+
dataloader = self.new
|
50
|
+
result = nil
|
51
|
+
dataloader.append_job {
|
52
|
+
result = block.call(dataloader)
|
41
53
|
}
|
54
|
+
dataloader.run
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize(nonblocking: self.class.default_nonblocking, fiber_limit: self.class.default_fiber_limit)
|
59
|
+
@source_cache = Hash.new { |h, k| h[k] = {} }
|
42
60
|
@pending_jobs = []
|
61
|
+
if !nonblocking.nil?
|
62
|
+
@nonblocking = nonblocking
|
63
|
+
end
|
64
|
+
@fiber_limit = fiber_limit
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [Integer, nil]
|
68
|
+
attr_reader :fiber_limit
|
69
|
+
|
70
|
+
def nonblocking?
|
71
|
+
@nonblocking
|
72
|
+
end
|
73
|
+
|
74
|
+
# This is called before the fiber is spawned, from the parent context (i.e. from
|
75
|
+
# the thread or fiber that it is scheduled from).
|
76
|
+
#
|
77
|
+
# @return [Hash<Symbol, Object>] Current fiber-local variables
|
78
|
+
def get_fiber_variables
|
79
|
+
fiber_vars = {}
|
80
|
+
Thread.current.keys.each do |fiber_var_key|
|
81
|
+
fiber_vars[fiber_var_key] = Thread.current[fiber_var_key]
|
82
|
+
end
|
83
|
+
fiber_vars
|
84
|
+
end
|
85
|
+
|
86
|
+
# Set up the fiber variables in a new fiber.
|
87
|
+
#
|
88
|
+
# This is called within the fiber, right after it is spawned.
|
89
|
+
#
|
90
|
+
# @param vars [Hash<Symbol, Object>] Fiber-local variables from {get_fiber_variables}
|
91
|
+
# @return [void]
|
92
|
+
def set_fiber_variables(vars)
|
93
|
+
vars.each { |k, v| Thread.current[k] = v }
|
94
|
+
nil
|
95
|
+
end
|
96
|
+
|
97
|
+
# This method is called when Dataloader is finished using a fiber.
|
98
|
+
# Use it to perform any cleanup, such as releasing database connections (if required manually)
|
99
|
+
def cleanup_fiber
|
43
100
|
end
|
44
101
|
|
45
102
|
# Get a Source instance from this dataloader, for calling `.load(...)` or `.request(...)` on.
|
@@ -48,17 +105,25 @@ module GraphQL
|
|
48
105
|
# @param batch_parameters [Array<Object>]
|
49
106
|
# @return [GraphQL::Dataloader::Source] An instance of {source_class}, initialized with `self, *batch_parameters`,
|
50
107
|
# and cached for the lifetime of this {Multiplex}.
|
51
|
-
if RUBY_VERSION < "3"
|
52
|
-
def with(source_class, *
|
53
|
-
|
108
|
+
if RUBY_VERSION < "3" || RUBY_ENGINE != "ruby" # truffle-ruby wasn't doing well with the implementation below
|
109
|
+
def with(source_class, *batch_args)
|
110
|
+
batch_key = source_class.batch_key_for(*batch_args)
|
111
|
+
@source_cache[source_class][batch_key] ||= begin
|
112
|
+
source = source_class.new(*batch_args)
|
113
|
+
source.setup(self)
|
114
|
+
source
|
115
|
+
end
|
54
116
|
end
|
55
117
|
else
|
56
118
|
def with(source_class, *batch_args, **batch_kwargs)
|
57
|
-
|
58
|
-
@source_cache[source_class][
|
119
|
+
batch_key = source_class.batch_key_for(*batch_args, **batch_kwargs)
|
120
|
+
@source_cache[source_class][batch_key] ||= begin
|
121
|
+
source = source_class.new(*batch_args, **batch_kwargs)
|
122
|
+
source.setup(self)
|
123
|
+
source
|
124
|
+
end
|
59
125
|
end
|
60
126
|
end
|
61
|
-
|
62
127
|
# Tell the dataloader that this fiber is waiting for data.
|
63
128
|
#
|
64
129
|
# Dataloader will resume the fiber after the requested data has been loaded (by another Fiber).
|
@@ -77,9 +142,28 @@ module GraphQL
|
|
77
142
|
nil
|
78
143
|
end
|
79
144
|
|
145
|
+
# Clear any already-loaded objects from {Source} caches
|
146
|
+
# @return [void]
|
147
|
+
def clear_cache
|
148
|
+
@source_cache.each do |_source_class, batched_sources|
|
149
|
+
batched_sources.each_value(&:clear_cache)
|
150
|
+
end
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
|
80
154
|
# Use a self-contained queue for the work in the block.
|
81
155
|
def run_isolated
|
82
156
|
prev_queue = @pending_jobs
|
157
|
+
prev_pending_keys = {}
|
158
|
+
@source_cache.each do |source_class, batched_sources|
|
159
|
+
batched_sources.each do |batch_args, batched_source_instance|
|
160
|
+
if batched_source_instance.pending?
|
161
|
+
prev_pending_keys[batched_source_instance] = batched_source_instance.pending.dup
|
162
|
+
batched_source_instance.pending.clear
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
83
167
|
@pending_jobs = []
|
84
168
|
res = nil
|
85
169
|
# Make sure the block is inside a Fiber, so it can `Fiber.yield`
|
@@ -90,113 +174,109 @@ module GraphQL
|
|
90
174
|
res
|
91
175
|
ensure
|
92
176
|
@pending_jobs = prev_queue
|
177
|
+
prev_pending_keys.each do |source_instance, pending|
|
178
|
+
pending.each do |key, value|
|
179
|
+
if !source_instance.results.key?(key)
|
180
|
+
source_instance.pending[key] = value
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
93
184
|
end
|
94
185
|
|
95
|
-
# @api private Move along, move along
|
96
186
|
def run
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
# - 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)
|
103
|
-
# B) Once all known jobs have been run until they are complete or paused for data, run all pending data sources.
|
104
|
-
# - Similarly, create a Fiber to consume pending sources and tell them to load their data.
|
105
|
-
# - If one of those Fibers pauses, then create a new Fiber to continue working through remaining pending sources.
|
106
|
-
# - When a source causes another source to become pending, run the newly-pending source _first_, since it's a dependency of the previous one.
|
107
|
-
# C) After all pending sources have been completely loaded (there are no more pending sources), resume any Fibers that were waiting for data.
|
108
|
-
# - Those Fibers assume that source caches will have been populated with the data they were waiting for.
|
109
|
-
# - Those Fibers may request data from a source again, in which case they will yeilded and be added to a new pending fiber list.
|
110
|
-
# D) Once all pending fibers have been resumed once, return to `A` above.
|
111
|
-
#
|
112
|
-
# 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`
|
113
|
-
# 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.
|
114
|
-
#
|
115
|
-
pending_fibers = []
|
116
|
-
next_fibers = []
|
187
|
+
jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
|
188
|
+
job_fibers = []
|
189
|
+
next_job_fibers = []
|
190
|
+
source_fibers = []
|
191
|
+
next_source_fibers = []
|
117
192
|
first_pass = true
|
118
|
-
|
119
|
-
|
120
|
-
if first_pass
|
193
|
+
manager = spawn_fiber do
|
194
|
+
while first_pass || !job_fibers.empty?
|
121
195
|
first_pass = false
|
122
|
-
else
|
123
|
-
# These fibers were previously waiting for sources to load data,
|
124
|
-
# resume them. (They might wait again, in which case, re-enqueue them.)
|
125
|
-
resume(f)
|
126
|
-
if f.alive?
|
127
|
-
next_fibers << f
|
128
|
-
end
|
129
|
-
end
|
130
196
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
197
|
+
while (f = (job_fibers.shift || (((next_job_fibers.size + job_fibers.size) < jobs_fiber_limit) && spawn_job_fiber)))
|
198
|
+
if f.alive?
|
199
|
+
finished = run_fiber(f)
|
200
|
+
if !finished
|
201
|
+
next_job_fibers << f
|
202
|
+
end
|
137
203
|
end
|
138
|
-
}
|
139
|
-
resume(f)
|
140
|
-
# In this case, the job yielded. Queue it up to run again after
|
141
|
-
# we load whatever it's waiting for.
|
142
|
-
if f.alive?
|
143
|
-
next_fibers << f
|
144
204
|
end
|
145
|
-
|
146
|
-
|
147
|
-
if pending_fibers.empty?
|
148
|
-
# Now, run all Sources which have become pending _before_ resuming GraphQL execution.
|
149
|
-
# Sources might queue up other Sources, which is fine -- those will also run before resuming execution.
|
150
|
-
#
|
151
|
-
# This is where an evented approach would be even better -- can we tell which
|
152
|
-
# fibers are ready to continue, and continue execution there?
|
153
|
-
#
|
154
|
-
source_fiber_queue = if (first_source_fiber = create_source_fiber)
|
155
|
-
[first_source_fiber]
|
156
|
-
else
|
157
|
-
nil
|
158
|
-
end
|
159
|
-
|
160
|
-
if source_fiber_queue
|
161
|
-
while (outer_source_fiber = source_fiber_queue.shift)
|
162
|
-
resume(outer_source_fiber)
|
163
|
-
|
164
|
-
# If this source caused more sources to become pending, run those before running this one again:
|
165
|
-
next_source_fiber = create_source_fiber
|
166
|
-
if next_source_fiber
|
167
|
-
source_fiber_queue << next_source_fiber
|
168
|
-
end
|
205
|
+
join_queues(job_fibers, next_job_fibers)
|
169
206
|
|
170
|
-
|
171
|
-
|
207
|
+
while (!source_fibers.empty? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) })
|
208
|
+
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))
|
209
|
+
if f.alive?
|
210
|
+
finished = run_fiber(f)
|
211
|
+
if !finished
|
212
|
+
next_source_fibers << f
|
213
|
+
end
|
172
214
|
end
|
173
215
|
end
|
216
|
+
join_queues(source_fibers, next_source_fibers)
|
174
217
|
end
|
175
|
-
# Move newly-enqueued Fibers on to the list to be resumed.
|
176
|
-
# Clear out the list of next-round Fibers, so that
|
177
|
-
# any Fibers that pause can be put on it.
|
178
|
-
pending_fibers.concat(next_fibers)
|
179
|
-
next_fibers.clear
|
180
218
|
end
|
181
219
|
end
|
182
220
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
raise "Invariant:
|
187
|
-
elsif next_fibers.any?
|
188
|
-
raise "Invariant: #{next_fibers.size} next fibers"
|
221
|
+
run_fiber(manager)
|
222
|
+
|
223
|
+
if manager.alive?
|
224
|
+
raise "Invariant: Manager fiber didn't terminate properly."
|
189
225
|
end
|
190
|
-
|
226
|
+
|
227
|
+
if !job_fibers.empty?
|
228
|
+
raise "Invariant: job fibers should have exited but #{job_fibers.size} remained"
|
229
|
+
end
|
230
|
+
if !source_fibers.empty?
|
231
|
+
raise "Invariant: source fibers should have exited but #{source_fibers.size} remained"
|
232
|
+
end
|
233
|
+
rescue UncaughtThrowError => e
|
234
|
+
throw e.tag, e.value
|
235
|
+
end
|
236
|
+
|
237
|
+
def run_fiber(f)
|
238
|
+
f.resume
|
239
|
+
end
|
240
|
+
|
241
|
+
def spawn_fiber
|
242
|
+
fiber_vars = get_fiber_variables
|
243
|
+
Fiber.new(blocking: !@nonblocking) {
|
244
|
+
set_fiber_variables(fiber_vars)
|
245
|
+
yield
|
246
|
+
cleanup_fiber
|
247
|
+
}
|
191
248
|
end
|
192
249
|
|
193
250
|
private
|
194
251
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
252
|
+
def calculate_fiber_limit
|
253
|
+
total_fiber_limit = @fiber_limit || Float::INFINITY
|
254
|
+
if total_fiber_limit < 4
|
255
|
+
raise ArgumentError, "Dataloader fiber limit is too low (#{total_fiber_limit}), it must be at least 4"
|
256
|
+
end
|
257
|
+
total_fiber_limit -= 1 # deduct one fiber for `manager`
|
258
|
+
# Deduct at least one fiber for sources
|
259
|
+
jobs_fiber_limit = total_fiber_limit - 2
|
260
|
+
return jobs_fiber_limit, total_fiber_limit
|
261
|
+
end
|
262
|
+
|
263
|
+
def join_queues(prev_queue, new_queue)
|
264
|
+
@nonblocking && Fiber.scheduler.run
|
265
|
+
prev_queue.concat(new_queue)
|
266
|
+
new_queue.clear
|
267
|
+
end
|
268
|
+
|
269
|
+
def spawn_job_fiber
|
270
|
+
if !@pending_jobs.empty?
|
271
|
+
spawn_fiber do
|
272
|
+
while job = @pending_jobs.shift
|
273
|
+
job.call
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def spawn_source_fiber
|
200
280
|
pending_sources = nil
|
201
281
|
@source_cache.each_value do |source_by_batch_params|
|
202
282
|
source_by_batch_params.each_value do |source|
|
@@ -208,45 +288,15 @@ module GraphQL
|
|
208
288
|
end
|
209
289
|
|
210
290
|
if pending_sources
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
#
|
217
|
-
# This design could probably be improved by maintaining a `@pending_sources` queue which is shared by the fibers,
|
218
|
-
# similar to `@pending_jobs`. That way, when a fiber is resumed, it would never pick up work that was finished by a different fiber.
|
219
|
-
source_fiber = spawn_fiber do
|
220
|
-
pending_sources.each(&:run_pending_keys)
|
291
|
+
spawn_fiber do
|
292
|
+
pending_sources.each do |source|
|
293
|
+
Fiber[:__graphql_current_dataloader_source] = source
|
294
|
+
source.run_pending_keys
|
295
|
+
end
|
221
296
|
end
|
222
297
|
end
|
223
|
-
|
224
|
-
source_fiber
|
225
|
-
end
|
226
|
-
|
227
|
-
def resume(fiber)
|
228
|
-
fiber.resume
|
229
|
-
rescue UncaughtThrowError => e
|
230
|
-
throw e.tag, e.value
|
231
|
-
end
|
232
|
-
|
233
|
-
# Copies the thread local vars into the fiber thread local vars. Many
|
234
|
-
# gems (such as RequestStore, MiniRacer, etc.) rely on thread local vars
|
235
|
-
# to keep track of execution context, and without this they do not
|
236
|
-
# behave as expected.
|
237
|
-
#
|
238
|
-
# @see https://github.com/rmosolgo/graphql-ruby/issues/3449
|
239
|
-
def spawn_fiber
|
240
|
-
fiber_locals = {}
|
241
|
-
|
242
|
-
Thread.current.keys.each do |fiber_var_key|
|
243
|
-
fiber_locals[fiber_var_key] = Thread.current[fiber_var_key]
|
244
|
-
end
|
245
|
-
|
246
|
-
Fiber.new do
|
247
|
-
fiber_locals.each { |k, v| Thread.current[k] = v }
|
248
|
-
yield
|
249
|
-
end
|
250
298
|
end
|
251
299
|
end
|
252
300
|
end
|
301
|
+
|
302
|
+
require "graphql/dataloader/async_dataloader"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module GraphQL
|
3
|
+
# This error is raised when `Types::ISO8601Date` is asked to return a value
|
4
|
+
# that cannot be parsed to a Ruby Date.
|
5
|
+
#
|
6
|
+
# @see GraphQL::Types::ISO8601Date which raises this error
|
7
|
+
class DateEncodingError < GraphQL::RuntimeTypeError
|
8
|
+
# The value which couldn't be encoded
|
9
|
+
attr_reader :date_value
|
10
|
+
|
11
|
+
def initialize(value)
|
12
|
+
@date_value = value
|
13
|
+
super("Date cannot be parsed: #{value}. \nDate must be be able to be parsed as a Ruby Date object.")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/graphql/dig.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
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
8
|
# @param args [Array<[String, Symbol>] Retrieves the value object corresponding to the each key objects repeatedly
|
@@ -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
|